블로그 이미지
redkite

카테고리

분류 전체보기 (291)
00.SI프로젝트 산출물 (0)
00.센터 운영 문서 (0)
01.DBMS ============.. (0)
01.오라클 (117)
001.DB 관리 (19)
002.DB 마이그레이션 (8)
003.DB 백업 및 복구 (20)
004.DB 보안 (8)
005.DB 설치 (7)
006.DB 스크립트 (0)
007.DB Knowledge Bas.. (38)
008.DB 통계 및 공간 관리 (3)
009.DB Trouble Shoot.. (14)
010.교육자료 (0)
999.테스트 (0)
01.MS-SQL (15)
01.MySQL (30)
01.PostgreSql (0)
01.DB튜닝 (28)
====================.. (0)
02.SERVER ==========.. (0)
02.서버-공통 (11)
02.서버-Linux (58)
02.서버-Unix (12)
02.서버-Windows (2)
====================.. (0)
03.APPLICATION =====.. (11)
====================.. (0)
04.ETC =============.. (0)
04.보안 (5)
====================.. (0)
05.개인자료 (1)
06.캠핑관련 (0)
07.OA관련 (1)
Total
Today
Yesterday

달력

« » 2024.5
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

공지사항

최근에 올라온 글

0011. ROWNUM 쿼리 분석

ROWNUM의 동작 원리와 활용 방법 SQL*Plus 명령

결과 셋의 제한

ROWNUM은 오라클 데이터베이스가 제공하는 마술과도 같은 컬럼입니다. 이 때문에 많은 사용자들이 문제를 겪기도 합니다. 하지만 그 원리와 활용 방법을 이해한다면 매우 유용하게 사용할 수 있습니다. 필자는 주로 두 가지 목적으로 ROWNUM을 사용합니다.

  • Top-N 프로세싱: 이 기능은 다른 일부 데이터베이스가 제공하는 LIMIT 구문과 유사합니다.
  • 쿼리 내에서의 페이지네이션(pagination) – 특히 웹과 같은 "stateless" 환경에서 자주 활용됩니다. 필자는 asktom.oracle.com 웹 사이트에서도 이 테크닉을 사용하고 있습니다.

두 가지 활용 방안을 설명하기 전에, 먼저 ROWNUM의 동작 원리에 대해 살펴 보기로 하겠습니다


ROWNUM의 동작 원리

ROWNUM은 쿼리 내에서 사용 가능한 (실제 컬럼이 아닌) 가상 컬럼(pseudocolumn)입니다. ROWNUM에는 숫자 1, 2, 3, 4, ... N의 값이 할당됩니다. 여기서 N 은 ROWNUM과 함께 사용하는 레코드(row, record)의 수를 의미합니다. ROWNUM의 값은 레코드에 영구적으로 할당되지 않습니다(이는 사람들이 많이 오해하는 부분이기도 합니다). 테이블의 레코드는 숫자와 연계되어 참조될 수 없습니다. 따라서 테이블에서 "row 5"를 요청할 수 있는 방법은 없습니다. "row 5"라는 것은 존재하지 않기 때문입니다.

또 ROWNUM 값이 실제로 할당되는 방법에 대해서도 많은 사람들이 오해를 하고 있습니다. ROWNUM 값은 쿼리의 조건절이 처리되고 난 이후, 그리고 sort, aggregation이 수행되기 이전에 할당됩니다. 또 ROWNUM 값은 할당된 이후에만 증가(increment) 됩니다. 따라서 아래 쿼리는 로우를 반환하지 않습니다.

select * from t where ROWNUM > 1;

첫 번째 로우에 대해 ROWNUM > 1의 조건이 True가 아니기 때문에, ROWNUM은 2로 증가하지 않습니다.
아래와 같은 쿼리를 생각해 봅시다.

select ..., ROWNUM from t where <where clause> group by <columns>having <having clause> order by <columns>;

이 쿼리는 다음과 같은 순서로 처리됩니다.

1. FROM/WHERE 절이 먼저 처리됩니다.
2. ROWNUM이 할당되고 FROM/WHERE 절에서 전달되는 각각의 출력 레코드에 대해 증가(increment) 됩니다.
3. SELECT가 적용됩니다.
4. GROUP BY 조건이 적용됩니다.
5. HAVING이 적용됩니다.
6. ORDER BY 조건이 적용됩니다.

따라서 아래와 같은 쿼리는 에러가 발생할 수 밖에 없습니다.

select * from emp where ROWNUM <= 5 order by sal desc;

이 쿼리는 가장 높은 연봉을 받는 다섯 명의 직원을 조회하기 위한 Top-N 쿼리로 작성되었습니다.
하지만 실제로 쿼리는 5 개의 레코드를 랜덤하게(조회되는 순서대로) 반환하고 salary를 기준으로 정렬합니다.
이 쿼리를 위해서 사용되는 가상코드(pseudocode)가 아래와 같습니다.

ROWNUM = 1for x in ( select * from emp )loop exit when NOT(ROWNUM <= 5) OUTPUT record to temp ROWNUM = ROWNUM+1end loopSORT TEMP

위에서 볼 수 있듯 처음의 5 개 레코드를 가져 온후 바로 sorting이 수행됩니다.
쿼리에서 "WHERE ROWNUM = 5" 또는 "WHERE ROWNUM > 5"와 같은 조건은 의미가 없습니다.
이는 ROWNUM 값이 조건자(predicate) 실행 과정에서 레코드에 할당되며, 레코드가 WHERE 조건에 의해 처리된 이후에만 increment 되기 때문입니다.

올바르게 작성된 쿼리가 아래와 같습니다.

select * from ( select * from emp order by sal desc ) where ROWNUM <= 5;

위 쿼리는 salary를 기준으로 EMP를 내림차순으로 정렬한 후, 상위의 5 개 레코드(Top-5 레코드)를 반환합니다.
아래에서 다시 설명되겠지만, 오라클 데이터베이스가 실제로 전체 결과 셋을 정렬하지 않습니다.
(오라클 데이터베이스는 좀 더 지능적인 방식으로 동작합니다.) 하지만 사용자가 얻는 결과는 동일합니다.


ROWNUM을 이용한 Top-N 쿼리 프로세싱

일반적으로 Top-N 쿼리를 실행하는 사용자는 다소 복잡한 쿼리를 실행하고, 그 결과를 정렬한 뒤 상위의 N 개 로우만을 반환하는 방식을 사용합니다. ROWNUM은 Top- N쿼리를 위해 최적화된 기능을 제공합니다. ROWNUM을 사용하면 대량의 결과 셋을 정렬하는 번거로운 과정을 피할 수 있습니다. 먼저 그 개념을 살펴보고 예제를 통해 설명하기로 하겠습니다.

아래와 같은 쿼리가 있다고 가정해 봅시다.

select ... from ... where ... order by columns;

또 이 쿼리가 반환하는 데이터가 수천 개, 수십만 개, 또는 그 이상에 달한다고 가정해 봅시다. 하지만 사용자가 실제로 관심 있는
것은 상위 N개(Top 10, Top 100)의 값입니다. 이 결과를 얻기 위한 방법에는 두 가지가 있습니다.

  • 클라이언트 애플리케이션에서 쿼리를 실행하고 상위 N 개의 로우만을 가져오도록 명령
  • 쿼리를 인라인 뷰(inline view)로 활용하고, ROWNUM을 이용하여 결과 셋을 제한 (예: SELECT * FROM (your_query_here) WHERE ROWNUM <= N)

두 번째 접근법은 첫 번째에 비해 월등한 장점을 제공합니다. 그 이유는 두 가지입니다. 첫 번째로, ROWNUM을 사용하면 클라이언트의 부담이 줄어듭니다. 데이터베이스에서 제한된 결과 값만을 전송하기 때문입니다. 두 번째로, 데이터베이스에서 최적화된 프로세싱 방법을 이용하여 Top N 로우를 산출할 수 있습니다. Top-N 쿼리를 실행함으로써, 사용자는 데이터베이스에 추가적인 정보를 전달하게 됩니다. 그 정보란 바로 "나는N 개의 로우에만 관심이 있고, 나머지에 대해서는 관심이 없다"는 메시지입니다. 이제, 정렬(sorting) 작업이 데이터베이스 서버에서 어떤 원리로 실행되는지 설명을 듣고 나면 그 의미를 이해하실 수 있을 것입니다. 샘플 쿼리에 위에서 설명한 두 가지 접근법을 적용해 보기로 합시다.

select * from t order by unindexed_column;

여기서 T가 1백만 개 이상의 레코드를 저장한 큰 테이블이라고, 그리고 각각의 레코드가 100 바이트 이상으로 구성되어 있다고
가정해 봅시다. 그리고 UNINDEXED_COLUMN은 인덱스가 적용되지 않은 컬럼이라고, 또 사용자는 상위 10 개의 로우에만 관심이
있다고 가정하겠습니다. 오라클 데이터베이스는 아래와 같은 순서로 쿼리를 처리합니다.

1. T에 대해 풀 테이블 스캔을 실행합니다.
2. UNINDEXED_COLUMN을 기준으로 T를 정렬합니다. 이 작업은 "full sort"로 진행됩니다.
3. Sort 영역의 메모리가 부족한 경우 임시 익스텐트를 디스크에 스왑하는 작업이 수행됩니다.
4. 임시 익스텐트를 병합하여 상위 10 개의 레코드를 확인합니다.
5.쿼리가 종료되면 임시 익스텐트에 대한 클린업 작업을 수행합니다. .

결과적으로 매우 많은 I/O 작업이 발생합니다. 오라클 데이터베이스가 상위 10 개의 로우를 얻기 위해 전체 테이블을 TEMP 영역으로 복사했을 가능성이 높습니다.

그럼 다음으로, Top-N 쿼리를 오라클 데이터베이스가 개념적으로 어떻게 처리할 수 있는지 살펴 보기로 합시다.

select * from (select * from t order by unindexed_column) where ROWNUM < :N;

오라클 데이터베이스가 위 쿼리를 처리하는 방법은 아래와 같습니다.

1. 앞에서와 마찬가지로 T에 대해 풀-테이블 스캔을 수행합니다(이 과정은 피할 수 없습니다).
2. :N 엘리먼트의 배열(이 배열은 메모리에 저장되어 있을 가능성이 높습니다)에서 :N개의 레코드만을 정렬합니다.

상위N 개의 레코드는 이 배열에 정렬된 순서로 입력됩니다. N +1 레코드를 가져온 경우, 이 레코드를 배열의 마지막 레코드와 비교합니다. 이 레코드가 배열의 N +1 슬롯에 들어가야 하는 것으로 판명되는 경우, 레코드는 버려집니다. 그렇지 않은 경우, 레코드를 배열에 추가하여 정렬한 후 기존 레코드 중 하나를 삭제합니다. Sort 영역에는 최대 N 개의 레코드만이 저장되며, 따라서 1 백만 개의 레코드를 정렬하는 대신N 개의 레코드만을 정렬하면 됩니다.

이처럼 간단한 개념(배열의 활용, N개 레코드의 정렬)을 이용하여 성능 및 리소스 활용도 면에서 큰 이익을 볼 수 있습니다. (TEMP 공간을 사용하지 않아도 된다는 것은 차치하더라도) 1 백만 개의 레코드를 정렬하는 것보다 10 개의 레코드를 정렬하는 것이 메모리를 덜 먹는다는 것은 당연합니다.

아래의 테이블 T를 이용하면, 두 가지 접근법이 모두 동일한 결과를 제공하지만 사용되는 리소스는 극적인 차이를 보임을 확인할 수 있습니다.

create table tasselect dbms_random.value(1,1000000) id, rpad('*',40,'*' ) data from dualconnect by level <= 100000;begindbms_stats.gather_table_stats( user, 'T');end;/Now enable tracing, viaexec dbms_monitor.session_trace_enable(waits=>true);

다음으로 ROWNUM과 함께 top-N 질의를 사용해보면:

select * from(select * from t order by id)where rownum <= 10;

마지막으로 상위 10 개의 레코드만을 반환하는 쿼리를 실행합니다.

declarecursor c isselect * from t order by id;l_rec c%rowtype;begin open c; for i in 1 .. 10 loop fetch c into l_rec; exit when c%notfound; end loop; close c;end;/


이 쿼리를 실행한 후, TKPROF를 사용해서 트레이스 결과를 확인할 수 있습니다. 먼저 Top-N 쿼리 수행 후 확인한 트레이스
결과가 Listing 1과 같습니다.

Code Listing 1: ROWNUM을 이용한 Top-N 쿼리

select * from(select * from t order by id)where rownum <= 10call count cpu elapsed disk query current rows-------- -------- ------- ------- ------- -------- -------- ------ Parse 1 0.00 0.00 0 0 0 0Execute 1 0.00 0.00 0 0 0 0Fetch 2 0.04 0.04 0 949 0 10-------- -------- ------- ------- ------- -------- -------- ------ total 4 0.04 0.04 0 949 0 10Rows Row Source Operation----------------- ---------------------------------------------------10 COUNT STOPKEY (cr=949 pr=0 pw=0 time=46997 us)10 VIEW (cr=949 pr=0 pw=0 time=46979 us)10 SORT ORDER BY STOPKEY (cr=949 pr=0 pw=0 time=46961 us)100000 TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400066 us)

이 쿼리는 전체 테이블을 읽어 들인 후, SORT ORDER BY STOPKEY 단계를 이용해서 임시 공간에서 사용되는 로우를 10 개로
제한하고 있습니다. 마지막 Row Source Operation 라인을 주목하시기 바랍니다. 쿼리가 949 번의 논리적 I/O를 수행했으며(cr=949), 물리적 읽기/쓰기는 전혀 발생하지 않았고(pr=0, pw=0), 불과 400066 백만 분의 일초 (0.04 초) 밖에 걸리지 않았습니다. 이 결과를 Listing 2의 실행 결과와 비교해 보시기 바랍니다.


Code Listing 2:ROWNUM을 사용하지 않은 쿼리

SELECT * FROM T ORDER BY IDcall count cpu elapsed disk query current rows-------- -------- ------- ------- ------- -------- -------- ------ Parse 1 0.00 0.00 0 0 0 0Execute 2 0.00 0.00 0 0 0 0Fetch 10 0.35 0.40 155 949 6 10-------- -------- ------- ------- ------- -------- -------- ------ total 13 0.36 0.40 155 949 6 10Rows Row Source Operation----------------- ---------------------------------------------------10 SORT ORDER BY (cr=949 pr=155 pw=891 time=401610 us)100000 TABLE ACCESS FULL T (cr=949 pr=0 pw=0 time=400060 us)Elapsed times include waiting for the following events:Event waited on Times------------------------------ ------------direct path write temp 33direct path read temp 5

결과가 완전히 다른 것을 확인하실 수 있습니다. "elapsed/CPU time"이 크게 증가했으며, 마지막 Row Source Operation 라인을
보면 그 이유를 이해할 수 있습니다. 정렬 작업은 디스크 상에서 수행되었으며, 물리적 쓰기(physical write) 작업이 "pw=891"회 발생했습니다. 또 다이렉트 경로를 통한 읽기/쓰기 작업이 발생했습니다. (10 개가 아닌) 100,000 개의 레코드가 디스크 상에서 정렬되었으며, 이로 인해 쿼리의 실행 시간과 런타임 리소스가 급증하였습니다.


ROWNUM을 이용한 페이지네이션

필자가 ROWNUM을 가장 즐겨 사용하는 대상이 바로 페이지네이션(pagination)입니다. 필자는 결과 셋의 로우 N 에서 로우 M까지를 가져오기 위해 ROWNUM을 사용합니다. 쿼리의 일반적인 형식이 아래와 같습니다.

select * from ( select /*+ FIRST_ROWS(n) */ a.*, ROWNUM rnum from ( your_query_goes_here, with order by ) a where ROWNUM <= :MAX_ROW_TO_FETCH ) where rnum >= :MIN_ROW_TO_FETCH;여기서,

  • FIRST_ROWS(N)는 옵티마이저에게 "나는 앞부분의 로우에만 관심이 있고, 그 중 N 개를 최대한 빨리 가져오기를 원한다"는 메시지를 전달하는 의미를 갖습니다.
  • :MAX_ROW_TO_FETCH는 결과 셋에서 가져올 마지막 로우로 설정됩니다. 결과 셋에서 50 번째 – 60 번째 로우만을 가져오려 한다면 이 값은 60이 됩니다.
  • :MIN_ROW_TO_FETCH는 결과 셋에서 가져올 첫 번째 로우로 설정됩니다. 결과 셋에서 50 번째 – 60 번째 로우만을 가져오려 한다면 이 값은 50이 됩니다.

이 시나리오는 웹 브라우저를 통해 접속한 사용자가 검색을 마치고 그 결과를 기다리고 있는 상황을 가정하고 있습니다. 따라서 첫 번째 결과 페이지(그리고 이어서 두 번째, 세 번째 결과 페이지)를 최대한 빨리 반환해야 할 것입니다. 쿼리를 자세히 살펴 보면, (처음의 :MAX_ROW_TO_FETCH 로우를 반환하는) Top-N 쿼리가 사용되고 있으며, 따라서 위에서 설명한 최적화된 기능을 이용할 수 있음을 알 수 있습니다. 또 네트워크를 통해 클라이언트가 관심을 갖는 로우만을 반환하며, 조회 대상이 아닌 로우는 네트워크로 전송되지 않습니다.

페이지네이션 쿼리를 사용할 때 주의할 점이 하나 있습니다. ORDER BY 구문은 유니크한 컬럼을 대상으로 적용되어야 합니다. 유니크하지 않은 컬럼 값을 대상으로 정렬을 수행해야 한다면 ORDER BY 조건에 별도의 조건을 추가해 주어야 합니다. 예를 들어 SALARY를 기준으로 100 개의 레코드를 정렬하는 상황에서 100 개의 레코드가 모두 동일한 SALARY 값을 갖는다면, 로우의 수를 20-25 개로 제한하는 것은 의미가 없을 것입니다. 여러 개의 중복된 ID 값을 갖는 작은 테이블을 예로 들어 설명해 보겠습니다.

SQL> create table t 2 as 3 select mod(level,5) id, trunc(dbms_random.value(1,100)) data 4 from dual 5 connect by level <= 10000;Table created.

ID 컬럼을 정렬한 후 148-150 번째 로우, 그리고 148–151 번째 로우를 쿼리해 보겠습니다.

SQL> select * 2 from 3 (select a.*, rownum rnum 4 from 5 (select id, data 6 from t 7 order by id) a 8 where rownum <= 150 9 ) 10 where rnum >= 148; ID DATA RNUM------- ---------- -----------0 38 1480 64 1490 53 150SQL>SQL> select * 2 from 3 (select a.*, rownum rnum 4 from 5 (select id, data 6 from t 7 order by id) a 8 where rownum <= 151 9 ) 10 where rnum >= 148; ID DATA RNUM------- ---------- -----------0 59 1480 38 1490 64 1500 53 151

로우 148의 경우 DATA=38의 결과가 반환되었습니다. 두 번째 쿼리에서는 DATA=59의 결과가 반환되었습니다. 두 가지 쿼리 모두
올바른 결과를 반환하고 있습니다. 쿼리는 데이터를 ID 기준으로 정렬한 후 앞부분의 147 개 로우를 버린 후 그 다음의 3 개 또는 4 개의 로우를 반환합니다. 하지만 ID에 중복값이 너무 많기 때문에, 쿼리는 항상 동일한 결과를 반환함을 보장할 수 없습니다. 이 문제를 해결하려면 ORDER BY 조건에 유니크한 값을 추가해 주어야 합니다. 위의 경우에는 ROWID를 사용하면 됩니다.

SQL> select * 2 from 3 (select a.*, rownum rnum 4 from 5 (select id, data 6 from t 7 order by id, rowid) a 8 where rownum <= 150 9 ) 10 where rnum >= 148; ID DATA RNUM------- ---------- -----------0 45 1480 99 1490 41 150SQL>SQL> select * 2 from 3 (select a.*, rownum rnum 4 from 5 (select id, data 6 from t 7 order by id, rowid) a 8 where rownum <= 151 9 ) 10 where rnum >= 148; ID DATA RNUM------- ---------- -----------0 45 1480 99 1490 41 1500 45 151

이제 쿼리를 반복 실행해도 동일한 결과를 보장할 수 있게 되었습니다. ROWID는 테이블 내에서 유니크한 값을 가집니다. 따라서
ORDER BY ID 조건과 ORDER BY ROWID 기준을 함께 사용함으로써 사용자가 기대한 순서대로 페이지네이션 쿼리의 결과를 확인할 수 있습니다.

ROWNUM 개념 정리

지금까지 ROWNUM에 관련하여 아래와 같은 개념을 설명하였습니다.

Posted by redkite
, |

0010. 파티션 테이블 생성

http://docs.oracle.com/cd/B19306_01/server.102/b14231/partiti.htm

1. ADD

ex)

ALTER TABLE LG_CV ADD PARTITION PT_0709 VALUES less than ('0710') TABLESPACE ADWS_00_LG;

2. SPLIT ()

ADD 방법 으로 했는데 "ORA-14074: partition bound must collate higher than that of the last partition" 에러가 날 경우

ex)

alter table LG_TS_URL split partition PT_0710 at('0710')
into (partition PT_0709,partition PT_0710) ;

= SPLIT 설명 =

ALTER TABLE &Table_Name
SPLIT PARTITION &분할대상Partition_Name AT ('&SplitValue')
INTO (
PARTITION &하위Partition_Name TABLESPACE &하위파티션TableSpace_Name,
PARTITION &상위Partition_Name TABLESPACE &상위파티션TableSpace_Name
);

- &Table_Name : 변경할 테이블 명
- &분할대상Partition_Name : Partition Key가 'MAXVALUE'인 현재 최상위 Partition 이름
- &SplitValue : 분할 기준이 되는 값
- &하위Partition_Name : 분할될 영역 중 하위 Partition 명 즉, 최상위 Partition 이름
- &하위파티션TableSpace_Name : 분할될 영역 중 하위 Partition이 사용할 TableSpace명
- &상위Partition_Name : 분할될 영역 중 상위 Partition 명 즉, 신규 Partition 이름
- &상위파티션TableSpace_Name : 분할될 영역 중 상위 Partition이 사용할 TableSpace명
※ Partition Split 구문은 해당 Table의 Local Index를 자동으로 생성하나 Local Index의
Partition 명 및 Tablespace도 Table 분할시 지정하였던 이름으로 지정 및 생성되지여.
고로, Rename 및 Tablespace를 변경 해야함다..
※ Partition Split 구문은 사용시 해당 Table의 Global Index(PK)는 사용불가 상태가 되며
Rebuild 작업을 해야함다.

작업이 끝나면 정상적으로 분할되었나 확인하시면 되여..
SELECT *
FROM USER_TAB_PARTITIONS
WHERE TABLE_NAME = 'TABLE명'

Posted by redkite
, |

No. 12141


10g-standbyDB생성.pdf


database crash 시 backup받아둔 datafile과 archive file을 모두 restore하고,
recover하는 작업은 경우에 따라 고객의 요구 사항보다 길어지는 경우가 종종
있다.
이런 경우 미리 standy db를 구성하여 standby db에 recovery를 진행해 두고,
piramry db crash시 바로 stadnby db와 연결하면, db down time을 최소화하는데
많은 도움이 된다.

Oracle 8.1부터 이 standby db에 새로운 기능이 추가되어, 이전 version에서,
주기적으로 archive file 적용 및 recover 작업을 수행해야 하는 필요를 덜어
주었다.
단, Automated Standby database Feature는 8i~10g Standard Edition에서는
지원하지 않는다.

이 문서에서 자세한 설정 방법 및 추가된 기능들을 확인한다.

1. 추가된 기능 정리
(1) primary db에서 archive file생성시 standby db에도 자동 전달

(2) standby db에 전달된 archive file이 자동으로 standby db에 적용

(3) standby db activate없이, standy db를 read only mode로 open

2. 구성 절차

(1) standby db가 구성될 system에 oracle을 primary db와 동일한 version으로
install한다.
- OS는 primary db와 동일해야 한다.
- database는 install할 필요없이, software만 install하면 된다.
- datafile, controlfile, redo log file이 생성될 directory를 만들어
둔다.
(가능하면 primary db와 동일한것이 좋다),

(2) primary db의 init.ora를 standby db에 copy한다.
- primary db의 $ORACLE_HOME/dbs/initSID.ora file을 standby db에
copy한다.
- initSID.ora file에 ifile=로 정의된 file이 있다면 그 file도 해당
directory에 copy한다.
- 이러한 initial parameter중 background_dump_dest, user_dump_dest,
core_dump_dest, archive_log_dest 등에 지정된 directory도 standby 쪽,
server에 생성해둔다.

(3) primary db에 multiple archive destination을 위한 parameter지정
다음과 같은 형태로 primary db를 위한 archive parameter외에,
standby db쪽에 자동으로 archive file이 생성되도록 destination을
initSID.ora file에 지정한다.

log_archive_start = true
log_archive_dest_1 = "location=/user/oradata/archive"
log_archive_format = arch%s.arc

log_archive_dest_2 = 'SERVICE=sby OPTIONAL REOPEN=60'
log_archive_dest_state_2 = ENABLE

- 이 예에서 sby라는 것은 primary db의 tnsnames.ora file에 미리
정의되어 있어야 하며, standby db에 대한 description을 가져야 한다.
- REOPEN은 standby db쪽으로 archive가 실패한경우 지정된 초만큼 후에
다시 archive를 시도하라는 의미이다.
- OPTIONAL의 의미는 지정된 archive가 실패하는 경우라도 primary db의
log_archive_dest_1에 지정된 곳에 archive만 성공하면 archive작업을
중단없이 계속 진행하라는 것이다.

(4) standby db의 initSID.ora file 수정

primary db에서 자동으로 전달되어온 archive file이 위치하게 될
destination과 datafile이나 redo log file이 위치할 directory 구조가
primary db와 다른 경우를 대비한 parameter를 다음 예와 같이 설정한다.

standby_archive_dest=/user/oradata/archive

log_archive_start = true
log_archive_dest_1 = "location=/user/oradata/archive"
log_archive_format = arch%S.ARC

db_file_name_convert="PROD","SBY"
log_file_name_convert="PROD","SBY"

- standby_archive_dest는 primary db에서 multiple archive destination을
지정하는 경우 자동으로 생성될 archive file의 위치를 나타낸다.
- standby_archive_dest뒤에는 log_archive_dest와 같은 location=은
적으면 안된다. 적을시엔 자동으로 archive가 전달되지 않고, primary db의
alert.log에 오류가 기록된다.
- 실제 recover시나 이후 open되어 archive가 생성되는 시에는
log_archive_dest 부분이 참조된다.

- db_file_name_conver나 log_file_name_convert의 경우는, primary db와
standby db간에 datafile, redo log file이 위치하는 directory가 다른
경우 directory 이름중 다른 부분을 치환하도록 하는 것이다.

이 경우 primary db는 /user/oradata/PROD directory에 file이 존재하고,
standby db는 /user/oradata/SBY directory에 위치하는 경우에 대한 예이다.

- 만약 datafile이 여러군데 나뉘어져 있어 이런 변경 부분이 더 필요하다면
다음과 같이 할 수 있다.

db_file_name_convert=('/dbs/t1/','/dbs/t1/s_','dbs/t2/','dbs/t2/s_')
- WindowsNT의 경우는 반드시 directory이름을 반드시 대문자로 하여야 한다.

(5) standby db용 controlfile을 생성
다음 문장을 primary db에서 수행한다. 이후 이렇게 생성된 file은
standby db쪽으로 옮겨질 것이다.

SQL> alter database create standby controlfile as
'/user/oradata/temp/control01.ctl';

(5) primary db의 datafile을 backup받아둔다.
db를 shutdown 시켜 cold backup을 받거나, hot backup을 받는다.
tape등에 backup받는 대신 바로 ftp 등으로 standby db disk로
옮겨도 된다.

(6) 위의 (4),(5)에서 만들어진 controlfile과 datafile을 standby db쪽으로
옮긴다.

(7) standby db에서 다음과 같이 수행한다.

os> sqlplus internal
SQL> startup nomount
SQL> alter database mount standby database;
SQL> recover managed standby database;

- 만약 recover managed standby database대신에 그냥
recover standby database하면, ora-279, 280, 289가 발생하면서,
생성된 archive를 manual하게 적용하면 된다.

(8) standby db에서 primary db가 운영중에 test나 다른 목적으로 data를 읽고자
한다면 read only로 open가능

SQL>alter database open read only;

(9) primary db가 crash가 발생하여 standby db를 운영하고자 한다면 다음과 같이
activate시켜야 하며, 이렇게 한 이후로는 이 standby db는 standby 의 속성은
잃게 되며, 이후에 다시 standby db로 구축하려면 다시 (5)번부터 작업을
재수행하여 구축하여야 한다.

SQL>alter database activate standy database;
SQL>shutdown
SQL>startup

- shutdown후 이제는 더 이상 standby db가 아니므로 primary성격의 multiple
archive destination지정 등을 원하는 경우 parameter를 추가하면 된다.

3. managed recover, read only mode open 관리
(1) managed recover
recover managed database를 수행한 창은 계속 새로 전달되온 archive file을
자동으로 recovery를 시켜준다.
이때 필요에 의해 이 자동 recovery를 중단하고자 한다면,
standby에서 다른 session을 연결하여 다음과 같이 수행하면 된다.

SQL>alter database recover managed standby database cancel;

이렇게 하면,
recover managed standby 상태의 창에서,
ora-283, ora-16037 메시지와 함께, managed recovery가 중단되고,
SQL혹은 SVRMGR prompt상태가 된다.

recover managed standby database와 일반, recover standby database는 필요에
따라, 선택하여 사용하면 되며, recover managed standby databse의 경우 이
문장을 실행한 이후에 생성된 archive file만을 자동 recovery한다.
즉, recover managed standby database문장 수행전에 미리 전달되어 온 archive
file이 있다면, 일단 먼저 recover standby database문장을 통해 recovery를
수행한 이후에, recovey managed standby database문장을 수행하여야 한다.

(2) read only mode open

standby db를 standby db 속성은 그대로 유지하면서 dml 외에 data나 dictionary
조회가 필요한 상황에서는
alter database open read only문장을 수행하여 read only mode로 open할 수 있다.

이렇게 조회후에, 다른 작업없이 recover 문장을 수행하면 다시 mount상태가 되는
것이며, 필요하면 다시 open read only를 하여야 한다.

standby db는 운영 중에 shutdown가 mount, open을 마음대로 할 수 있으나
그 때마다 반드시,
startup nomount;
alter database mount standby database;
(필요한 경우 alter database open read only)
문장을 통해 mount나 open 상태가 되도록 하여야 한다.


Reference Documents
-------------------

<Note:74185.1> Standby Database and Oracle 8.1
<Note:70233.1> How to Create a Oracle 8i Standby Database

Posted by redkite
, |

Version 11.1

 

General Information

Dependencies

file$

ts$

x$ktfbhc

dba_data_files

dba_temp_files

 

dba_free_space

gv$dbfile

 
 

Alter Data Files


Resize An Existing Datafile

ALTER DATABASE DATAFILE '<data_file_name | data_file_number>'
RESIZE <n> K|M|G|T|P|E;

Beware that you can only decrease the size of the datafile with the space that is free between highest used block of the datafile and the last block of the file. If the tablespace is fragmented, the free spaces between extents cannot be deallocated this way. Check dba_free_space for details.

ALTER DATABASE DATAFILE 'c:\oracle\oradata\orabase ools02.tom'
RESIZE 50M;

ALTER DATABASE DATAFILE 'c:\oracle\oradata\orabase ools03.dan'
RESIZE 50M;


Add A Datafile To An Existing Tablespace

ALTER TABLESPACE <tablespace_name>
ADD DATAFILE '<path_and_file_name>' SIZE <n>K|M|G|T|P|E;

ALTER TABLESPACE tools
ADD DATAFILE 'c:\oracle\oradata\orabase ools02.tom' SIZE 20M;

ALTER DATABASE
CREATE DATAFILE '<path_and_file_name>' SIZE <n>K|M|G|T|P|E
AS '<tablespace_name>';

ALTER DATABASE
CREATE DATAFILE 'c:\oracle\oradata\orabase\uwdata03.dbf' SIZE 1G
AS 'UWDATA';


Move Tablespace Datafile

Can also be used to move SYSTEM, SYSAUX, and TEMP tablespace files

SHUTDOWN

STARTUP MOUNT

-- Copy the datafile to it's new location

ALTER DATABASE RENAME FILE
'<old_full_path>' TO '<new_full_path>';

-- then

ALTER DATABASE OPEN;

-- then you can safely delete the old datafile.

conn / as sysdba

shutdown immediate;

startup mount

host

$ cp /u01/oradata/tools01.dbf /u06/oradata/tools01.dbf

$ exit

alter database rename file '/u01/oradata/tools01.dbf'
to '/u06/oradata/tools01.dbf';

alter database open

host

$ rm /u01/oradata/tools.01.dbf

$ exit


Autoextend

ALTER DATABASE DATAFILE <'data_file_name' | data_file_number>
AUTOEXTEND <OFF | ON [NEXT SIZE <n>K|M|G|T|P|E
MAXSIZE <UNLIMITED | <n>K|M|G|T|P|E>;

ALTER DATABASE DATAFILE 'u06/oradata/tools01.dbf' AUTOEXTEND OFF;

ALTER DATABASE DATAFILE 'u06/oradata/tools01.dbf' AUTOEXTEND ON MAXSIZE UNLIMITED;


Online / Offline

ALTER DATABASE DATAFILE <'data_file_name' | data_file_number>
<ONLINE | OFFLINE [FOR DROP]>;

ALTER DATABASE DATAFILE 'u06/oradata/tools01.dbf' OFFLINE;

ALTER DATABASE DATAFILE 'u06/oradata/tools01.dbf' ONLINE;

ALTER DATABASE DATAFILE 'u06/oradata/tools01.dbf' OFFLINE FOR DROP;

 

Alter Temp Files

Resize

alter database tempfile <temp file name>
resize <integer> K|M|G|T|P|E;

ALTER DATABASE TEMPFILE 'temp01.dbf' RESIZE 100M;

Drop

alter database tempfile <temp file name>
drop including datafiles;

ALTER DATABASE TEMPFILE 'temp01.dbf' DROP INCLUDING DATAFILES;

 

Drop Data File


Drop A Datafile

ALTER DATABASE DATAFILE '<file_name_or_file_number>' [offline] DROP;

set linesize 121
col file_name format a80

SELECT file_name, SUM(bytes)/1024/1024 DF_SIZE
FROM dba_data_files
GROUP BY file_name;

ALTER TABLESPACE users ADD datafile SIZE 50M;

SELECT file_name, SUM(bytes)/1024/1024 DF_SIZE
FROM dba_data_files
GROUP BY file_name;

ALTER DATABASE DATAFILE 'C:\ORACLE\PRODUCT\ORADATA\UKOUG\DATAFILE\O1_MF_USERS_35HCKNFO_.DBF'
OFFLINE DROP;

or

ALTER TABLESPACE users DROP DATAFILE 'C:\ORACLE\PRODUCT\ORADATA\UKOUG\DATAFILE\O1_MF_USERS_35HCKNFO_.DBF';

 

Data File Related Queries


Data File Information

set linesize 121
col file_name format a45
col tablespace_name format a20

SELECT file_name, tablespace_name,
bytes/1024/1024 MB, blocks
FROM dba_data_files
UNION ALL
SELECT file_name, tablespace_name,
bytes/1024/1024 MB, blocks
FROM dba_temp_files
ORDER BY tablespace_name, file_name;


Data File Block Sizing

-- as root created a file system with block size 1024

mkfs.ext3 -b 1024 /dev/sda3

-- mounted it

mount /dev/sda3 /mnt/test

-- and issued

iostat -d -t -x /dev/sda3

-- in another shell

dd if=/tmp/foo of=/mnt/test/foo2 bs=1024k

-- the results

Time: 08:47:05
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s
avgrq-sz
avgqu-sz await svctm %util
/dev/sda3 0.00 0.00 2.00 0.00 4.00 0.00 2.00 0.00
2.00
0.10 50.00 50.00 1.00

Time: 08:47:10
Device: rrqm/s wrqm/s r/s w/s rsec/s wsec/s rkB/s wkB/s
avgrq-sz
avgqu-sz await svctm %util
/dev/sda3 0.00 10200.40 0.20 83.60 0.40 20568.00 0.20
10284.00 245.
45 67.92 810.50 31.03 26.00

-- do the math

wsec/s / wrqm/s = 20568.00 / 10200.40 = 2,017

-- Roughly two sectors of 512 bytes. So write were in blocks of 1K.


Uneven Datafile Usage Within A Tablespace

CREATE TABLESPACE bowie_data
DATAFILE 'c:\bowie\bowie_data01.dbf' size 10m,
'c:\bowie\bowie_data02.dbf' size 10m,
'c:\bowie\bowie_data03.dbf' size 10m
uniform size 64;

col segment_name format a30

SELECT file_id, file_name
FROM dba_data_files
WHERE tablespace_name = 'BOWIE_DATA';

CREATE TABLE one (x NUMBER) TABLESPACE bowie_data;
CREATE TABLE two (x NUMBER) TABLESPACE bowie_data;
CREATE TABLE three (x NUMBER) TABLESPACE bowie_data;
CREATE TABLE four (x NUMBER) TABLESPACE bowie_data;

Now we've create 4 tables in this tablespace. Let's see which data file they were placed in ...

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA';

Note that *all* tables have their first extent created in the *first* data file defined to the tablespace.

Now lets grow these tables and see what happens next.


ALTER TABLE one ALLOCATE EXTENT;
ALTER TABLE two ALLOCATE EXTENT;
ALTER TABLE three ALLOCATE EXTENT;
ALTER TABLE four ALLOCATE EXTENT;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

... and the second extent of each table has been created in the second data file of the tablespace.

If a particular table were to keep growing ...


ALTER TABLE four ALLOCATE EXTENT;
ALTER TABLE four ALLOCATE EXTENT;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

You can see how the extents get allocated to the data files in a round robin fashion. But the first extent is allocate to the first data file (providing it has sufficent space) ...

CREATE TABLE five (x NUMBER) TABLESPACE bowie_data;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

Let's add a new data file. What happens now ...

ALTER TABLESPACE bowie_data
ADD DATAFILE 'c:\bowie\bowie_data04.dbf' SIZE 10M;

ALTER TABLE four ALLOCATE EXTENT;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

A new extent is added to table four. And uses the new datafile.

ALTER TABLE four ALLOCATE EXTENT;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

ALTER TABLE four ALLOCATE EXTENT;

SELECT segment_name, file_id
FROM dba_extents
WHERE tablespace_name = 'BOWIE_DATA'
ORDER BY segment_name;

... and now the new file is used. The files are still used in a round robin fashion with the new file slipping in.

Note how file 16 is the *most* used file and file 19 is the least. If I were to allocate several new tables that were only 1 or 2 extents in size, see how file 16 would be the one to be most "filled".

Posted by redkite
, |
  1. B*Tree Index(Balance Tree Index)
    1
    2 -> 1과 root의 중간값 (250) is branch value
    .. 1~250, 251~500 값 사이의 블럭을 leaf라고함
    ...---> 중간의 값(500) is root value
    ....
    .... -> root와 1000의 중간값(750) is branch value
    1000
    ** 잦은 insert, delete로 인해 index 공간 활용도가 떨어질 경우 index rebulid 작업으로 가능하나, index create 시부터 dept가 깊어진 경우는 다른 문제로 해결해야 함.
  2. SELECTIVITY
    select column_name, num_distinct, density from user_tab_col_statistics where table_name = 'EMPLOYEES';
    벨류값이 0.0에 가까울수록 구별할수 있는 값들이 많은것이고 이것을 selectivity가 좋다고 함.
Posted by redkite
, |

* 데이터 검색

SELECT 칼럼명 , GROUP 함수

FROM 테이블명

WHERE 조건식

GROUP BY 칼럼명

HAVING 조건식

ORDER BY 칼럼이나 표현식 ;

 

 

- DISTINCT : 중복행을 제거함. 항상 SELECT 바로 다음에서 기술

DISTINCT뒤에 나타나는 컬럼들은 모두 DISTINCT의 영향를 받음 기본적으로 오름차순 정렬됨

- ALIAS : 나타날때 컬럼에 대하여 다른 이름을 부여함

- GROUP BY : 전체 데이터를 소그룹으로 나눌 칼럼을 명시한다.

- HAVING : GROUP에 대한 조건을 기술한다.

 

* WHERE절에 사용되는 연산자의 3가지 부류

1. 논리 연산자

- AND : 여러조건을 동시에 만족한다.

- OR : 여러조건들 중 어느 하나라도 만족한다.

- NOT : 조건에 대한 반대를 돌려준다.

2. 논리 비교 연산자 - = : 같다.

- > : 보다 크다.

- >= : 보다 크거나 같다.

- < : 보다 작다.

- <= : 보다 작거나 같다.

 

SQL 비교 연산자 - BETWEEN a AND b : a와 b사이에 있다.(a,b값 포함)

- IN (list) : list의 값 중 어느 하나와 일치한다.

- IS NULL : NULL값을 가졌다.

LIKE '%문자_문자%' : % 는 0개서부터 여러개까지의 문자열을 나타내는

와일드카드 (wildcard)이고 '_' 는 단 하나의 문자를 나타내는 와일드카드입니다.

와일드 카드를 일반문자처럼 쓰고 싶은 경우에는 ESCAPE 옵션을 사용

WHERE name LIKE '%X_Y%' ESCAPE ''

 

EX)

SQL> SELECT name,salary*18 AS 연봉

2 FROM s_emp;

SQL> SELECT name||' '||title

2 FROM s_emp ;

 

SQL> SELECT name, salary*18 연봉 , title

2 FROM s_emp

3 ORDER BY salary*18 DESC ;

 

SQL> SELECT name , salary

2 FROM s_emp

3 WHERE salary BETWEEN 1000 AND 1500;

 

SQL> SELECT name, title , dept_id

2 FROM s_emp

3 WHERE dept_id IN (110,113) ;

 

SQL> SELECT name, start_date , title

2 WHERE start_date BETWEEN '01-JAN-91'

3 AND '31-DEC-91' ;

 

SQL> SELECT dept_id , count(*) 인원수

2 FROM s_emp

3 WHERE dept_id = 110

4 GROUP BY dept_id ;

 

SQL> SELECT dept_id , AVG(salary)

2 FROM s_emp

3 GROUP BY dept_id ;

 

SQL> SELECT dept_id , AVG(salary)

2 FROM s_emp

3 WHERE title = '사원'

4 GROUP BY dept_id ;

 

SQL> SELECT dept_id , title , COUNT(*)

2 FROM s_emp

3 GROUP BY dept_id , title ;

 

SQL> SELECT title , AVG(salary) , COUNT(*)

2 FROM s_emp

3 GROUP BY title

4 HAVING COUNT(*) > 2 ;

 

SQL> SELECT title , SUM(salary) 급여총합

2 FROM s_emp

3 WHERE title NOT LIKE '%부장'

5 HAVING SUM(salary) > 10000

6 ORDER BY SUM(salary) ;

 

* SQL*PLUS의 기능

 

- 버퍼에 있는 명령어 편집하기

A(PPEND) text : line의 끝에 text를 추가함

C(HANGE)/old/new : old를 new로 바꿈

DEL n : n line을 지움

I(NPUT) text : 다음 line에 text를 추가함

L(IST) : 전체 문장을 보여줌

n text : n line전체를 text로 바꿈

R(UN) : buffer에 있는 문장을 실행함(/ 와 같음)

EDIT : buffer에 있는 문장을 파일로 부름(afiedt.buf)

 

- 파일에 있는 명령어 편집하기

SAVE a : buffer에 있는 내용을 a.sql 파일로 저장

GET a : 파일 a에 있는 내용을 buffer로 부름

START a (=@a) : 파일 a를 실행함

! : UNIX Shell로 나들이

!vi a.sql : 파일 a.sql을 vi편집기로 부름

 

- 환경설정 : SET 환경변수 값

COLSEP (text) : 칼럼이 표시될때 칼럼간의 구별문자 기본값은 공백

FEEDBACK (off|on) : 선택된 행이 몇행인지를 표시함 기본값은 6행 이상인 경우에 on

HEADING (off|on) : 칼럼에 대한 HEADING를 표시함 기본 값은 on

LINESIZE (n) : 한 라인당 표시되는 문자의 수 기본값은 80

PAGES (n) : 한 페이지당 표시되는 라인수 기본값은 24

PAUSE (off|on|text) : 「ENTER」키를 누를 때마다 화면이 지나감 기본값은 off

TIMING (off|on) : SQL문장이 처리되는데 걸리는 시간을 표시 기본값은 off

SHOW : SET 환경이 어떻게 설정되어 있는지 보는 명령어

SHOW ALL : 전체가 어떻게 설정되어 있는지 보고 싶은 경우

 

!. 자신이 쓰는 환경을 항상 맞추고 싶으면 login.sql 파일에 SET환경을 설정하면 됩니다.

 

- 표시형식

COL(UMN) 칼럼이나 ALIAS 옵션

 

- 옵션의 종류 - CLE(AR) : 칼럼에 지정된 형식을 지움

- FOR(MAT) : 형식 칼럼에 대한 표시 형식과 폭을 바꿈

- HEADING text : 칼럼에 대한 HEADING를 지정함

ex)

SQL> COL name HEADING '사원이름' FORMAT A10

SQL> COL salary FORMAT $9,999,999

SQL> COL salary CLEAR

CLEAR COLUMNS : 지정된 형식을 다 지우고 싶은 경우

 

- 변수사용

& 변수 사용 :

사용자가 원하는 데이터를 사용할 때마다 입력하고 싶은 경우에 치환변수를 사용.

사용시에는 &기호를 이용

&&기호를 사용하면 한번 입력받은 변수값을 다시 적용할 수 있음

&기호를 이용하여 조건, 칼럼명, 테이블명, 전체 SELECT구문도 받을 수 있음

EX)

SQL> SELECT id,name,dept_id

2 FROM s_emp

3 WHERE dept_id = &부서번호 ;

Enter value for 부서번호: 112

old 3: WHERE dept_id = &부서번호

new 3: WHERE dept_id = 112

 

 

- ACCEPT를 사용한 변수

사용자가 SELECT구문을 사용하기 전에 미리 변수를 설정해 놓는 경우에 ACCEPT를

사용할 수 있습니다.

> ACCEPT 변수명 데이터타입 FORMAT PROMPT text HIDE

데이터타입 : NUMBER,CHAR,DATE 중에서 지정

FORMAT : A10, 9,999등의 표시 형식지정

PROMPT text : 사용자가 데이터를 입력할 때 보여주는 문장

HIDE : password등을 지정시 화면에 보이지 않도록 함

EX)

SQL> ACCEPT p_salary NUMBER PROMPT '급여 입력 :'

SQL> ACCEPT pswd CHAR PROMPT 'Password : ' HIDE

 

 

 

* 단일행 함수

- 문자형 함수

UPPER : 모든 문자를 대문자로 전환

LOWER : 모든 문자를 소문자로 전환

INITCAP : 문자를 단어별로 앞머리는 대문자 나머지는 소문자로 전환

CONCAT : 두 문자열을 합성. ||연산자와 같은 용도로 사용

SUBSTR : 특정문자열의 부분을 선택

LENGTH : 문자열의 길이를 구함

LPAD : 왼쪽 문자 자리를 채움

RPAD : 오른쪽 문자 자리를 채움

LTRIM : 왼쪽 문자를 지움

RTRIM : 오른쪽 문자를 지움

TRANSLATE : 특정 문자열을 대체

REPLACE : 특정 문자열을 대신

 

UPPER(문자값) : UPPER('Oracle Server')

→ ORACLE SERVER

LOWER(문자값) : LOWER('Oracle Server')

→ oracle server

INITCAP(문자값) : INITCAP('Oracle Server')

→ Oracle Server

CONCAT(문자값1, 문자값2) : CONCAT('Oracle',' Server')

→ Oracle Server

SUBSTR(문자값, a, b)

 

a 선택할 문자열의 시작위치. 음수면 끝에서부터 시작

b 선택할 문자열의 개수. 이 인자는 생략할 수 있으며, 생략할 경우 문자열의 끝까지 선택

 

: SUBSTR('강남구 역삼동',5,2)

→ 역삼

LENGTH(문자값1, a, 문자값2) : LENGTH('홍길동')

→ 3

LPAD(문자값1, a, 문자값2)

RPAD(문자값1, a, 문자값2)

 

a : 전체 채울 자리수

문자값2 : 채울 문자

생략할 수 있으며, 생략되면 공백값임

 

: LPAD('홍길동',10 '*')

→ ****홍길동

LTRIM(문자값1, 문자값2)

RTRIM(문자값1, 문자값2)

문자값1에서 왼쪽(오른쪽)에서부터

더이상 문자값2를 만나지 않을 때까지 지움

 

: LTRIM('XXAXBA','X')

→ AXBA

TRANSLATE(문자값, a, b)

a 대체하고 싶은 문자(from)

b 대체할 결과의 문자(to)

 

: TRANSLATE('AABBA','B','C')

→ AACCA

REPLACE (문자값, a, b)

a 바꾸고 싶은 문자(from)

b 바꿀 결과의 문자(to)

 

: REPLACE ('JACK and JUE','J','BL')

→ BLACK and BLUE

 

- 숫자형 함수

ROUND : 숫자를 반올림

TRUNC : 숫자를 절사

MOD : 나누기 연산에서 나머지 구함

POWER : 거듭제곱

SQRT : 제곱근

SIGN : 양수인지 음수인지 0인지를 구벌함

CHR : ASCII 값에 해당하는 문자를 구함

ROUND(숫자값, a), TRUNC(숫자값, a) a 숫자값을 반올림(버림)하여 a자리까지 돌려줌.

a가 양수이면 소수이하자리를, 음수이면 정수 부분 자리임 생략할 수 있으며, 생략하면 0

 

: ROUND(35.735,2)→35.74

MOD(숫자값, a )

a 숫자값을 나누기 할 수 있음

 

: MOD(7,2)→1

POWER(숫자값1, 숫자값2) : POWER(3,2)→9

SQRT (숫자값) : SQRT(25)→5

SIGN(숫자값) : SIGN(-15)→-1

CHR(숫자값) : CHR(65)→A

 

- 날짜형 함수

SYSDATE : 현재 시스템의 날짜 및 시간을 구함

LAST_DAY : 지정한 날짜의 해당 월의 마지막 날짜를 구함

MONTHS_BETWEEN : 두 날짜 사이의 개월 수를 구함

ADD_MONTHS : 지정한 날짜로부터 몇 개월 후의 날짜를 구함

ROUND : 날짜에 대한 반올림

TRUNC : 날짜에 대한 버림

 

SYSDATE :

SYSDATE → 10-MAY-99

 

LAST_DAY(날짜값) :

LAST_DAY('17-FEB-98') → 28-FEB-98

 

MONTHS_BETWEEN(날짜값1, 날짜값2) :

MONTHS_BETWEEN('26-APR-97','22-JUL-95') → 21.1290323

 

ADD_MONTHS(날짜값, 숫자값) :

ADD_MONTHS('22-JUL-95',21) → 22-APR-97

 

ROUND(날짜값, 자리수) :

현재 날짜가 1999년 5월 10일이라고 가정하자.

 

ROUND(SYSDATE,'MONTH') → 01-MAY-99

 

TRUNC(날짜값, 자리수) :

현재 날짜가 1999년 5월 10일이라고 가정하자.

 

TRUNC(SYSDATE,'YEAR') → 01-JAN-99

 

- 날짜에 대한 산술연산

날짜 + 숫자 : 날짜 특정한 날로부터 몇일 후의 날짜 계산

날짜 - 숫자 : 날짜 특정한 날로부터 몇일 전의 날짜 계산

날짜 - 날짜 : 숫자 두 날짜 사이의 차이를 숫자로 계산

 

- 변환형 함수

TO_CHAR : 숫자나 날짜를 문자열로 변환

TO_NUMBER : 문자를 숫자로 변환

TO_DATE : 문자를 날짜로 변환

 

- TO_CHAR에서 숫자를 문자로 변환시에 형식에 사용되는 요소

9 : 일반적인 숫자를 나타냄

0 : 앞의 빈자리를 0으로 채움

$ : dollar를 표시함

L : 지역 통화 단위(ex )

. : 소숫점을 표시함

, : 천단위를 표시함

 

- TO_CHAR에서 날짜를 문자로 변환시에 형식에 사용되는 요소

SCC : 세기를 표시 S는 기원전(BC)

YEAR : 연도를 알파벳으로 spelling

YYYY : 4자리 연도로 표시

YY : 끝의 2자리 연도로 표시

MONTH : 월을 알파벳으로 spelling

MON : 월의 알파벳 약어

MM : 월을 2자리 숫자로 표시

DAY : 일에 해당하는 요일

DY : 일에 해당하는 요일의 약어

DDD,DD,D : 연도,월,일 중의 날짜를 숫자로 표시

HH , HH24 : (1-12) , (0-23)중의 시간을 표시

MI : 분을 표시

SS : 초를 표시

AM(A.M.),PM(P.M.) : 오전인지 오후인지를 표시

 

TO_CHAR(문자값,'형식')

숫자를 문자로 변환

: TO_CHAR(350000,'$999,999')→ $350,000

 

숫자를 날짜로 변환

: TO_CHAR(SYSDATE,'YY/MM/DD')→ 95/05/25

TO_DATE(문자값, '형식') : TO_DATE('10 SEPTEMBER 1992','DD MONTH YYYY')→10-SEP-92

TO_NUMBER(문자값) : TO_NUMBER('1234')→ 1234

 

- DECODE 함수

DECODE 함수는 값을 비교하여 해당하는 값을 돌려주는 함수

> DECODE (형식,비교값1,결과치1,비교값2,결과치2,...기본치 )

형식 : 컬럼이나 값

비교값1 : 형식이 비교값1에 맞는지를 비교

결과값1 : 형식이 비교값1에 맞을 때 갖는 값

기본치 : 형식이 비교값1,2,...에 맞지 않을 때 가지는 값

생략될 수 있으며, 생략되면 NULL이다.

 

EX)

SQL> SELECT name,title,DECODE(SUBSTR(title,-2,2),

2 '부장',salary*1.1,

3 '과장',salary*1.07,

4 '사원',salary*1.05,

5 salary) 이번달급여

6 FROM s_emp

7 ORDER BY 3 DESC ;

 

* 다중행 함수

- 그룹함수

COUNT( a ) : a의 행의 개수를 구함

AVG( a ) : a의 평균을 구함

SUM( a ) : a의 합계를 구함

MIN( a ) : a의 최소값을 구함

MAX( a ) : a의 최대값을 구함

STDDEV( a ) : a의 표준 편차를 구함

VARIANCE( a ) : a의 분산을 구함

 

COUNT(*)를 제외한 모든 그룹함수는 NULL값을 고려하지 않습니다.

중복값을 제거하고 싶은 경우는 a의 앞에 DISTINCT를 기술합니다.

MAX , MIN , COUNT를 제외한 그룹함수는 숫자타입의 데이터에만 가능합니다

 

* JOIN

- EQUIJOIN

컬럼에 있는 값들이 정확하게 일치하는 경우에 =연산자를 사용하여 JOIN하는 방법을 말합니다.

WHERE 절에서 JOIN조건을 기술하도록 합니다.

 

SELECT 테이블명.컬럼명, 테이블명.컬럼명, ...

FROM 테이블1, 테이블2

WHERE 테이블1.컬럼1 = 테이블2.컬럼2 ;

 

EX)

SQL> SELECT s_emp.name, s_emp.dept_id , s_dept.name

2 FROM s_emp , s_dept

3 WHERE s_emp.dept_id = s_dept.id ;

SQL> SELECT e.name 사원명, e.dept_id , d.name 부서명

2 FROM s_emp e, s_dept d

3 WHERE e.dept_id = d.id ;

SQL> SELECT e.name 사원명, d.name 부서명

2 FROM s_emp e, s_dept d , s_region r

3 WHERE e.dept_id = d.id

4 AND d.region_id = r.id

5 AND r.name LIKE '%서울%' ;

 

- NON-EQUIJOIN

Non-Eqijoin이란 한 칼럼의 값이 다른 칼럼의 값과 정확히 일치하지 않는 경우에

=연산자외의 다른 연산자를 사용하여 JOIN하는 방법을 말합니다

 

SQL> SELECT e.name, e.salary , g.grade 급여등급

2 FROM s_emp e, salgrade g

3 WHERE e.salary BETWEEN g.losal AND g.hisal ;

 

- OUTER JOIN

Outer join이란 JOIN조건을 만족하지 않는 경우에도 모든 행들을 다 보고자하는 경우에 JOIN하는 방법

SQL> SELECT e.name 사원명 ,e.id,c.name 고객명

2 FROM s_emp e, s_customer c

3 WHERE e.id (+) = c.sales_rep_id

4 ORDER BY 2;

 

- SELF JOIN

Self join이란 한 테이블의 행을 같은 테이블에 있는 행과 연결하는 방법으로 같은

테이블을 마치 두개의 테이블인 것처럼 사용하여 JOIN하는 방법을

SQL> SELECT w.id 사번, w.name 사원명 ,

2 m.id 부서장사번, m.name 부서장명

3 FROM s_emp w, s_emp m

4 WHERE w.manager_id = m.id ;

 

- SET 연산자의 활용

UNION : 각 QUERY결과의 합집합

UNION ALL : 각 QUERY결과의 합집합에 공통부분을 더함

INTERSECT : 각 QUERY결과의 교집합

MINUS : 첫번째 QUERY결과와 두번째 QUERY결과의 차집합

 

SELECT 칼럼1, 칼럼2 . . .

FROM 테이블1 . . .

SET 연산자

SELECT 칼럼1`, 칼럼2` . . .

FROM 테이블2 . . .

ORDER BY ;

 

SQL> SELECT name , dept_id , title

2 FROM s_emp

3 WHERE dept_id = 110

4 UNION

5 SELECT name , dept_id , title

6 FROM s_emp

7 WHERE dept_id = 113

8 ORDER BY 1 ;

 

* SUBQUERY

- SUBQUERY의 문형

 

SELECT 검색할 컬럼들

FROM 테이블명

WHERE 형식 연산자 (SELECT 검색할 컬럼들

FROM 테이블명

. . . );

 

SUBQUERY는 괄호로 묶여 있어야 합니다.

SUBQUERY구문에서는 ORDER BY절을 포함할 수 없습니다.

SUBQUERY는 연산자의 오른쪽에 나타나야 합니다.

SUBQUERY에서 사용할 수 있는 연산자의 종류에는

- 단일행 연산자(=, >, >=, <, <=, <>)

- 복수행 연산자 (IN, NOT IN)가 있습니다.

 

SUBQUERY를 사용할 수 있는 절의 종류

WHERE 절

HAVING절

UPDATE절

INSERT구문의 INTO절

UPDATE구문의 SET절

SELECT나 DELETE의 FROM절

 

- SINGLE ROW SUBQUERY

SUBQUERY에서 Main Query로 전달되는 행이 단 하나인 경우

이런 경우는 단일 행 연산자를 사용합니다

SQL> SELECT name, title , dept_id

2 FROM s_emp

3 WHERE dept_id = 김정미가 근무하는 부서;

SQL> SELECT dept_id

2 FROM s_emp

3 WHERE name = '김정미';

SQL> SELECT name, title , dept_id

2 FROM s_emp

3 WHERE dept_id = (SELECT dept_id

4 FROM s_emp

5 WHERE name = '김정미') ;

SQL> SELECT name, salary ,title

2 FROM s_emp

3 WHERE title = (SELECT title

4 FROM s_emp

5 WHERE name = '최정선')

6 ORDER BY salary ;

 

- MULTI ROW SUBQUERY

SUBQUERY에서 Main Query로 전달되는 행이 여러 개인 경우를 말합니다.

이런 경우는 다중 행 연산자를 사용합니다.

SUBQUERY에서 넘어오는 행이 여러 개이므로, 이때 사용되는 연산자는 IN임을 주의하세요.

SQL> SELECT name, dept_id

2 FROM s_emp

3 WHERE dept_id IN (SELECT id

4 FROM s_dept

5 WHERE region_id =3 ) ;

SQL> SELECT name , dept_id

2 FROM s_emp

3 WHERE dept_id IN

4 (SELECT id

5 FROM s_dept

6 WHERE region_id =

7 (SELECT id

8 FROM s_region

9 WHERE name = '서울특별시') ) ;

 

- MULTI COLUMN SUBQUERY

SUBQUERY구문을 작성할 때 WHERE절에서 비교하는 컬럼이 하나가 아니라

여러개의 컬럼을 동시에 비교하는 경우를 말하며, 이런 경우를 Pair-wise되었다고 합니다.

 

- Non-Pairwise SUBQUERY

SQL> SELECT name, dept_id, salary

2 FROM s_emp

3 WHERE salary IN (SELECT MIN(salary)

4 FROM s_emp

5 GROUP BY dept_id );

 

Pairwise SUBQUERY

SQL> SELECT name, dept_id, salary

2 FROM s_emp

3 WHERE (salary,dept_id) IN

4 (SELECT MIN(salary),dept_id

5 FROM s_emp

6 GROUP BY dept_id );

 

- FROM절에서의 SUBQUERY

한 테이블에 데이터 양이 많은 경우에는 FROM절에 테이블 전체를 기술하여

사용하면 효율이 떨어질 수 있으므로 이런 경우에는 필요한 행과 열만을

선택하여 FROM절에 SUBQUERY로 기술함으로써 효율적인 데이터 검색을 할 수 있습니다.

SQL> SELECT e.name , e.title , d.name

2 FROM (SELECT name ,title , dept_id

3 FROM s_emp

4 WHERE title = '사원') e , s_dept d

5 WHERE e.dept_id = d.id ;

 

- HAVING절에서의 SUBQUERY

일반적인 조건은 WHERE절에서 기술하지만, GROUP에 대한 조건은 HAVING절에서 기술합니다.

이 때 HAVING의 조건에 기술할 값이 주어져 있지 않은 경우에 모르는 값에 대한 데이터를

검색하기 위하여 SUBQUERY를 사용할 수 있습니다

SQL> SELECT dept_id , AVG(salary)

2 FROM s_emp

3 GROUP BY dept_id

4 HAVING AVG(salary) > (SELECT AVG(salary)

5 FROM s_emp

6 WHERE dept_id = 113) ;

 

- CORRELATED SUBQUERY

Outer Query의 candidate row가 더 이상 남지 않을때까지 반복됩니다.

CORRELATED SUBQUERY인 경우는 Outer Query의 각 행에 대해서 Inner Query가 매번 수행됩니다.

 

SQL> SELECT name, salary ,dept_id

2 FROM s_emp outer

3 where salary < (SELECT AVG(salary)

4 FROM s_emp

5 WHERE dept_id = outer.dept_id) ;

 

바로 2번째 LINE의 OUTER라는 테이블 ALLAS를 5번 LINE에서 사용하게 되면

내부적으로 CORRELATE SUBQUERY의 진행방식을 따르게 됩니다.

Posted by redkite
, |
인덱스 생성: Syntax
하나 또는 하나 이상의 Column에 인덱스를 생성

CREATE INDEX 인덱스
ON 테이블(Column[,Column]...);


♠예 :S_EMP테이블의 LAST_NAME Column에 대한 질의 액세스 속도를 빠르게 하기 위한 인덱스를 만드시오.

  SQL>CREATE INDEX s_emp_last_name_idx
2 ON s_emp(last_name);

Index created.



인덱스 생성:Guideline

  1. 인덱스를 만드는 때
  WHERE절이나 조인 조건에서 Column을 자주 이용할 때
  Column이 넓은 범위의 값을 가질때
  많은 NULL 값을 갖는 Column일 때
  테이블의 Data가 많고 그 테이블에서 Query되는 행의 수가 전체의 10-15%정도 일때

 2. 인덱스를 만들지 않아야 할 때
  테이블이 작을때
  Column이 질의의 조건으로 사용되는 경우가 별로 없을 때
  대부분의 질의가 행의 10-15% 이상을 검색한다고 예상될때
  테이블이 자주 변경될때

인덱스 확인
USER_INDEXES Dictionary 뷰는 인덱스의 이름과 Unique 여부를 가지고 있다.
USER_IND_COLUMNS 뷰는 인덱스 명, 테이블 명과 Column 명을 가지고 있다.

SQL> SELECT ic.index_name, ic.column_name
2 ic.column_position, ix.uniqueness
3 FROM user_indexes ix, user_ind_columns ic
4 WHERE ic.index_name = ix.index_name
5 AND table_name = 'S_EMP';


인덱스 확인
USER_INDEXES Dictionary 뷰에 인덱스가 있는지 확인하시오.
USER_IND_COLUMNS 뷰를 Query 하여 인덱스를 갖고 있는 Column을 확인할 수도 있다.
♠ 질의 예제 :S_EMP 테이블에서 이미 생성된 인덱스, 관련된 Column 명, Unique 여부를 Display 하라.


SQL> SELECT ic.index_name, ic.column_name
2 ic.column_position, ix.uniqueness
3 FROM user_indexes ix, user_ind_columns ic
4 WHERE ic.index_name = ix.index_name
5 AND table_name = 'S_EMP';

인덱스 삭제
인덱스를 삭제합니다.
SQL> DROP INDEX s_emp_list_name_idx;
Index dropped.

인덱스를 삭제하려면 그 인덱스의 소유자이거나 DROP ANY INDEX 권한을 가지고 있어야 한다.


Syntax
인덱스를 수정할 수는 없다.
인덱스를 변경하려면 삭제한 다음 다시 만들어야 한다.
INDEX 명령을 써서 인덱스를 삭제하라.
인덱스를 삭제하려면 그 인덱스의 소유자이거나 DROP ANY INDEX 권한을 가지고 있어야 한다.
DROP INDEX 인덱스;



CREATE INDEX IDX_ETL_LOG_ID ON ps_mom.etl_job_log_tbl(LOG_ID); -- PS_MOM 에 인덱스 추가(2010.12.03)

--CREATE INDEX IDX_RACLIENT ON RACLIENT(CERTI_CODE,STATUS_FLAG) --ONLINE; -- 국민 RA_CLIENT 테스트 인덱스 추가(2010.12.03)

 

Posted by redkite
, |

### 컨트롤 파일 ####

   
   
   
   
  1. 컨트롤 파일 미러링
    1) spfile의 경우
    shutdown immediate; -- DB서버를 정지
    alter system set controlfiles = '/data/controlfile1.ctl', '/data/controlfile2.ctl' scope=spfile; -- 파일 추가
    cp /data/controlfile1.ctl /data/controlfile2.ctl ## OS에서 파일 복사
    startup
    2) pfile의 경우
    shutdown immediate; -- DB서버 정지
    vi /data/admin/pfileSID.ora 파일에 컨트롤 파일 추가
    cp /data/controlfile1.ctl /data/controlfile2.ctl ## OS에서 파일 복사
    startup

  1. 컨트롤 파일 복구
    SQL> select spid, name from v$process, v$bgprocess where paddr(+) = addr; -- 프로세스 확인
    SQL> show parameter user_dump_dest

    NAME TYPE VALUE
    ------------------------------------ ----------- ------------------------------
    user_dump_dest string /data/oracle/app/oracle/admin/emsdb/udump -- 해당 디렉토리에는 컨트롤 파일을 재생성할 수 있는 스크립트가 저장되어 있음.
    SQL > shutdown immediate;
    cd /data/oracle/app/oracle/admin/emsdb/udump/
    grep controlfile *.trc ## 해당 파일 찾은 후
    cp -p SID_ora_PID.trc controlfile.sql ## 파일 변경 후
    sqlplus "/as sysdba"
    SQL > @controlfile.sql -- 실행 하면 컨트롤 파일 및 아카이브 파일이 생성 된다. 일부 에러 발생 가능성 있음.

### 리두로그 파일 ###

  1. 리두 로그 파일 미러링
    SQL > select * from v$logfile; -- 로그 파일 확인
    SQL > select * from v$log; -- 현재 사용 중인 로그 파일 확인 및 MEMBERS 의 수가 1만 있을 경우 미러링이 안되어 있는 것임
    SQL > alter database add logfile group 2 '/data/redo/redolog2_1.log' size 500M; -- 그룹 생성
    SQL > alter database add logfile member '/data/redo/redolog2_2.log' to group 2; -- 2그룹에 대한 추가 파일 생성

### 아카이브 모드 확인 ###

SQL> archive log list
Database log mode Archive Mode
Automatic archival Enabled
Archive destination /data/archivelog
Oldest online log sequence 748
Next log sequence to archive 750
Current log sequence 750

SQL> archive log list
Database log mode Archive Mode
Automatic archival Enabled
Archive destination /data/archivelog
Oldest online log sequence 748
Next log sequence to archive 750
Current log sequence 750

SQL> select group#, sequence#, archived, status from v$log;

GROUP# SEQUENCE# ARC STATUS
---------- ---------- --- ----------------
1 748 YES INACTIVE
2 749 YES INACTIVE
3 750 NO CURRENT
4 595 YES INACTIVE
5 596 YES INACTIVE
6 597 NO CURRENT

6 rows selected.


SQL> select archiver from v$instance;

ARCHIVE
-------
STARTED


### 오프라인 백업(노아카이브 모드) ###

  1. 주의 할 점
    오프라인 백업 시에는 정상적인 방법으로 종료(normal, immediate, transactional) 해야 한다. abort 종료의 경우 메모리 상의 할당된 내용도 즉시 종료 하고 데이터 베이스를 종료하기 때문에 나중에 스타트업 시에 복구 작업을 수행하게 된다. 이때 수행하는 프로세스는 SMON이다.
  2. 백업 받을 파일은 컨트롤 파일, 데이터 파일, 리두로그 파일, 파라메터 파일 전부를 같은 시점에 백업 받아야 한다.
    한번에 같이 받지 않으면 복구 시점이 틀어지게 된다. 이유는 컨트롤 파일의 SCN 번호 부여가 바뀌기 때문이다.
  3. 백업 전 확인 사항
    SQL > select TABLESPACE_NAME, FILE_NAME from dba_data_files; -- 데이터 파일의 구조 분석
    SQL > select GROUP#, MEMBER from v$logfile; -- 리두로그 파일의 구조 분석
    SQL > select * from v$confile; -- 컨트롤 파일의 구조 분석
    SQL > host edit /data/oracle/products/pfile/initSID.ora -- 파라메터 파일 구조 분석

    ## 오라클 DB 정상적인지 확인SQL > host edit moredept.sql
    alter system switch logfile;
    insert into scott.dept values(1,'Personnen','Pusan');
    insert into scott.dept values(2,'Personnen','Pusan');
    insert into scott.dept values(3,'Personnen','Pusan');
    alter system switch logfile;
    insert into scott.dept values(4,'Personnen','Pusan');
    insert into scott.dept values(5,'Personnen','Pusan');
    insert into scott.dept values(6,'Personnen','Pusan');
    alter system switch logfile;
    insert into scott.dept values(7,'Personnen','Pusan');
    insert into scott.dept values(8,'Personnen','Pusan');
    insert into scott.dept values(9,'Personnen','Pusan');
    commit;
    select count(*) from scott.dept
    SQL > @moredept

  4. 특정 파일이 삭제되어 데이터 베이스 OPEN이 안될 경우
    startup -- 에러 발생될 경우 해당 파일을 아래의 명령어로 변경 후 open 시도 ## 컨트롤 파일의 파일경로 수정을 해주는 단계임.
    alter database rename file '/data/users01.dbf' to '/data/oradata/users01.dbf';
    alter database open;

### 아카이브 모드 백업-복구 ###

  1. 아카이브 모드 변경 작업
    1) initSID.ora 파일에 아래의 내용을 넣는다.
    LOG_ARCHIVE_START = TRUE
    LOG_ARCHIVE_DEST = [archivefile의 경로와 파일명]
    LOG_ARCHIVE_DEST_n = [archivefile의 경로와 파일명] ## DB_RECOVERY_FILE_DEST 파라메터를 정의하면 안된다.(해당 경로는 10g에서 플래시백에서 사용함)
    LOG_ARCHIVE_FORMAT = [format type].[확장자] ## sample [%r_%s.arc]
    ## [%s]아카이브의 일련번호 : 1, 2, 3 ... [%S] 아카이브 파일의 일련번호를 0으로 채워줌 00001, 00002, 00003 ...
    ## [%t]데이터 베이스의 인스턴스를 구분해서 표시해줌 [%T] 001, 002, 003...
    ## [%r]재시작된 후 아카이브 파일의 혼동을 줄이기 위해 RESETLOG ID 값을 구분하기 위한 것임.alter database open resetlogs명령어에 의해..(10g부터 적용됨)
    DB_RECOVERY_FILE_DEST ="
    2) 아카이브 모드 변경
    startup mount
    alter database archivelog;
    alter database open;
  2. 아카이브 모드 복구 절차(전체 복구 방법)
    1) FULL 백업 된 파일들의 백업 시점이 일치하는지 확인.
    2) 아카이브 모드로 운영중인지 확인.
    3) 최종 FULL 백업된 이후의 아카이브 로그 파일이 있는지 확인.
    4) 최종 리두로그 파일이 존재하는지 확인.(select * v$log;) -- 마운트 단계까지 들어간다.
    5) 장애가 발생한 데이터 파일 확인.(select * v$recover_file; select file_id, file_name from dba_data_files;) 에러가 발생한 DBF파일을 복사해 놓는다.
    6) 데이터 베이스 STARTUP
    7) recover database;
    8) auto
    9) alter database open
  3. 아카이브 모드 복구 절차(테이블 스페이스 완전 복구 방법)
    1) 오픈단계에서 장애발생 테이블스페이스 기준으로 복구한다.
    2) 오프라인 백업 데이터의 생성일자를 확인한다.
    3) 아카이브 모드로 운영중인지의 여부 확인한다.
    4) DB shutdown 후에 해당 테이블 스페이스의 데이터 파일을 복사한다.
    5) DB startup 한다. 기동 시에 해당 데이터 파일의 시점 불일치 에러 메시지가 발생한다.(ORA-01113, ORA-01110)
    6) alter database datafle 'OOOO.DBF' offline ;
    7) ALTER DATABASE OPEN; -- 을 실행하여 정상적으로 OPEN 시도.
    8) ALTER TABLESPACE OOOO OFFLINE IMMEDIATE; -- 해당 테이블 스페이스는 ONLINE상태로 OFFLINE으로 변경해줘야 한다.
    9) RECOVER TABLESPACE OOOO;
  4. 아카이브 모드 복구 절차(데이터파일 완전 복구 방법)
    1) 오픈단계에서 장애발생 데이터 파일기준으로 복구한다.
    2) 오프라인 백업 데이터의 생성일자를 확인한다.
    3) 아카이브 모드로 운영중인지의 여부 확인한다.
    4) DB shutdown 후에 해당 데이터 파일을 복사한다.
    5) DB startup 한다. 기동 시에 해당 데이터 파일의 시점 불일치 에러 메시지가 발생한다.(ORA-01113, ORA-01110)
    6) alter database datafle 'OOOO.DBF' offline IMMEDIATE;
    7) ALTER DATABASE OPEN; -- 을 실행하여 정상적으로 OPEN 시도.
    8) RECOVER DATAFILE 'OOOO.DBF';
    9) AUTO
  5. 아카이브 모드 복구 절차(read-only 테이블 복구)
    1) 백업 파일 복사
    2) startup mount -- DB를 마운트 단계까지 간다.
    3) recover database
    4) alter database open;
    5) alter tablespace TABLESPACE_NAME read only;
  6. 패러럴 복구 절차

    1) initSID.ora 파일 관련 파라메터 수정(Parallel_min_servers=2 / Parallel_max_servers=4 / Recovery_parallel_servers =4)
    2) select name from v$bgprocess; (P000, P001 등 프로세스가 수행됨)
    3) recover database parallel(degree 4)

  7. 시간기반 불완전 복구 방법
    1) DROP 된 테이블을 DROP 시키기 전으로 복구
    2) 로그마이너 패키지로 확인 가능



    3) 백업된 모든 데이터 파일 복사
    ** 주의 **
    장애가 발생한 데이터 파일만 복사하여 아카이브 파일들을 순차적으로 적용하게 되면 복구 작업이 완료되었지만, 불완전 복구 방법에서는
    특정 파일만 재 설치해서는 모든 데이터를 과거 특정시점으로 되돌릴 수 없기 때문에 반드시 모든 데이터를 과거 시점으로 복구 해야 함.
    불완전 복구 작업을 수행할 때 가장 중요한 포인트 중에 하나는 마지막 오프라인 백업된 모든 데이터 파일들을 현재
    경로로 복사 해야 한다는 것임.
    이때, 마지막 컨트롤 파일이나 리두로그 파일들은 복사할 필요는 없으며, 데이터 파일이 깨진 것이므로 모든 데이터 파일들만 복사 해야 함.
    4) STARTUP MOUNT
    5) SET AUTORECOVERY ON
    6) RECOVER DATABASE UNTIL TIME '2011-07-12-12:10:10'; ## 시점 복구
    7) ALTER DATABASE OPEN; ## 해당 명령을 실행하면 아래와 같은 에러 메시지 발생.
    ORA- Can not open Database; Please Open Database with resetlog option
    8) ALTER DATABASE OPEN RESETLOGS; ## SCN과 모든 로그 파일이 새로 시작되는 것임
    archivce log list 로 확인 가능
    9) DROP 된 테이블 복구 확인 후 OFF-LINE 백업 꼭 수행해야 함!!!(## RESETLOGS로 로그파일이 초기화 되기 때문에 꼭 백업 해야 함)
  8. 취소 기반 불완전 복구
    1) 복구 파일 복사 후 STARTUP MOUNT
    2) SET AUTORECOVERY ON
    3) RECOVER DATABASE UNTIL CANCEL; 과거 특정 시점까지 복구 완료
    ### 리두로그 파일 일부 삭제 시 복구

    ### 리두로그 파일 전체 삭제 시 복구



    ### 모든 컨트롤 파일이 삭제된 경우

    마지막 Current Redo log 파일을 지정해 주어야 함.
    ### 컨트롤 파일과 특정 datafile 삭제된 경우
  9. 변경기반 불완전 복구 방법
    1) RECOVER DATAABASE UNTIL CHANGE 80014;

6/2 일 SQL 튜닝 교육 5090912_workshop.zip5090914_labs.zip

  1. blocks 할당이 크고 avg_space의 크기가 크면 공간 낭비가 심한것임.
    SQL > select table_name, num_rows, blocks, avg_space, last_analyzed
    from user_tables
    where table_name like '%'
    SQL > save a1 -- 저장됨.
    SQL > get a1 -- 불러오기
    SQL > exec dbms_stats.gather_table_stats('sh','cust_test'); -- 통계정보 갱신
    SQL > exec dbms_stats.delete_table_stats('sh','sales_test'); -- 통계정보 삭제
  2. blevel 이 4level 로 떨어질 경우 공간 활용도가 떨어지고 있다는 것임.
    SQL > select index_name, num_rows, distinct_keys, leaf_blocks, blevel
    from user_indexes
    where table_name = 'sales_test'
  3. SQL TRACE
    SQL > alter session set tracefile_identifier = 'statement_trace';
    SQL > alter session set sql_trace=true;
    SQL > select max(cust_credit_limit) from customers
    where cust_city = ' Paris';
    SQL > alter session set sql_trace=false;
    #> tkprof orcl_ora_2364_statement_trace.trc run1.txt sys=no ## recursive SQL 문장 제외하라는 옵션(sys=no)
    SQL > create index cust_city_idx on customers(cust_city); -- index 생성 후 재실행해서 확인
  4. STATSPACK 생성 방법
    SQL > @%ORACLE_HOME%\rdbms\admin\spcreate
    perfstat_password의 값을 입력하십시오: pertstat
    pertstat


    Choose the Default tablespace for the PERFSTAT user
    ---------------------------------------------------
    Below is the list of online tablespaces in this database which can
    store user data. Specifying the SYSTEM tablespace for the user's
    default tablespace will result in the installation FAILING, as
    using SYSTEM for performance data is not supported.

    Choose the PERFSTAT users's default tablespace. This is the tablespac
    in which the STATSPACK tables and indexes will be created.

    TABLESPACE_NAME CONTENTS STATSPACK DEFAULT TABLESPACE
    ------------------------------ --------- ----------------------------
    EXAMPLE PERMANENT
    SYSAUX PERMANENT *
    USERS PERMANENT

    Pressing <return> will result in STATSPACK's recommended default
    tablespace (identified by *) being used.

    default_tablespace의 값을 입력하십시오: USERS

    Using tablespace USERS as PERFSTAT default tablespace.


    Choose the Temporary tablespace for the PERFSTAT user
    -----------------------------------------------------
    Below is the list of online tablespaces in this database which can
    store temporary data (e.g. for sort workareas). Specifying the SYSTEM
    tablespace for the user's temporary tablespace will result in the
    installation FAILING, as using SYSTEM for workareas is not supported.

    Choose the PERFSTAT user's Temporary tablespace.

    TABLESPACE_NAME CONTENTS DB DEFAULT TEMP TABLESPACE
    ------------------------------ --------- --------------------------
    TEMP TEMPORARY *

    Pressing <return> will result in the database's default Temporary
    tablespace (identified by *) being used.

    temporary_tablespace의 값을 입력하십시오: temp
    SQL > show user
    SQL > exec statspack.snap; -- 스냅샷 찍음.

  5. SQL Access Advisor TEST
    SQL > exec dbms_stats.gather_table_stats('sh','sales_test');
    SQL> select * from sales_test where cust_id = 100866;
    SQL> select * from sales_test1 where cust_id=100866;
    SQL> select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id
  6. Materialized View
    - JOIN하는 테이블들에 Mview 생성이 되면 summary 된 하나의 테이블 형식으로 조회가 되며, 사용자가 기존의 쿼리를 사용하여
    조회를 하더라도 Mview가 자동으로 자체 쿼리를 생성하여 응답속도를 빠르게 조회한다.
  7. leaf block 공간 낭비 확인
    SQL> select lf_rows_len, del_lf_rows_len, (del_lf_rows_len/lf_rows_len)*100 "Delete %" from index_stats
    SQL> update cust_test set cust_id=cust_id + 20000000
    where rownum <= 2000; -- 업데이트 후 확인작업
    SQL> analyze index cust_id_idx validate structure; -- 통계 정보 갱신 후 블럭 확인
    SQL> select lf_rows_len, del_lf_rows_len, (del_lf_rows_len/lf_rows_len)*100 "Delete %" from index_stats
    LF_ROWS_LEN DEL_LF_ROWS_LEN Delete %
    ----------- --------------- ----------
    911322 29881 3.27886301 <== %가 20% 이상이면 공간 활용도가 낮음으로 rebuild 필요함.

    1 개의 행이 선택되었습니다.
    SQL> alter index cust_id_idx rebuild;

  8. Unused Index 모니터링
    SQL> select 'alter index '||index_name||' monitoring usage;' from user_indexes;
    SQL> select table_name, index_name, monitoring, used from v$object_usage

    SQL> exec dbms_stats.gather_schema_stats('hr'); -- 통계정보 갱신 후 확인하게 되면 index가 사용된 걸로 확인된다.(안좋음ㅡㅡ;)

6/3일 SQL 튜닝 교육

  1. function based index
    SQL> create index func_first_name_idx on cust_test(upper(cust_first_name));
    SQL> select index_name, index_type, status from user_indexes
    where table_name = 'CUST_TEST';
    SQL> select index_name, column_name, column_position
    from user_ind_columns
    where table_name = 'CUST_TEST'
    order by 1, 3;
    SQL> select index_name, column_expression
    from user_ind_expressions
    where table_name = 'CUST_TEST';
  2. HINT
    - /*+ */ <== 힌트 포맷, 여러개의 힌트 사용시 한 포맷안에서 띄어쓰기로 작성.
  3. TRACE
    SQL> set autot traceonly explain
    SQL> select /*+ index(sales_test prod_time_idx) */ *
    from sales_test
    where prod_id=13
    and time_id between to_date('19980510', 'yyyymmdd')
    and to_date('19980522','yyyymmdd');
  4. Meterialized view
    SQL> create materialized view cust_sales_mv
    enable query rewrite
    as
    select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id;
    SQL> create materialized view cust_sales_mv1
    enable query rewrite
    as
    select c.cust_id, s.channel_id, sum(s.amount_sold)
    from customers c, sales s
    where c.cust_id = s.cust_id
    group by c.cust_id, s.channel_id;
    SQL> set autot traceonly explain
    SQL> alter materialized view cust_sales_mv disable query rewrite;
  5. Using DBMS_MVIEW Package
    declare
    task_nm varchar2(20) := 'emp_tune';
    begin
    dbms_advisor.tune_mview(task_name=>task_nm,
    mv_create_stmt=>'create materialized view emp_mv
    as
    select department_id, avg(salary)
    from employees
    group by department_id');
    end;
    /
  6. FLASHBACK
    - 9i 에서는 DML 에 대해 flashback query
    - 10g Database :

    . table --> Drop
    --> Table
    --> Version
    --> Transaction
    #### flashback transaction
    SQL> select to_char(sysdate, 'yyyy/mm/dd hh24:mi:ss') from dual;
    SQL> delete from dept where deptno=40;
    SQL> select * from dept as of timestamp
    to_timestamp('2011/06/03 15:46:07', 'yyyy/mm/dd hh24:mi:ss') -- 과거 특정 시간대로 돌아갈 경우
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> select * from dept as of timestamp
    systimestamp - interval '10' minute
    -- 과거 시간대로 돌아갈 경우
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> select * from dept as of timestamp
    sysdate - 10/1440
    -- 과거 시간대로 돌아갈 경우(10분/60분 환산 * 24)
    where deptno=40 -- 과거 시간대 40번 부서가 있었는지 확인
    SQL> show parameter undo
    undo_retention integer 900 -- 복구 가능한 최대 시간(900초)
    undo 공간이 부족할 경우 해당 과거 시간까지의 데이터를 보장 못함(젠장)
    SQL> show recyclebin -- 휴지통에서 확인(drop된 테이블 확인할 수 있음)
    ORIGINAL NAME RECYCLEBIN NAME OBJECT TYPE DROP TIME
    ---------------- ------------------------------ ------------ -------------------
    EMP_FLASH BIN$s/Vv2p9dSemiALQ05QJWuw==$0 TABLE 2011-06-03:16:09:14
    EMP_FLASH BIN$ahDZ8KZxQ2+26wiG+vjimA==$0 TABLE 2011-06-03:16:07:48
    EMP_FLASH BIN$aS6Q/kqETYa2NLqb7m+LHA==$0 TABLE 2011-06-03:16:06:36
    SQL> select * from "BIN$ahDZ8KZxQ2+26wiG+vjimA==$0"
    #### flashback drop
    SQL> flashback table emp_flash to before drop; -- drop 테이블 복원
    플래시백이 완료되었습니다.
    SQL> flashback table "BIN$aS6Q/kqETYa2NLqb7m+LHA==$0" to before drop; -- 특정 테이블 복구시
    플래시백이 완료되었습니다.
    SQL> flashback table "BIN$ahDZ8KZxQ2+26wiG+vjimA==$0" to before drop rename to emp_new; -- 테이블 이름을 변경 하여 복구도 가능
    플래시백이 완료되었습니다.
    #### flashback table
    16:24:37 SQL> insert into dept values(50,'New','CA');

    1 개의 행이 만들어졌습니다.

    16:25:07 SQL> commit;

    커밋이 완료되었습니다.

    16:25:36 SQL> update dept set loc = 'Test1' where deptno=10;

    1 행이 갱신되었습니다.

    16:25:51 SQL> commit;

    커밋이 완료되었습니다.

    16:25:54 SQL> select * from dept;

    DEPTNO DNAME LOC
    ---------- -------------- -------------
    50 New CA
    10 ACCOUNTING Test1
    20 RESEARCH DALLAS
    30 SALES CHICAGO
    16:27:59 SQL> alter table dept enable row movement; -- 테이블의 row 이동 가능 활성화
    16:28:07 SQL> flashback table dept to timestamp to_timestamp('2011/06/03 16:24:37', 'yyyy/mm/dd hh24:mi:ss'); -- 테이블 자체 rollback
    플래시백이 완료되었습니다.

Posted by redkite
, |

최근에 달린 댓글

최근에 받은 트랙백

글 보관함