Village For DreamChasers....


Undocumented HIT (잘못되어도 오라클에서 보장 하지 않음)
 
일반적으로 특정 테이블을 Update하기 위해서는 WHERE절에 EXISTS 또는 IN 등의 Sub-Query로 조인 조건을 만족하는
Row를 먼저 Check하고, 조건을 만족하는 Row에 대하여 SET 절에서 필요한 데이터를 검색하여 Update하는 것이 보통이다.
 
이 때, Update 해야 하는 Row가 많을 경우 WHERE절이나 SET절에서 테이블을 반복적으로 Random 액세스해야 하는 부담이
발생하므로 처리 범위가 넓은 Update문의 경우에는 'Updatable Join View'를 활용할 필요가 있다.
 
이 때, 조인되는 2개의 테이블은 반드시 1:1 또는 1:M의 관계여야 하며,
Update되는 컬럼의 테이블은 M쪽 집합이어야 한다.
이것은 1쪽 집합인 Parent table의 조인 컬럼이 UK 또는 PK로 설정되어 있어야 함을 의미한다. 
이 조건을 만족하지 못하는 Updatable Join View는 에러를 Return하며 실행되지 않는다.
(ORA-01779 cannot modify a column which maps to a non key-preserved table)
 
그러나, 일반적으로 View 또는 2개 이상의 테이블을 조인한 집합을 엑세스하는
경우가 많으므로 위의 UK나 PK Constraint를 설정하기 어려운 것이 현실이다.
 
따라서, 이러한 Constraint를 피해서 Updatable Join View를 사용할 수 있도록
BYPASS_UJVC 라는 힌트를 사용하여 튜닝할 수 있다.
 

 
-----------------------------
▣ TEST 1 환경
   Constraint :
   DETP.DEPTNO CONSTRAINT PK_DEPT PRIMARY KEY
   EMP.EMPNO CONSTRAINT PK_EMP PRIMARY KEY
   EMP.DEPTNO CONSTRAINT FK_DEPTNO REFERENCES DEPT
-----------------------------
 
▣ VIEW 생성
create or replace view empdept_v
as
select x.empno, x.ename, x.job, y.dname, y.deptno
from   emp x, dept y
where x.deptno = y.deptno;
 
View created.
 
▣ UPDATABLE JOIN VIEW 내용
SQL> select * from empdept_v;
 
     EMPNO ENAME      JOB       DNAME              DEPTNO
---------- ---------- --------- -------------- ----------
      7369 SMITH      CLERK     RESEARCH               20
      7499 ALLEN      SALESMAN SALES                  30
      7521 WARD       SALESMAN SALES                  30
      7566 JONES      MANAGER   RESEARCH               20
      7654 MARTIN     SALESMAN SALES                  30
      7698 BLAKE      MANAGER   SALES                  30
      7782 CLARK      MANAGER   ACCOUNTING             10
      7788 SCOTT      ANALYST   RESEARCH               20
      7839 KING       PRESIDENT ACCOUNTING             10
      7844 TURNER     SALESMAN SALES                  30
      7876 ADAMS      CLERK     RESEARCH               20
      7900 JAMES      CLERK     SALES                  30
      7902 FORD       ANALYST   RESEARCH               20
      7934 MILLER     CLERK     ACCOUNTING             10
 
14 rows selected.
 
▣ 1쪽 컬럼 갱신
update empdept_v
   set dname = 'AP_TUNNING'
 where empno = '7369';
 
ERROR at line 2:
ORA-01779: cannot modify a column which maps to a non key-preserved table
 
▣ 1쪽 컬럼 갱신 WITH bypass_ujvc HIT
update /*+ bypass_ujvc */
       empdept_v
   set dname = 'AP_TUNNING'
 where empno = '7369';
 
1 row updated.
 
 
▣ 변경 내역 확인
SQL> select * from dept;
 
    DEPTNO DNAME          LOC
---------- -------------- -------------
        10 ACCOUNTING     NEW YORK
        20 AP_TUNNING     DALLAS
        30 SALES          CHICAGO
        40 OPERATIONS     BOSTON
 
SQL> select * from empdept_v;
 
     EMPNO ENAME      JOB       DNAME              DEPTNO
---------- ---------- --------- -------------- ----------
      7369 SMITH      CLERK     AP_TUNNING             20
      7499 ALLEN      SALESMAN SALES                  30
      7521 WARD       SALESMAN SALES                  30
      7566 JONES      MANAGER   AP_TUNNING             20
      7654 MARTIN     SALESMAN SALES                  30
      7698 BLAKE      MANAGER   SALES                  30
      7782 CLARK      MANAGER   ACCOUNTING             10
      7788 SCOTT      ANALYST   AP_TUNNING             20
      7839 KING       PRESIDENT ACCOUNTING             10
      7844 TURNER     SALESMAN SALES                  30
      7876 ADAMS      CLERK     AP_TUNNING             20
      7900 JAMES      CLERK     SALES                  30
      7902 FORD       ANALYST   AP_TUNNING             20
      7934 MILLER     CLERK     ACCOUNTING             10
 
14 rows selected.
-----------------------------
▣ TEST 2 환경
   제약조건 : Constraint 없음.
-----------------------------
 
▣ 의미상 M쪽 집합을 갱신함.
update
(select b.dname, a.ename
   from emp a,
        dept b
 where a.deptno = b.deptno
    and a.empno = '7369')
set ename = 'KIMDOL';
 
ERROR at line 5:
ORA-01779: cannot modify a column which maps to a non key-preserved table
 
--> Constraint가 없으므로 oracle은 M쪽 집합인지 알지 못한다.
 
 
▣ 의미상 M쪽 집합을 갱신, With bypass_ujvc HIT
 
update /*+ bypass_ujvc */
(select b.dname, a.ename
   from emp a,
        dept b
 where a.deptno = b.deptno
      and a.empno = '7369')
set dname = 'KIMDOL';
 
1 row updated.

[출처] bypass_ujvc 힌트|작성자 리원아빠

저작자 표시 비영리 동일 조건 변경 허락
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰


SYSDBA 권한으로 로그인 한다.

 

<==     Execute Plan   ===>

1. 우선 실행계획을 저장할 PLAN_TABLE 필요하다.

%ORACLE_HOME%\ RDBMS\ADMIN \UTLXPLAN.SQL실행하면 생성된다.

2. PLAN_TABLE 권한을 설정한다.

Grant all on plan_table to public;

3. 실행

Explain Plan

  Set statement_id = ‘name‘ for

  SQL구문

4. 확인

%ORACLE_HOME%\ RDBMS\ADMIN\UTLXPLS.SQL

 

 

<==     AUTOTRACE   ===>

1. %ORACLE_HOME%\sqlplus\admin\plustrce.sql 실행한다.

2. PLUSTRACE 롤의 권한을 설정한다.

Grant PLUSTRCE to public;

PLUSTRACE 롤이 부여되면 이를 사용하기 전에

PLAN_TABLE 해당 유저 스키마에 설치되었는지 확인해야한다.

3. 실행

Set autotrace on;

Set autotrace traceonly

SQL 구문

Set autotrace off;

 

set autotrace on

set autotrace traceonly : 성능통계정보와 실행계획만

set autotrace  explain : 쿼리 결과와 실행계획만

set autotrace  statistics : 쿼리 결과와 성능통계정보만

set autotrace  traceonly explain : 실행계획만

set autotrace  traceonly statistics : 성능통계정보만

 


<==     SQL_TRACE   ===>

어플리케이션에서 실행하는 모든 SQL 대한 실행내용, 성능통계, 실행계획 등을 저장하는데 사용

출력내용이 많을 경우 성능에 영향을 미치므로 세션별로 설정하는 것이 바람직하다.

1. 설정

init.org파일

      sql_trace=true

Session

    Alter Session Set sql_trace=true;

System

    Alter System Set sql_trace=true;

2. Trace파일 위치

Init.ora파일에sql_trace=true 설정한 경우

Init.ora user_dump_dest 설정된 위치에

  전용서버의 경우

    user_dump_dest

  공유서버의 경우

    background_dump_dest

3. init.ora파일의 max_dump_file_size

  일반적으로 50M~100M정도로 설정한다.

  K, M 붙이면 킬로바이트 메가바이트를 의미한다.

  UNLIMITED 제한없음

  세션에서 변경하고자

    Alter Session Set max_dump_file_size = ’100M’

4. SQL_TRACE 종류

Alter Sesstion Set SQL_TRACE = true

    현재 세션만 TRACE 모드

  SYS.DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION

    데이터베이스 내의 모든 세션에 대해 TRACE 모드 사용여부 제어

  Alter Session Set Events

  Alter Sesstion Set SQL_TRACE = true 실행하는 이벤트를 만들어 사용하는 방법

Set Event 오라클에 의해 정식으로 지원되는 방법은 아니지만 널리 사용된다.

추적정보와 바인드 변수 정보 또한 얻을 있다는 장점이 있다.

    사용법

      Alter Session Set Events ‘10046 trace name context forever, level <n>’;

      Alter Session Set Events ‘10046 trace name context off’;

      N = 1 : 표준SQL TRACE 기능을 사용한다.

      N = 4 : 표준SQL TRACE 기능을 사용하고 바인드 변수 정보를 수집한다.

      N = 8 : 표준SQL TRACE 기능을 사용하고 쿼리 수준의 대기 이벤트 정보를 수집한다.

      N = 12 : 표준SQL TRACE 기능을 사용하고
바인드 변수 정보와 쿼리 수준의 대기 이벤트 정보를 수집한다.

 

 

<==     TIMED_STATISTICS   ===>

단계가 어느 정도의 시간을 필요로하는지 알아보고자 사용

디폴트 TRUE 설정되어 있다.

1. 설정

  Init.ora 파일

    timed_statistics=true

  Session

    Alter Session set time_statistics=true

  System

    Alter System set time_statistics=true

2.

 

<==     TKPROF   ===>

TRACE 파일을 보는 사용

DBA권한이 있어야 읽을 있다.

Init.ora 파일의 _trace_files_public=true

( 파라미터는 오라클이 정식으로 지원하는 파라미터는 아니다.)

1. Trace 모드에서 쿼리 실행

  Show Parameter timed_statistics;

  Alter Session Set sql_trace =true;

  쿼리 실행

2. 추적파일 이름을 얻기 위해 쿼리 실행

  V$ 테이블로 부터 정보를 얻는 것으로

C.VALUE 오라클이 추적 파일을 만드는데 사용하는 디렉토리

  A.SPID 유일한 세션 식별자에 해당한다.

 

Select

C.VALUE || ‘ORA’ || to_char(A.SPID, ‘fm00000’) || ‘.trc’

From

  V$Process a, V$Session b, V$Parameter c

Where

  a.addr = b.paddr

  and b.audsid = userenv(‘sessionid’)

  and c.name = ‘user_dump_dest’

 

추적파일은 서버내에 만들어진다.

3. 파일 읽기

TKPROF  ora00892.trc  report.txt

4. 유심히 봐야할 내용

Execute count 1 보다 크고 execute count 대한 parse count 비율이 높은 경우

거의 모든 execute count 1 경우

CPU 시간과 Elapsed 시간에 차이가

CPU 또는 slapsed 시간이 너무 경우

(fatch count) / (얻어낸 행수) 비율이 너무 경우

Disk count 너무 높은 경우

Query current count 너무 높은 경우

Misses in library cache
저작자 표시 비영리
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰
TAG plan

ROWNUM의 동작 원리와 활용 방법
저자 - Tom Kyte

오라클 전문가 Tom Kyte가 ROWNUM의 동작 원리와 활용 방법에 대해 설명합니다.

이번 호의 Ask Tom 컬럼은 지금까지와는 조금 다른 내용을 담고 있습니다. 필자는 오라클 데이터베이스에서 Top-N 쿼리와 페이지네이션(pagination) 쿼리를 구현하는 방법에 대해 자주 질문을 받곤 합니다. 하나의 컬럼을 통해 이러한 질문에 한꺼번에 대답하기 위한 방편으로, < Effective Oracle by Design (Oracle Press, 2003)> 의 내용을 인용하기로 했습니다. 컬럼의 포맷에 맞게 책의 내용이 다소 수정되었음을 참고하시기 바랍니다.

결과 셋의 제한

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

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

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

ROWNUM의 동작 원리

ROWNUM은 쿼리 내에서 사용 가능한 (실제 컬럼이 아닌) 가상 컬럼(pseudocolumn)입니다. ROWNUM에는 숫자 1, 2, 3, 4, ... N의 값이 할당됩니다. 여기서 N 은 ROWNUM과 함께 사용하는 로우의 수를 의미합니다. 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 = 1
for x in
( select * from emp )
loop
exit when NOT(ROWNUM <= 5)
OUTPUT record to temp
ROWNUM = ROWNUM+1
end loop
SORT 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 t
as
select dbms_random.value(1,1000000)
id,
rpad('*',40,'*' ) data
from dual
connect by level <= 100000;

begin
dbms_stats.gather_table_stats
( user, 'T');
end;
/

Now enable tracing, via

exec
dbms_monitor.session_trace_enable
(waits=>true);

And then run your top-N query with ROWNUM:

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

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

declare
cursor c is
select *
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 <= 10

call count cpu elapsed disk query current rows
-------- -------- ------- ------- ------- -------- -------- ------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.04 0.04 0 949 0 10
-------- -------- ------- ------- ------- -------- -------- ------
total 4 0.04 0.04 0 949 0 10

Rows 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 ID
call count cpu elapsed disk query current rows
-------- -------- ------- ------- ------- -------- -------- ------
Parse 1 0.00 0.00 0 0 0 0
Execute 2 0.00 0.00 0 0 0 0
Fetch 10 0.35 0.40 155 949 6 10
-------- -------- ------- ------- ------- -------- -------- ------
total 13 0.36 0.40 155 949 6 10

Rows 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 33
direct 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;

where

여기서,

  • 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 148
0 64 149
0 53 150

SQL>
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 148
0 38 149
0 64 150
0 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 148
0 99 149
0 41 150

SQL>
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 148
0 99 149
0 41 150
0 45 151
이제 쿼리를 반복 실행해도 동일한 결과를 보장할 수 있게 되었습니다. ROWID는 테이블 내에서 유니크한 값을 가집니다. 따라서 ORDER BY ID 조건과 ORDER BY ROWID 기준을 함께 사용함으로써 사용자가 기대한 순서대로 페이지네이션 쿼리의 결과를 확인할 수 있습니다.

원문 : http://www.oracle.com/technology/global/kr/oramag/oracle/06-sep/o56asktom.html


저작자 표시 비영리
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰
TAG rownum

1. OCP License 시험 완료 /11월중 ~ / 12월 1일 Pass
2. 책 3권 읽기(판타지, 전공서적 제외)  /  완료
3. 1박2일로 여행 다녀오기 => 12월중 다시 계획~
4. 대용량 데이타 베이스 구입 및 계획만큼 독파하기  / 미구입
5. Toeic 시험 일정 정리하기. / 1월 일정 예약
6. Diet 및 운동 꾸준히 하기
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰

i n v i t a t i o n

티스토리 초대장

+ 남은 초대장 수 : 0
서식을 불러와서 쓰기는 하지만 서식이 맘에 들진 않네요 ㅋ
제목과 같이 초대장 10장  배포 합니다.
아래 메일 주소 안적어 주신 1분 제외하고 1장 남았습니다.
배포 완료했습니다.

배포 시간은 당일 18시를 기점으로 배포 합니다.      확인되는대로 초대합니다.
단, 배포 수량이 10장 1장 이기 때문에 확실하게 선착순으로 드리겠지만,
소심하고 까탈스러운 주인장 맘대로 아래 조건을 만족하시는 분, 그리고 앞으로 충족 시켜주실분 에 한해 1~2장은 더 배포가 가능합니다. (보유수량이 10장인건 아니란 소리지요)

1. 블로그 메인 테마를 지정해 주세요
  - 소소한 일상도 좋고, 잡담도 좋습니다. 하지만 아무런 생각이 없이 시작한 블로그는
1달이 지나기 전에 접고 맙니다. 그런분들 보다 좀더 애정을 가지고 지속적으로 하실 분에게 드리는게 더 좋을것 같네요 ^^

2. 다른 블로그에 초대장 요청 하신분은 남기지 말아 주세요.
  - 초대장을 달라고 하셔서 배포해 드릴려고 해도 , 중복이 되면 초대장이 가지 않습니다. 그렇게 되면 이후에 정말 원하시는 분이 있으셔도 댓글을 안달게 되어 그런분들을 초대해 드릴수 없게 됩니다.

3. 기존에 운영하시던 블로그가 있으시면 주소를 적어주세요. (없으시거나 새로 시작하실분은 없으시다고만 코멘트 달아 주시면 됩니다. )
 - 왠만하면 다 드리긴 하지만 스팸이나 광고용으로 사용하실분은 가급적 드리고 싶지 않습니다.

4. 댓글 비밀댓글로 적어시되 반드시 위의 내용이 포함되어 있어야 합니다.
  - 초대장 하나 가지고 왜이리 유세냐.. 까탈스럽다 라고 하실지 모르겠지만 이정도 댓글도 못쓰시는분이 블로깅을 할 수 있으시리란 생각이 들지 않습니다. 사실 그닥 많은 내용도 아니구요 =ㅅ=

마지막으로 티스토리에서 아래의 조건도 만족하면 좋겠지만 위의 조건만 만족해 주시면
18시를 기점으로 바로 배포하겠습니다. =ㅅ=)/

P.S. 예전 초대장 메일의 버그인지 메일의 버그인지는 모르겠지만 일부 초대장이 제대로 안가는 현상이 있었습니다. 18시 이후에 "초대 완료되었습니다" 라고 댓글이 달렸음에도 불구하고 초대장이 오지 않으신분은 귀찮으시겠지만 다시한번 코멘 남겨 주시기 바랍니다. ^^;;
Yes
이런 분들께 드립니다!
1. 다른 블로그를 사용해보셨던 분
2. 이메일 주소가 정상적인 분
3. 블로그를 시작하려는 이유를 남겨주신 분!
No
이런 분들께 드리지 않아요!
1. 이메일 주소가 의심되는 분!
2. 이메일 주소를 남기지 않으신 분
3. 이유도 없이 달라고 하시는 분


이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰



오른쪽 뇌와 왼쪽 뇌의 독립된 기능의 조화와 두뇌 기능의 100% 활용 문제는 아직도 완전히 해결되지 않은 신체의 미스터리중 하나다.

위 애니메이션은 자신이 평소에 오른쪽 뇌를 주로 쓰는 사람인지 아니면 왼쪽 뇌를 많이 쓰는 사람인지 판별할 수 있는 신기한 소재다.

여인이 시계바늘 반대방향으로 돌고 있는 모습이 보이는 사람은 평소에 왼쪽 뇌를 사용하는 사람이다.

왼쪽 뇌는 우리가 아는 대로 논리적이고 세밀한 사고와 사실에 입각한 생각과 판단을 하는 기능을 하며 왼쪽 뇌가 잘 발달된 사람의 특징은 수학과 과학을 잘하고 이해력이 빠르며 기억력이 좋고 꼼꼼한 체질로 알려졌다.

만약에 위 애니메이션의 여인이 시계바늘 방향으로 도는 모습이 보이는 사람은 오른쪽 뇌를 사용하는 사람이다.

오른쪽 뇌는 창의력과 상상력 그리고 철학이나 종교, 예술 등 심미적 사고를 하는 기능을 하며 오른쪽 뇌가 잘 발달하면 창조적이고 탐구적이며 진취적이며 의욕적인 성격과 감성적이고 성급한 체질의 사람이 된다고 알려졌다.

위 그림이 신기한 이유는 훈련하기에 따라서 마음만 먹으면 오른쪽 뇌와 왼쪽 뇌를 번갈아 사용해 여인을 시계 방향 또는 반대 방향으로 돌 수 있게 조종할 수 있다는 것이다.

여인의 다리 또는 발과 그림자 사이에 시선을 집중하고 방향을 바꾸려고 생각하면 여인이 방향을 바꾸며 집중을 잘하면 두 다리가 평행이 될 수 있고 다리를 양 옆으로 또는 앞뒤로 계속 움직이게 할 수도 있다.

위 영상은 오른쪽 뇌를 사용하지 않는 사람에게 오른쪽 뇌를 사용할 수 있는 방법을 터득케 해 왼쪽 뇌만 사용하는 사람이 갖지 못한 창의적이고 진취적인 능력을 갖게 해주고 오른쪽 뇌만 사용하는 사람에게 왼쪽 뇌를 사용하는 방법을 알게 해 필요시에 논리적이고 이성적인 사고 판단을 하도록 돕는다. 좌우 뇌의 기능을 100% 적절하게 활용해 유능한 사람이 되도록 변화시킨다는 것이다.

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰

오라클 데이타 파일 사이즈 추가시 고려사항
1. ORA-01144 : file size (**** blocks) exceeds maxinum of **** blocks

Change db_block_size.  This can only be done by recreating of
   database.
  
       db_block_size    Maximum data file size
       -------------    ----------------------  
            2kb                 8Gb-2kb
            4kb                16Gb-4kb
            8kb                32Gb-8kb
           16kb                64Gb-16kb
           32kb               128Gb-32kb

이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰


오랜만에 사촌동생이 서울 나들이를 온김에 다같이 여의도 불꽃축제 고고싱~
재정옹이랑 형수님이랑 해서 총 5명이 여의도 에서 합류

사람들이 많아서 좀 북적북적대고 힘들긴 했지만 그만큼 불꽃이 이뻐서 만족~



사운드랑 편집해야하는데 걍 귀찮아서 그대로 올리는 만행을 저지름...=ㅅ=;;




밧데리를 챙긴다고 챙겼는데.. 다른 가방에 넣어 버려서 결국
하이라이트인 한화 불꽃은 찍지 못해버린 우울한 사태가.. orz..





한화 시작 할때
- 사이즈 조정한다고 잘못 건드렸더니.. 우울하게 찍혀버렸.. ㅠ_ㅠ
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰
o
# TO DO LIST RULE
# 할일 / 기간 / 시작일 / 종료일 / 기타

1. 불꽃 사진및 동영상 정리 및 파일전송 / 10.06 ~ 10.06 / 10.06  / 10.07 /
2. 책 4권 읽기(판타지소설/전공관련서적 제외) / 10.01 ~ 10.31 /
3. 10g OCP 공부 및 Licese 시험 / 10.01 ~ 10. 31 / 라이센스 시험은 11월로 이월
4. 10g WS2 교육 / 10.20 ~ 10.24 / 10.20 / 10.24  /
5. 경영개선 제안서 / 10.06 ~ 10.08 / 10.10 /
6. 토익 공부 / 10.06 ~ 11.30 / 10. 06 / 11월까지 연장
7. Diet / 10. 06 ~ 10. 31 / 11월 이후도 계속 하기
8. 친구들 얼굴 한번 이상 보기 / 10. 01~ 10.31 /
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰
아아.. 듣지 말걸 그랬다 ㅠ_ㅠ
악마의 음악이야.. 제길슨........
삐삐리 빠삐코~

http://kr.youtube.com/watch?v=uafxMMN47to
이올린에 북마크하기(0) 이올린에 추천하기(0)
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by 건빵쥔곰
TAG 빠삐코