블록 단위 I/O는 버퍼 캐시와 데이터파일 I/O 모두에 적용된다.
1. 오라클 딕셔너리 정보를 저장하는 딕셔너리 캐시는 로우 단위로 I/O를 수행
(딕셔너리 캐시를 '로우 캐시'라고도 부르는 이유)
2. Block = 데이터베이스를 생성할 때 db_block_size를 지정
3. 오라클에서 허용 되는 범위 = 2k, 4k, 8k, 16k, 32k, 64k (Default 8K)
4. 다른 크기의 블록을 동시에 사용하려면 각각 별도의 테이블스페이스와 버퍼 Pool을 구성
SQL> CREATE TABLE t2
2 AS
3 SELECT * FROM all_objects
4 ORDER BY dbms_random.value;
Table created.
SQL> SELECT COUNT(*) FROM t2;
COUNT(*)
----------
49906
-- T2 테이블에는 49,906건의 레코드가 저장돼 있음.
SQL> SELECT COUNT(*) FROM t2
2 WHERE owner LIKE 'SYS%';
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 SORT AGGREGATE (cr=691 pr=0 pw=0 time=13037 us)
24613 TABLE ACCESS FULL T2 (cr=691 pr=24456 pw=0 time=98473 us)
위 쿼리는 24,613개 레코드를 선택하려고 49,906개 레코드를 스캔했으므로 선택도는 49%다.
(선택도 : 24,613 / 49,906 X 100 = 49%)
Full Scan 선택도가 이 정도면 나쁘지 않아 보인다. 읽은 블록 수는 691개였다.
SQL> SELECT COUNT(*) FROM t2
2 WHERE owner LIKE 'SYS%'
3 AND object_name = 'ALL_OBJECTS';
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 SORT AGGREGATE (cr=691 pr=0 pw=0 time=7191 us)
1 TABLE ACCESS FULL T2 (cr=691 pr=0 pw=0 time=7150 us)
위 쿼리는 1개 레코드를 선택하려고 49,906개 레코드를 스캔했으므로 선택도는 0.002%다.
선택도가 매우 낮으므로 테이블 Full Scan 비효율이 크다.
여기서도 읽은 블록 수는 똑같이 691개다.
이처럼 테이블을 스캔하면서 읽은 레코드 중 대부분 필터링되고 일부만 선택된다면 아래처럼 인덱스를 이용하는게 효과적이다.
SQL> CREATE INDEX t_idx ON t2 (owner, object_name);
Index created.
SQL> SELECT /*+ index(t t_idx) */ COUNT(*) FROM t2
2 WHERE owner LIKE 'SYS%'
3 AND object_name = 'ALL_OBJECTS';
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 SORT AGGREGATE (cr=76 pr=0 pw=0 time=7009 us)
1 INDEX RANGE SCAN T_IDX (cr=76 pr=0 pw=0 time=6972 us)(Object ID 89340571)
SQL> SELECT /*+ index(t t_idx) */ COUNT(*) FROM t2
2 WHERE owner like 'SYS%'
3 AND ((owner = 'SYS' and object_name >= 'ALL_OBJECTS' ) or (owner >'SYS'));
COUNT(*)
----------
14587
-- 인덱스 컬럼 순서를 변경하고 같은 쿼리를 수행.
SQL> DROP INDEX t_idx;
Index droped.
SQL> CREATE INDEX t_idx ON t2 (object_name, owner);
Index created.
SQL> SELECT /*+ index(t t_idx) */ COUNT(*) FROM t2
2 WHERE owner LIKE 'SYS%'
3 AND object_name = 'ALL_OBJECTS';
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 TABLE ACCESS BY INDEX ROWID T (cr=2 pr=0 pw=0 time=67 us)
1 INDEX RANGE SCAN T_IDX (cr=2 pr=0 pw=0 time=51 us)(Object ID 89340584)
Random 액세스 발생량을 낮추는 방법.
인덱스에 속하지 않는 컬럼(object_name)을 참조하도록 쿼리를 변경함으로써 테이블 액세스가 발생하도록 할 것이다.
SQL> DROP INDEX t_idx;
SQL> CREATE INDEX t_idx ON t2 (owner);
SQL> SELECT object_id FROM t2
2 WHERE owner = 'SYS'
3 AND object_name = 'ALL_OBJECTS';
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.010 0.005 0 227 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 2.000 8.980 16110 16151 0 1
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 2.010 8.986 16110 16378 0 1
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 TABLE ACCESS BY INDEX ROWID T2 (cr=16151 pr=16110 pw=0 time=3709697 us)
26263 INDEX RANGE SCAN T_IDX (cr=59 pr=57 pw=0 time=79997 us)(Object ID 89343114)
최종 한 건을 선택하려고 너무 많은 Random 액세스가 발생
object_name을 필터링하려고 테이블을 많이 방문한 것이므로 인덱스 액세스 단계에서 필터링할 수 있도록 object_name을 추가해보자.
SQL> DROP INDEX t_idx;
SQL> CREATE INDEX t_idx ON t2 (owner, object_name);
SQL> SELECT object_id FROM t2
2 WHERE owner = 'SYS'
3 AND object_name = 'ALL_OBJECTS';
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.010 0.013 0 230 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 0.000 0.002 1 5 0 1
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 0.010 0.015 1 235 0 1
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
1 TABLE ACCESS BY INDEX ROWID T2 (cr=5 pr=1 pw=0 time=1878 us)
1 INDEX RANGE SCAN T_IDX (cr=4 pr=0 pw=0 time=30 us)(Object ID 89340592)