Oracle/Administration2020. 2. 22. 13:23

사용자 정의 함수의 성능을 개선하기 위해 FBI(Function Based Index)를 사용하는 경우가 있다. 사용자 정의 함수를 사용한 FBI의 동작을 살펴보자.


테스트를 위해 아래와 같이 테이블과 함수를 생성하자. t1_x1 인덱스는 f1 함수를 사용한 FBI다.

-- 1
DROP TABLE t1 PURGE;
CREATE TABLE t1 AS SELECT ROWNUM AS c1, ROWNUM AS c2 FROM XMLTABLE ('1 to 2');

CREATE OR REPLACE FUNCTION f1 (i_val IN NUMBER)
    RETURN NUMBER DETERMINISTIC
IS
BEGIN
    DBMS_OUTPUT.PUT_LINE ('X');
    RETURN i_val + 1;
END;
/

CREATE INDEX t1_x1 ON t1 (c1, f1 (c1));

아래의 2-1, 2-2번 쿼리는 t1_x1 인덱스를 사용했고, f1 함수가 수행되지 않았다. 2-2번 쿼리에서 인덱스로 테이블을 액세스한 경우 인덱스에 저장된 값을 사용한다는 것을 알 수 있다. t1_x1 인덱스를 사용하지 않은 3번 쿼리는 f1 함수가 수행된다. 

-- 2-1
SET SERVEROUTPUT ON

SELECT c1, f1 (c1) AS cf1 FROM t1 WHERE c1 = 1;

C1 C1F
-- ---
 1   2

1개의 행이 선택되었습니다.

----------------------------------
| Id  | Operation        | Name  |
----------------------------------
|   0 | SELECT STATEMENT |       |
|*  1 |  INDEX RANGE SCAN| T1_X1 |
----------------------------------

-- 2-2
SELECT c1, c2, f1 (c1) AS cf1 FROM t1 WHERE c1 = 1;

C1 C2 CF1
-- -- ---
 1  1   2

1개의 행이 선택되었습니다.

-----------------------------------------------------
| Id  | Operation                           | Name  |
-----------------------------------------------------
|   0 | SELECT STATEMENT                    |       |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T1    |
|*  2 |   INDEX RANGE SCAN                  | T1_X1 |
-----------------------------------------------------

-- 2-3
SELECT c1, f1 (c1) AS cf1 FROM t1;

C1 CF1
-- ---
 1   2
 2   3

2 행이 선택되었습니다.

X
X

----------------------------------
| Id  | Operation         | Name |
----------------------------------
|   0 | SELECT STATEMENT  |      |
|   1 |  TABLE ACCESS FULL| T1   |
----------------------------------

FBI의 표현식은 테이블에 가상 칼럼(SYS_NC00003$)으로 생성된다. 가상 칼럼은 물리적으로 저장되지 않는다.

-- 3
SELECT column_name, data_default, hidden_column, virtual_column FROM user_tab_cols WHERE table_name = 'T1';

COLUMN_NAME  DATA_DEFAULT      HIDDEN_COLUMN VIRTUAL_COLUMN
------------ ----------------- ------------- --------------
C1                             NO            NO
C2                             NO            NO
SYS_NC00003$ "TUNA"."F1"("C1") YES           YES

3 행이 선택되었습니다.

블록 덤프를 수행하기 위해 아래와 같이 쿼리를 수행하자. 테이블은 7번 파일, 403번 블록, 인덱스는 7번 파일, 411번 블록에 저장되어 있다.

-- 4-1
SELECT object_id FROM user_objects WHERE object_name  = 'T1_X1';

OBJECT_ID
---------
   277654

1개의 행이 선택되었습니다.

-- 4-2
SELECT c1
     , sys_nc00003$
     , DBMS_ROWID.ROWID_RELATIVE_FNO (ROWID) AS tfno
     , DBMS_ROWID.ROWID_BLOCK_NUMBER (ROWID) AS tbno
     , DBMS_ROWID.ROWID_RELATIVE_FNO (SYS_OP_LBID (277654, 'L', ROWID)) AS ifno
     , DBMS_ROWID.ROWID_BLOCK_NUMBER (SYS_OP_LBID (277654, 'L', ROWID)) AS ibno
  FROM t1;

C1 SYS_NC00003$ TFNO TBNO IFNO IBNO
-- ------------ ---- ---- ---- ----
 1            2    7  403    7  411
 2            3    7  403    7  411

2 행이 선택되었습니다.

X
X

아래와 같이 블록 덤프를 수행하자. t1 테이블은 f1 (c1) 표현식의 값이 저장되지 않고, t1_x1 인덱스는 표현식의 결과가 저장된 것을 확인할 수 있다. 복호화 함수로 FBI를 생성하면 보안 이슈가 발생할 수 있는 점에 주의할 필요가 있겠다.

-- 5-1
ALTER SYSTEM DUMP DATAFILE 7 BLOCK 403;

tab 0, row 0, @0x1f77
tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 02 --> 1
col  1: [ 2]  c1 02 --> 1
tab 0, row 1, @0x1f6e
tl: 9 fb: --H-FL-- lb: 0x0  cc: 2
col  0: [ 2]  c1 03 --> 2
col  1: [ 2]  c1 03 --> 2

-- 5-2
ALTER SYSTEM DUMP DATAFILE 7 BLOCK 411;

row#0[8021] flag: -------, lock: 0, len=15
col 0; len 2; (2):  c1 02             --> 1 : c1
col 1; len 2; (2):  c1 03             --> 2 : f1 (c1)
col 2; len 6; (6):  01 c0 01 93 00 00 --> ROWID
row#1[8006] flag: -------, lock: 0, len=15
col 0; len 2; (2):  c1 03             --> 2 : c1
col 1; len 2; (2):  c1 04             --> 3 : f1 (c1)
col 2; len 6; (6):  01 c0 01 93 00 01 --> ROWID


'Oracle > Administration' 카테고리의 다른 글

ALTER SEQUENCE RESTART  (0) 2019.09.04
DBA_LOGSTDBY_NOT_UNIQUE  (0) 2019.08.27
Hybrid Partitioned 테이블  (0) 2019.08.22
Partitioned External 테이블  (0) 2019.08.22
인덱스 명명 규칙  (0) 2019.08.19
Posted by 정희락_