2013년 7월 6일 토요일

목록 쿼리 - 페이지 처리에 대한 고찰

페이지 처리

현재의 인터넷 페이지는 아주 많은 부분이 게시판 형식의 목록 형태로 되어 있다. 수 천에서 수백만 이상의 데이터를 특정 조건으로 조회/정렬하여 사용자 화면에 보여주게 되는 이러한 형태의 SQL은 자주 사용되어진다. 이 문서는 이러한 목록 형태의 SQL을 패턴별로 어떻게 작성해야 효율적인지에 대하여 설명할 것이다.

왜 제대로 해야 하는가?

목록 형태의 웹 페이지는 거의 모든 웹사이트에서 필수적으로 사용되고 있다. 이 이야기는 결국 DBMS을 이용하여 서비스를 하는 웹사이트는 필수적으로 목록 SQL을 작성할 수 밖에 없다는 말과 같다. 그런데 많은 개발자들이 이러한 SQL의 중요성을 잘 모르고 있을 뿐만 아니라 효율적으로 작성하지 못하는 것이 현실이다. 또한 다양한 사이트에서 SQL튜닝을 지원한 결과 많은 사이트에서의 성능 이슈가 주로 목록 SQL에 있었다는 점이다. 심지어 모 회사에서 만든 프레임워크에서는 웹 페이지의 페이지처리를 담당할 수 있는 모듈을 공통기능으로 만들어 놓았으나, 프레임워크에서 성능에 부정적인 SQL을 자동으로 생성해 주는 문제점도 보았다.
다음과 같은 경우를 생각해보자
1.     페이지 처리를 SQL에서(DBMS에서)하지 않고 어플리케이션에서 하는 경우
이 경우 SQL이 효율적으로 작성되어 있다(물론 페이지처리를 할 때의 효율성은 아니다) 하더라도 네트워크에 대한 부하는 막을 수 없다. 앞쪽 페이지의 경우에는 네트워크 부하가 적을 수 있으나 뒤쪽 페이지로 이동 할 수록 DBMS WAS간의 데이터 통신량은 늘어 날 것이다.
예를 들어, 한 건의 로우가 2,000바이트이고 페이지당 50건씩 보여준다고 할 때 1,000번째 페이지로 이동한 경우를 생각해 보라.(누가 1,000 페이지까지 보겠어? 라고 반 문 할 수도 있지만, 보지 말라는 법도 없다.) 95.5MB(2,000 * 50 * 1,000)가 네트워크 라인을 타고 DBMS에서 WAS로 전달 될 것이고, 어플리케이션에서는 50,000(50 * 1000) 만큼 루프를 돌며 앞쪽 49,950건의 데이터는 그냥 버리게 될 것이다.
이런 비효율을 감수하면서도 어플리케이션에서 페이지처리를 할 것인가?
2.     페이지 처리를 어플리케이션에서 하되, SQL이 효율적이지 않은 경우
수백 수천 건 정도의 데이터인 경우에는 크게 문제가 되지 않겠으나, 수십 수백만 건의 데이터에 대해서 조인/정렬 등의 작업은 많은 부하를 줄 수 밖에 없다. 목록에서 특정 로우를 클릭하여 조회하는 경우에는 주로 Unique Index를 사용하므로 문제가 될 것이 없지만, 목록을 조회하는 경우에는 SQL의 효율이 아주 중요하다 할 수 있다. 이러한 목록 형태의 SQL들은 특히 좀더 효율적으로 작성하여야 한다. 

기본개념

페이지 처리를 위한 효율적인 SQL을 작성하는 것도 SQL을 튜닝하는 기본 개념과 다르지 않다. 몇 가지 중요한 원리만 알고, 그 원리에 기반하여 SQL을 작성하면 좋은 성능을 보장 받을 수 있다.
첫 번째 I/O의 최소화이다. I/O를 최소화 한다는 이야기는 Disk 또는 DB Buffer로 부터 필요로 하는 데이터만을 읽는 것이다. 잘 수립된 인덱스 전략으로 생성된 인덱스를 효율적으로 엑세스 하는 것이 중요하다. 인덱스를 효율적으로 엑세스 할 수 없다면, Index FFS를 통해서 처리할 수 있는 방안이 있는지도 고민해 봐야 한다.
두 번째 조인의 최소화이다. 이는 I/O최소화와도 아주 관련이 많다. 필요로 하는 데이터만을 이용하여 두 번째 테이블과 조인하여야만 조인을 최소화 하고 I/O도 최소화 할 수 있는 것이다.
세 번째 정렬의 제거 또는 최소화이다. Index를 잘 활용하면 정렬을 수행 하지 않고도 정렬된 결과를 얻을 수 있으며, 정렬이 불가피한 경우에는 정렬을 수행할 데이터의 양을 최소화 하는 것이다.
대부분의 SQL는 위의 3가지를 유의하여 작성하면 최소한의 성능은 보장 받을 수 있다
이러한 원리를 적용한 구체적인 사례를 통하여 앞으로 이 블로그에 하나씩 설명을 하고자 한다.
(시간이 생길 때 마다 하나씩 정리해 봐야겠다.)

패턴1 – 검색조건 없음
패턴2 – 단일테이블 검색조건
패턴3 – 다중테이블 검색조건
패턴4 OUTER 조인을 포함

NoSQL 개념잡기

1. NoSQL 이란?
  o NoSQL은 Not-Only SQL의 약자로써
  o 비관계형 데이터저장소로
  o보통 기존 전통적인 방식의 관계형 데이터베이스와(RDBMS)는 다르게 설계된 데이터베이스
  o 이러한 데이터스토어들은 테이블 스키마(Table Schema)가 고정되지 않고
  o 테이블 간 조인(Join) 연산을 지원하지 않으며
  o 대체로 수평적 확장(Horizontal Scalability)이 용이하다는 특징을 갖는다.


2. 등장 배경
  o SNS의 등장 및 웹 환경의 변화로 동시에 대량의 데이터를 Write/Read 필요
  o 지속적으로 증가하는 사용자에 대응 하기 위하여 수평적 확장성이 필요
  o 빠르게 변화하는 비즈니스에 대한 신속한 대응의 필요
  o RDBMS와는 다르게 데이터 저장구조가 비정형적이다.
  o 위의 요건을 만족하기 위해서는 기존 RDBMS로는 어려움이 있음
  o 그러므로 새로운 형태의 저장 방식과 분산 방식이 필요해짐 

3. 관계형 데이터베이스의 한계


4. Scale-out 분산
   4.1 Why?


   4.2 RDBMS의 Scale-out?
      4.2.1. ACID(Atomicity, Consistency, Isolation, Durability)의 유지의 어려움
         o Atomicity를 만족하기 위해서는 2PC 프로토콜과 같은 분산 트랜잭션 프로토콜이     트랜잭션에 관련되어 있는 시스템간에 이뤄져야 함
         o Isolation level을 맞추기 위해서는 일반적으로 데이터를 locking해야 하며. Locking의 단위는 레코드, 테이블, 인덱스 등이 될 수 있음
         o 결과적으로 분산된 환경에서 Atomic과 Isolated 속성을 만족하기 위해서는 분산 트랜잭션 프로토콜이 진행되는 동안에 관련된 모든 lock이 각 시스템에 걸려 있어야 하며,
         o 이러한 방식은 시스템의 서비스 부하가 높아 질수록 많은 lock 경합이 이루어지는 것을 의미함. 이러한 경합 때문에 scale-out 하기 어려움

      4.2.2. 확장의 어려움
         o Replication - 복제에 의한 분산
            - Master-Slave 구조에서는 결과를 슬레이브의 개수 만큼 복제해야 하는데 N개의 슬레이브에서 읽을 수 있기 때문에 Read는 빠르지만
            - Write에서는 병목현상이 발생하기 때문에 확장성에 대한 제한을 가지게 됨
            - 다중 마스터구조에서는 마스터를 추가함으로써 쓰기의 성능을 향상시킬 수 있는데 대신에 충돌이 발생할 가능성이 생기게 됨
         o Partitioning(Sharding) - 분할에 의한 분산
            - Read만큼 Write도 확장할 수 있지만 애플리케이션레이어에서 파티션된 것을 인지하고 있어야 함
            - RDBMS의 가치는 관계에 있다고 할 수 있는데 파티션을 하면 이 관계가 깨져버리고 각 파티션된 조각간에 조인을 할 수 없기 때문에 관계에 대한 부분은 애플리케이션 레이어에서 책임져야 함
            - 일반적으로 RDBMS에서 수동 Sharding 은 쉽지 않음

       4.2.3. How NoSQL Scale-out
          o. 데이터 모델의 단순화
            - 쿼리 연산의 데이터 closure가 분산의 기본단위가 되고, 이 단위를 모아서 적당한  수준의 shard를 만들 수 있도록 데이터 모델이 단순하게 구성함
            - 기본적으로 쿼리는 분산 단위의 읽기 쓰기를 지원하지만, 여러 분산 단위에 대한 집계 연산 등을 하기 위해서 map-reduce와 같은 별도의 쿼리 방식을 지원하기도 함
          o 쿼리의 ACID 속성을 완화
            - 쿼리 연산의 일관성을 RDBMS의 ACID 속성보다 완화한 형태를 사용함
            - 복제(Replacation)까지 포함해서 생각해 보면 이와 같은 쿼리 속성 완화 현상은 두드러짐.
            - CouchDB처럼 ACID 속성을 유지해주는 시스템도 있지만, 많은 경우 고 가용성을 위해, Consistence나 Isolated를 완화함

   4.3. CAP 이론
      o CAP 이론 : 분산 컴퓨팅 시스템에서 보장해야하는 3가지 특징을 정의
      o Consistency(일관성) : 모든 노드들은 동시에 같은 데이터를 보아야 한다.
      o Availability(유효성) : 모든 노드는 항상 Read와 Write를 할 수 있어야 한다.
      o Partition Tolerance(파티션 허용치) : 시스템은 물리적인 네트워크 파티션을 넘어서도 잘 동작해야 한다.
      o CAP 이론에 따르면 CAP중 동시에 보장할 수 있는 것은 이중 2가지이므로, 데이터를 관리할 때 CAP중 어느 2가지에 중점을 둘 것인지를 결정해야 함.
      o 기존 RDBMS는 CA에 치중 하고 있음
      o AP를 추구하는 NoSQL은 Consistency를 포기하게 되고 CP를 추구하는 NoSQL은 Availability를 포기해야 함.
      (요즈음에는 다양한 방식을 통해 AP와 CP를 절충하거나 보완하는 방식도 사용됨)

5. NoSQL의 구조
  5.1 공통 특징
    o Key value store
    o Run on large number of commodity machines
    o Data are partitioned and replicated among these machines
    o Relax the data consistency requirement
    o API Model
       - get(key)
       - put(key, value)
       - delete(key)
       - execute(key, operation, parameters)
       - (※)mapreduce(keyList, mapFunc, reduceFunc) 

   5.2 데이터 저장 구조
      5.2.1. Key-Value(blob)
        o 단순한 모델인 만큼 속도가 빠른 것이 주 장점
        o Key 단위의 원자적 쓰기/읽기 만을 지원하는 경우가 많으며, 이 경우 여러 key의 value에 동시 처리를 하면서 serialize 할 수 있는 방법은 없음
        o 메모리를 저장소로 사용하는 경우 아주 빠른 get/put을 지원하는 것을 목적으로 함
        o Key에 대한 단위 연산이 빠른 것이지, 여러 key에 대한 연산은 고정적으로 네트워크 전송 지연이 포함되기 때문에 느릴 수 있음
(RDBMS테이블에 10만 row의 데이터를 select 하는 것과 Key-value 단위로 10만 번 읽는 것은 비교할 수 없을 정도로 Key-Value DB가 느림)

      5.2.2. Key-Value(Structure)
         o List, Set 과 같은 ADT(Abstract Data Structure)를 제공하는 모델이고, 장점은 한 key에 대해 여러 값을 저장할 수 있음
         o Key-BLOB모델에서는 단일 값만 Value로 사용할 수 있으나, 이 구조는 여러 Key를 사용해 저장 해야 하는 데이터를 하나의 key 만 사용하여 저장할 수 있음
         o 단순히 get/put하는 모델보다는 처리 시간이 오래 걸림(그리 많은 차이가 나지는 않음/설계에 따라 극복 가능함)

      5.2.3. Document oriented
         o schema 없이, 임의의 property 를 추가할 수 있는 데이터 모델
         o JSon이나 XML 같은 문서 데이터를 저장하기 적합한 구조
         o Document id나 특정 property 값 기준으로 order-preserving 하는 경우가 많음
           (이 경우 해당 key 값의 range에 대한 효율적인 연산이 가능해 지므로 이에 대한 쿼리를 제공)
         o 쿼리 처리에 있어서 데이터를 parsing 해서 memory 연산을 해야 하므로 처리 overhead가 key-value나 key-structure 모델보다 큼(큰 크기의 document를 다룰 때 성능 저하 발생)

      5.2.4. Multi-dimensional map
         o Bigtable의 경우 row-column-timestamp에 의해서 데이터를 mapping 하고, 데이터 자체는 binary 값
         o Cassandra의 경우 row-column, families-column 형태로 데이터를 mapping 하고 데이터 자체는 binary 값
         o 두 모델 모두 데이터(column)에 대한 grouping 과 access 방식을 구조화 하는 방식으로 데이터를 모델링 할 수 있음



Oracle flush back

Oracle FlashBack


 

1 FlashBack Database

1.1 개요

오라클의 백업 및 복구의 개념에는 여러 가지가 존재한다. 이 문서에서는 백업 및 복구에 대해서 개념적으로만 알아보고 FlashBack Database가 논리적인 복구에서 어떻게 활용될 수 있는지에 대해서 간단한 예제를 활용하여 알아보고자 한다.
우선 오라클 장애의 종류에 대해서 생각해보자. 장애라 함은 오라클 데이터베이스가 어떠한 원인으로 인하여 정상적인 서비스를 수행 할 수 없는 상태를 이야기 한다. 어떠한 원인에 의해서 Instance failure, Media failure, User failure, Network failure등 다양한 장애가 존재하지만 이 중에서 Instance, Media, User failure에 대해서 간단히 정리해보자.
l Instance failure
정전 및 CPU등의 고장으로 인하여 fail이 발생한 경우일 것이다. 이러한 유형의 fail에 대해서는 복구를 위해서 DBA가 수행해야 할 별도의 작업은 없다. 오라클이 startup 되면서 자동으로 online redo log 파일을 읽어 roll forward[1] rollback[2] 단계를 수행하여 자동으로 복구를 하게 된다.
l Media failure
Database 파일이 들어있는 특정 디스크의 고장으로 인하여 Database 파일에 대한 읽기, 쓰기 작업을 할 수 없는 상태 또는 사용자의 실수로 인하여 Database 파일을 삭제한 경우로, 상황에 따라 완전복구[3] 또는 불완전 복구[4]를 수행한다.
l User failure
사용자의 실수로 인하여 테이블을 삭제(drop) 또는 자르기(truncate)한 경우 또는 데이터를 잘못 변경한 후 commit한 경우 등 사용자의 실수로서 발생하는 fail이다. 이 경우 다양한 해결 방법이 존재한다.
유효한 백업에서 복구
export 파일에서 테이블을 import
LogMiner를 이용하여 online/archived logfile을 분석/복구
Point-in-time Recovery를 통해 복구
oracle 9i/10g/11gFlash Back을 사용하여 복구
그럼 이제 oracle 10g에서 새롭게 도입된 개념인 Flash Back Database에 대해서 알아보자. FlashBack Database는 백업 및 복구를 쉽고 빠르게 수행하기 위하여 제공 되는 기능이다. FlashBack Database는 아카이브 로그 모드에서만 사용할 수 있으며, flash recovery를 위한 로그를 RVWR 백그라운드 프로세스가 생성한다. FlashBack 데이터베이스 로그는 redo log와는 다르게 아카이브 되지 않는다. 또한 물리적인 데이터베이스 복구를 위해서는 사용 될 수 없다.

1.2      FlashBack Database 모드로 운영하기

FlashBack Database 모드로 운영하기 위해서는 우선 세 가지의 파라미터 설정이 필요하며, 반드시 아카이브 로그 모드로 운영되어야 한다.
l  db_recovery_file_dest : flashback recovery log가 저장될 기본 디렉토리 지정
l  db_recovery_file_dest_size : db_recovery_file_dest 디렉토리에 저장될 수 있는 파일들의 총 용량의 최대 크기(Kbyte, Mbyte, Gbyte) 지정
l  flashback_retention_target : flashback recovery로그로 유지해야 할 시간 지정(분단위)
l  아래의 절차대로 flashback database 모드로 변경하여 보자
--archive log mode로 변경 하기 위한 파라미터 설정
alter system set log_archive_dest = '/home/oracle/app/archive' scope = spfile;
alter system set log_archive_format = '%t_%s_%r.dbf' scope = spfile;

--flashback database mode로 운영 하기 위한 파라미터 설정
alter system set db_recovery_file_dest_size = 2G scope = spfile;
alter system set db_recovery_file_dest = '/home/oracle/app/flash_recovery_area' scope = spfile;
alter system set db_flashback_retention_target = 1440 scope = spfile;

--dbms 종료
shutdown immediate;
--dbms mount단계까지만 시작
startup mount;
--archive log 모드로 변경
alter database archivelog;
--flashback database모드로 변경
alter database flashback on;
--database open
alter database open;


1.3      FlashBack Database 모드 종료

FlashBack Database 모드를 종료시키기 위해서는 아래와 같은 명령을 수행하면 된다.
alter database flashback off;

1.4      Restore Point

Restore Point Oracle 10g R2에서 새롭게 도입된 기능으로 복구하고자 하는 데이터베이스의 시점(지점)을 기록하여 두는 기능이다. Restore Point flashback database, flashback table 기능에서 사용할 수 있으며, 두 가지 타입이 있다.
l  Guaranteed restore point : 이 타입으로 설정된 restore point flashback database에 의해서 반드시 복원 지점의 데이터가 삭제되지 않음을 보장하게 된다. 그러므로 Guaranteed restore point를 설정하게 되면 db_flashback_retention_target 파라미터의 설정 값은 무시되며, flash recovery area 영역의 공간을 디스크가 허용할 때 까지 flashback database log 가 쌓이므로, 명시적으로 restore point를 삭제해 주어야 한다.
l  Normal restore point : 일반적인 restore point를 생성한다. 이 타입으로 restore point를 생성하면, db_flashback_retention_target 파라미터 설정 값에 의해 flashback database log가 삭제될 때 자동으로 restore point도 삭제된다. 그러나 명시적으로 삭제할 수 도 있다.
* Restore Point Syntax

* ex) create restore point rp1 guarantee flashback database;

1.5      Database 복구 테스트

* FlashBack Database Syntax

이제 flashback database 모드로 변경하였으니, 여러 가지 작업을 수행해본 후 특정 시점으로 데이터베이스를 변경해 보자
--테스트를 위해 테이블을 생성한다.
create table t1 as select * from emp;

create table t2 as select * from dept;

select count(*) from t1;
/*
  COUNT(*)
----------
        14
*/

select count(*) from t2;
/*
  COUNT(*)
----------
         4
*/

--테스트를 위해서 현재의 SCN을 확인한다.
select current_scn from v$database;
/*
CURRENT_SCN
-----------
    5215533
*/

truncate table t1;
truncate table t2;

--테이블을 자른 후 현재 SCN을 확인
select current_scn from v$database;
/*
CURRENT_SCN
-----------
    5215580
*/

--테이블을 자르기전의 시점으로 데이터베이스 복구하기(데이터베이스 복구는 sysdba 권한으로 수행 하여야 한다.)
shutdown immediate;
startup mount;
flashback database to scn 5215533;

--읽기전용으로 database open
alter database open read only;

--데이터가 복구되었는지 확인
select count(*) from test.t1;
/*
  COUNT(*)
----------
        14
*/

select count(*) from test.t2;
/*
  COUNT(*)
----------
         4
*/

--복구된 상태의 SCN확인(현재는 모든 데이터파일의 SCN이 일치하지 않은 상태임)
select current_scn from v$database;
/*
CURRENT_SCN
-----------
    5215534
*/

shutdown immediate;
startup mount;
--모든 데이터파일의 SCN이 부적합한 상태이므로 일반적인 open이 불가능함
alter database open;
/*
ERROR at line 1:
ORA-01589: must use RESETLOGS or NORESETLOGS option for database open
*/
--database의 정상적인 open을 위하여 SCN를 초기화하는 resetlogs로 오픈
alter database open resetlogs;

--복구된 상태의 SCN확인(현재는 모든 데이터파일의 SCN이 초기화된 상태임)
select current_scn from v$database;
/*
CURRENT_SCN
-----------
    5215810
*/

1.6      FlashBack Database

오라클 10g에서는 FlashBack Database를 위한 다음과 같은 뷰를 제공한다.
l  V$DATABASE
ü  FLASHBACK_ON : YES/NO로서 FlashBack Database의 활성/비활성을 확인할 수 있다.
l  V$FLASHBACK_DATABASE_LOG : FlashBack 데이터베이스를 모니터링하기위해 새롭게 제공되는 뷰
ü  OLDEST_FLASHBACK_SCN : 가장 오래된 FlashBack Database SCN
ü  OLDEST_FLASHBACK_TIME : 가장 오래된 FlashBack Database의 시간
ü  RETENTION_TARGET : 설정된 flashback database 유지 목표시간
ü  FLASHBACK_SIZE : 현재 FlashBack Database의 크기(byte)
ü  ESTIMATED_FLASHBACK_SIZE : 유지 목표시간을 위해 예상되는 FlashBack Database의 크기
l  V$FLASHBACK_DATABASE_STAT : FlashBack Database를 운영하는데 소모되는 I/O 오버헤드를 모니터링 할 수 있음.
ü  BEGIN_TIME : 시작시간
ü  END_TIME : 종료시간
ü  FLASHBACK_DATA : 시작시간과 종료시간 사이에 쓰여진 FLASHBACK DATA의 크기(bytes)
ü  DB_DATA : 시작시간과 종료시간 사이에 읽고, 쓰여진 Database Data의 크기(bytes)
ü  REDO_DATA : 시작시간과 종료시간 사이에 쓰여진 redo의 크기(bytes)
ü  ESTIMATED_FLASHBACK_SIZE : V$FLASHBACK_DATABASE_LOG의 컬럼과 동일함.
l  V$FLASH_RECOVERY_AREA_USAGE : FlashBack Recovery Area에 대한 사용률 정보를 보여줌
ü  FILE_TYPE : File Type(CONTROLFILE, ONLINELOG, ARCHIVELOG, FLASHBACKLOG )
ü  PERCENT_SPACE_USED : Recovery Area에 대한 사용률
ü  PERCENT_SPACE_RECLAIMABLE : Recovery Area를 요구할 수 있는 비율
ü  NUMBER_OF_FILES : Recovery Area안에서의 파일 개수


2      FlashBack Table

2.1     개요

사용자의 실수 또는 응용프로그램의 오류로 인하여 테이블의 삭제, 데이터의 변경을 잘못 조작한 경우에 이전의 특정 시점으로 되돌리는 기능을 제공한다. FlashBack Table은 다음과 같은 제약을 가진다.
l  Cluster, Materialized View, Advanced Queue(AQ) Table, Dictionary Table, System Table, Remote Table, Object Table, Nested Table, 개별적인 Partition 또는 Subpartition 에는 사용할 수 없다.
l  Upgrading한 경우, Table에 대해서 moving 또는 truncating 그리고 제약조건, Cluster를 추가한 경우, 테이블의 컬럼을 수정하거나, 삭제한 경우, 파티션을 추가, 삭제, 병합, 분할, 합병, truncating 한 경우에는 사용할 수 없다. 다만 예외적으로 Range Partition 추가에 대해서는 사용할 수 있다.

가)  FLASHBACK DROP TABLE
Oracle 10g 부터 제공하는 RECYBLE BIN 기능으로 테이블을 purge 옵션 없이 삭제하면 segment가 삭제 되지 않고, Object명이 변경되어 RECYCLE BIN안에 들어가게 된다. 이렇게 삭제된 테이블은 향후에 FLASHBACK TABLE TO BEFORE DROP 명령문으로 복구 할 수 있다. 만일 테이블 스페이스의 공간이 부족하게 되면 RECYCLE BIN내의 테이블들은 삭제된 순으로 할당된 extent를 해제하여 테이블 스페이스의 공간을 확보하게 되며, 결과적으로 해당 테이블은 영구적으로 삭제되게 된다. 삭제된 테이블의 이름은 rb$$객체$$객체타입$버전 과 같은 명명규칙으로 생성된다.

나)  INSERT, UPDATE, DELETE(9i버전에서는 dbms_flashback package로 지원함)
테이블에 대해서 INSERT, UPDATE, DELETE를 잘못 수행 하였을 경우 FLASHBACK TABLE TO TIMESTAMP 또는 SCN RESTORE POINT 명령을 이용하여 테이블 데이터를 복구 할 수 있다. 그러나 다음과 같은 제약사항을 갖는다.
l  테이블에 대해서 DDL명령을 수행하여 구조가 변경된 경우에는 복구를 수행할 수가 없다. 또한 복구의 수행은 RECYCLE BIN FLASHBACK Database와 무관하게 Undo Segment에 저장된 이전 이미지를 이용하여 복구를 수행하므로 기본적으로 UNDO_RETENTION<!--[if !supportFootnotes]-->[5]<!--[endif]--> 파라미터에 지정된 시간을 초과하게 되면 복구가 불가능 할 수도 있다.
l  UNDO_RETENTION 파라미터는 UNDO 데이터를 유지하기 위하여 권유하는 값일 뿐 강제성을 가지지 않으므로 지정된 시간을 초과하지 않더라도 UNDO SEGMENT가 부족하게 되면 언제든지 재사용 될 수 있으므로 빈번하게 트랜잭션이 발생하는 시스템에서는 UNDO_RETENTION 시간을 보장 받을 수 없다. 이 경우 UNDO_RETENTION에 설정된 시간을 보장받기 위해서는 RETENTION GUARANTEE로 보장하도록 하여야 하는데, 이렇게 할 경우 Undo Segment가 부족한 경우에는 오류가 발생한다. 다음과 같은 명령수행으로 undo tablespace retention시간을 보장 받을 수 있다.
- ALTER TABLSPACE UNDOTBS1 RETENTION GUARANTEE
l  테이블 데이터의 복구를 위해서는 테이블의 ROW MOVEMENT 옵션이 ENABLE 되어야 한다.
-      ALTER TABLE TNAME ENABLE ROW MOVEMENT
* Flashback table Syntax
 

2.2      Table 복구하기 예제

l  FlashBack Table To Timestamp
--테스트를 위한 테이블을 생성한다.
create table t3
( c1 number, c2 number, c3 number );

--현재의 timestamp를 확인한다.
select systimestamp from dual;
/*
SYSTIMESTAMP
---------------------------------
10/04/17 08:04:45.681332 +09:00
*/

--테스트 데이터를 추가한다.
insert into t3
select rownum, rownum, rownum from dual connect by level <= 10;
commit;

--현재의 timestamp를 확인한다.
select systimestamp from dual;
/*
SYSTIMESTAMP
---------------------------------
10/04/17 08:06:08.996513 +09:00
*/

delete t3 where c1 <= 5;
commit;

--현재의 timestamp를 확인한다.
select systimestamp from dual;
/*
SYSTIMESTAMP
--------------------------------
10/04/17 08:07:10.788725 +09:00
*/

--이제부터 순차적으로 테이블의 데이터를 복구해보자
alter table t3 enable row movement;

--테이블에 10건의 데이터를 insert했을 때의 시점으로 복구
flashback table t3 to timestamp (to_timestamp('20100417080608', 'yyyymmddhh24miss'));

select count(*) from t3;
/*
  COUNT(*)
----------
        10
*/

--테이블에 10건의 데이터를 insert 하기 전 시점으로 복구
flashback table t3 to timestamp (to_timestamp('20100417080501', 'yyyymmddhh24miss'));

select count(*) from t3;
/*
  COUNT(*)
----------
         0
*/

--다시 가장 마지막 시점으로 복구
flashback table t3 to timestamp (to_timestamp('20100417080712', 'yyyymmddhh24miss'));

select count(*) from t3;
/*
  COUNT(*)
----------
         5
*/
--테이블의 데이터상태가 자유롭게 과거와 현재로 변경되어짐을 확인 할 수 있다.

l  FlashBack Table Before Drop
--테스트를 위한 테이블 생성
create table t4
( c1 number, c2 number, c3 number );

--테스트 데이터를 insert 한다.
insert into t4
select rownum, rownum, rownum from dual connect by level <= 10;
commit;

--인덱스가 어떻게 처리 되는지 확인하기 위하여 인덱스를 생성한다.
create index t4_x01 on t4 (c1);

--테이블을 삭제한다.
drop table t4;

--recyclebin을 조회해 보자
select object_name, original_name, type, operation, createtime, droptime from user_recyclebin;
/*
OBJECT_NAME   ORIGINAL_N TYPE  OPERATION  CREATETIME       DROPTIME
------------- ---------- ---- ---------- ------------------------------
BIN$hGLiEGv7J4ngQAB/ T4_X01 INDEX DROP  2010-04-17:08:22:18  2010-04-17:08:22:21
AQARyQ==$0
BIN$hGLiEGv8J4ngQAB/ T4     TABLE DROP  2010-04-17:08:21:37  2010-04-17:08:22:21
AQARyQ==$0
*/

--동일한 테이블을 하나더 만들어 보자
create table t4
( c1 number, c2 number, c3 number );

--5개의 row insert한다.
insert into t4
select rownum, rownum, rownum from dual connect by level <= 5;
commit;

--인덱스가 어떻게 처리 되는지 확인하기 위하여 인덱스를 생성한다.
create index t4_x01 on t4 (c1);

--테이블을 삭제한다.
drop table t4;

--recyclebin 을 조회해보자. 삭제된 테이블 및 인덱스가 들어가 있다.
select object_name, original_name, type, operation, createtime, droptime from user_recyclebin;
/*
OBJECT_NAME        ORIGINAL_N TYPE OPERATION CREATETIME  DROPTIME
------------------ ---------- ----- ------- ------------ -----------
BIN$hGLiEGv7J4ngQAB/ T4_X01 INDEX  DROP 2010-04-17:08:22:18  2010-04-17:08:22:21
AQARyQ==$0
BIN$hGLiEGv8J4ngQAB/ T4     TABLE  DROP 2010-04-17:08:21:37  2010-04-17:08:22:21
AQARyQ==$0
BIN$hGLiEGv9J4ngQAB/ T4_X01 INDEX  DROP 2010-04-17:08:46:26  2010-04-17:08:46:29
AQARyQ==$0

BIN$hGLiEGv+J4ngQAB/ T4     TABLE  DROP 2010-04-17:08:46:24  2010-04-17:08:46:29
AQARyQ==$0
*/

--테이블을 복구해보자
flashback table t4 to before drop;

--recyclebin 을 조회해보자
select object_name, original_name, type, operation, createtime, droptime from user_recyclebin;
/*
OBJECT_NAME  ORIGINAL_N TYPE       OPERATION  CREATETIME           DROPTIME
------------ ---------- ---------- ---------- ----------------- ------------------
BIN$hGLiEGv7J4ngQAB/ T4_X01 INDEX DROP 2010-04-17:08:22:18  2010-04-17:08:22:21
AQARyQ==$0
BIN$hGLiEGv8J4ngQAB/ T4     TABLE DROP 2010-04-17:08:21:37  2010-04-17:08:22:21
AQARyQ==$0
*/
--조회결과 가장 최근에 삭제된 테이블이 복구되었음을 확인할 수 있다.

--복구된 테이블의 row를 세어보자
select count(*) from t4;
/*
  COUNT(*)
----------
         5
*/

--먼저 삭제된 t4테이블은 rename to 절을 사용하여 복구 할 수 있다.
flashback table t4 to before drop rename to t4_b;

--복구된 테이블의 row를 세어보자
select count(*) from t4_b;
/*
  COUNT(*)
----------
        10
*/

--recyclebin 을 조회해보자
select object_name, original_name, type, operation, createtime, droptime from user_recyclebin;
/*
선택된 레코드가 없습니다.
*/

3      FlashBack Query

3.1      개요

FlashBack Query Oracle 9i에서 처음 소개되었고, 특정 시점의 데이터를 조회하는 기능을 제공한다. 특정 시점의 지정은 SCN 또는 Timestamp를 지정하여 조회 할 수 있으며, Oracle 10g R1부터는 범위를 주어 서로 다른 버전을 함께 보여줄 수 있도록 확장되었다. 이 기능은 Oracle Undo Segment의 내용을 기반으로 제공되므로 UNDO_RETENTION 파라미터에 의존적이다.

3.2      FlashBack Version Query

Flashback version query의 기본 문법은 아래와 같다.
SELECT <columns>
FROM <schema_name.table_name>
[
VERSIONS BETWEEN <SCN|TIMESTAMP> <EXPR> AND <EXPR>
OR
AS OF <SCN|TIMESTAMP> <EXPR>
]
[WHERE <column_filter>]
[GROUP BY <non-aggregated_columns>]
[HAVING <group filter>
[ORDER BY <position_numbers_or_column_names>]
--일반적인 Query문과 모두 동일하며 다만 VERSION BETWEEN 또는 AS OF 절을 추가하여 SCN 이나 TIMESTAMP 지정하여 버전 별로 질의를 있다.
데이터가 변경된 후에는 반드시 커밋이 수행되어야 버전관리가 가능해진다.
다음의 예제를 수행하여 보자.
--테스트를 위한 테이블을 생성한다.
create table t5 ( c1 number, c2 varchar2(20), c3 timestamp );

--ORA-01466: unable to read data - table definition has changed
--에러를 막기위하여 10초간의 sleep 시간을 준다.
exec dbms_lock.sleep(10);

--1건의 데이터를 추가한다.
insert into t5 select 1, 'init data', systimestamp from dual;
commit;

--버전간의 시간 간격을 위하여 약 10초간 sleep한다.
exec dbms_lock.sleep(10);

--데이터를 업데이트해보자
update t5 set c2 = 'first update', c3 = systimestamp;
commit;

--버전간의 시간 간격을 위하여 약 10초간 sleep한다.
exec dbms_lock.sleep(10);
select systimestamp from dual;

update t5 set c2 = 'second update', c3 = systimestamp;
commit;

--버전간의 시간 간격을 위하여 약 10초간 sleep한다.
exec dbms_lock.sleep(10);
select systimestamp from dual;

delete t5 where c1 = 1;
commit;

--버전간의 시간 간격을 위하여 약 10초간 sleep한다.
exec dbms_lock.sleep(10);
select systimestamp from dual;

--flashback version query를 이용하여 버전별 데이터를 조회해보자
--지금까지 수행한 DML이 버전별로 관리되어 있는 것을 확인할 수 있다.
select c1, c2, c3 from t5
versions between timestamp minvalue and maxvalue;
/*
C1 C2               C3
--- --------------- --------------------------
 1 second update    10/04/18 09:29:02.797367
 1 second update    10/04/18 09:29:02.797367
 1 first update     10/04/18 09:28:52.705343
 1 init data        10/04/18 09:28:42.649270

아래와 같은 표현도 가능하다
select c1, c2, c3 from t5
versions between timestamp (systimestamp - interval '30' minute) and (systimestamp - interval '1' minute);
*/
flashback version query에서는 다음과 같은 pseudo column을 제공한다.
l    VERSION_STARTTIME : version의 유효 시작시간
l    VERSION_STARTSCN : version의 유효 시작 SCN
l    VERSION_ENDTIME : version의 유효 종료시간(이 값이 NULL인 경우는 현재 사용중인 버전이거나 row가 삭제된 것이다.)
l    VERSION_ENDSCN : version의 유효 종료 SCN(이 값이 NULL인 경우는 현재 사용중인 버전이거나 row가 삭제된 것이다.)
l    VERSION_XID : version transaction id
l    VERSION_OPERATION : version DML Operation(I = insert, U = update, D = delete)
다음의 예제를 수행하여 pseudo-column의 사용법을 확인하자.
select c2, c3
      ,versions_starttime, versions_endtime, versions_xid, versions_operation
from  t5
versions between timestamp minvalue and maxvalue
order by versions_endtime;

3.3      FlashBack Transaction Query

오라클 10g에서 새롭게 제공하기 시작한 VIEW로서, 데이터 버전에 대한 더 많은 정보를 제공한다. 각각의 변경에 대하여 수행된 SQL 문장도 확인할 수 있다.
     FLASHBACK_TRANSACTION_QUERY VIEW에서 제공하는 컬럼은 다음과 같다.
l  XID : transaction ID
l  START_SCN : transaction이 시작된 시점의 SCN
l  START_TIMESTAMP : transaction이 시작된 시점의 timestamp
l  COMMIT_SCN : transaction commit된 시점의 SCN
l  COMMIT_TIMESTAMP : transaction commit된 시점의 timestamp
l  LOGON_USER : transaction을 발생시킨 logon user
l  UNDO_CHANGE# : UNDO SCN
l  OPERATION : transaction에 수행된 DML Operation(DELETE, INSERT, UPDATE, UNKNOWN)
l  TABLE_NAME : DML이 적용된 테이블 명
l  TABLE_OWNER : DML이 적용된 테이블의 소유자명
l  ROW_ID : DML에 의해 수정된 row rowid
l  UNDO_SQL : 적용된 DML 문장을 취소(UNDO)하기 위한 SQL



select xid, operation, undo_sql
from   flashback_transaction_query
where  table_owner = user
and    table_name = 'T5'
order by start_timestamp;
/*
XID              OPERATION  UNDO_SQL
---------------- ----------------------------------------------------------------
11000F0059020000 INSERT delete from "TEST"."T5" where ROWID = 'AAANEyAAAAAAAAAAAA';
0C000F0082030000 UPDATE update "TEST"."T5" set "C2" = 'init data', "C3" = TO_TIMESTAMP('10/04/18 09:28:42') where ROWID = 'A
0D00030080030000 UPDATE update "TEST"."T5" set "C2" = 'first update', "C3" = TO_TIMESTAMP('10/04/18 09:28:52') where ROWID =
0E001E0055020000 DELETE insert into "TEST"."T5"("C1","C2","C3") values ('1','second update',TO_TIMESTAMP('10/04/18 09:29:02'
*/

3.4      Timestamp and SCNs

Timestamp SCN은 간단한 방법으로 서로 변환이 가능하다. 오라클 10g에서 제공하는 두 가지의 변환 함수인 TIMESTAMP_TO_SCN SCN_TO_TIMESTAMP를 이용하면 된다. 그리고 DBMS_FLASHBACK.GET_SYSTEM_CHANGE_NUMBER를 이용하거나 v$database view를 조회하면 현재의 SCN을 확인 할 수 있다.
alter session set nls_timestamp_format = 'yyyy-mm-dd hh24:mi:ss.ff3';
/*
SYSTIMESTAMP                       LOCALTIMESTAMP          SCN
-------------------------------------------------------------------
10/04/18 09:57:04.534631 +09:00   2010-04-18 09:57:04.534  6235359
*/

select systimestamp, localtimestamp, dbms_flashback.get_system_change_number as scn
from   dual;
/*
SYSTIMESTAMP                       LOCALTIMESTAMP          SCN
-------------------------------------------------------------------
10/04/18 09:57:04.534631 +09:00   2010-04-18 09:57:04.534  6235359
*/

select scn_to_timestamp(6235359) tstamp from dual;
/*
TSTAMP
------------------------
2010-04-18 09:57:04.000
*/

select timestamp_to_scn('2010-04-18 09:57:04.000') scn from dual;
/*
       SCN
----------
   6235352
*/

---------------------------------------------------------------------------------------------------

[1] Online redo log로부터 Instance fail 이전에 수행되고 시스템에 반영되지 않은 모든 명령을 재 수행 하는 과정
[2] Roll forward 수행 후 commit 되지 않는 사항을 rollback하는 과정
[3] 장애가 발생하기 직전의 상태(최신의 상태) Database 복구함
[4] 과거의 특정시점으로 Database를 복구함
[5] UNDO_RETENTION 파라미터는 UNDO_SEGMENT에 저장된 변경전의 데이터를 유지하고자 하는 시간(초 단위)을 설정한다.