본문 바로가기
DBMS/SQL튜닝

스칼라 서브쿼리 캐싱 및 버퍼 pinning

by 드바 2022. 5. 24.
- 오라클은 스칼라 서브쿼리 수행 시 입력 값(메인쿼리에서 받은)과 출력 값을 내부 캐시(Query Execution Cache)에 저장
- _query_execution_cache_max_size 파라미터 사이즈 만큼 캐시 사용
- 스칼라 서브쿼리가 수행될 때 '입력 값'이 캐시에 있으면 저장된 '출력 값'을 리턴
- 캐시에서 찾지 못한 경우 쿼리 수행, 결과값은 캐시에 저장
- 스칼라 서브쿼리의 캐싱 효과는 입력 값의 종류가 적을 때 성능 개선 효과

 
테스트를 위해 아래와 같이 테이블을 생성하자.

CREATE TABLE t1 AS SELECT ROWNUM AS c1, NVL (NULLIF (MOD (ROWNUM, 100), 0), 100) AS c2 FROM XMLTABLE ('1 to 10000');
CREATE TABLE t2 AS SELECT ROWNUM AS c1, ROWNUM AS c2 FROM XMLTABLE ('1 to 10000');
 
CREATE INDEX t1_x1 ON t1 (c1, c2);
CREATE INDEX t1_x2 ON t1 (c2, c1);
CREATE INDEX t2_x1 ON t2 (c1);
CREATE INDEX t2_x2 ON t2 (c2);


아래 쿼리는 서브 쿼리에 1에서 10000까지의 순번이 입력된다. 서브 쿼리 Caching 효과가 발생하지 않았지만(Starts = 10000), 버퍼 Pinning 효과에 의해 166개의 블록 I/O가 발생했다.
 

-- T1 데이터 조회 순서
T1_C1|T1_C2|
-----+-----+
    1|    1|
    2|    2|
    3|    3|
    4|    4|
    5|    5|
    6|    6|
    7|    7|
    8|    8|
    9|    9|
   10|   10|
   11|   11|
   12|   12|
   13|   13|
   14|   14|
   15|   15|
   16|   16|
...

SELECT /*+ INDEX(A) */ 
COUNT ((SELECT /*+ INDEX(X) */ MAX(x.c2) FROM t2 x WHERE x.c1 = a.c1))
FROM t1 a
WHERE a.c1 > 0
;

-------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name  | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
-------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |       |      1 |        |       |   115 (100)|          |      1 |00:00:00.03 |     193 |     40 |
|   1 |  SORT AGGREGATE                      |       |  10000 |      1 |    26 |            |          |  10000 |00:00:00.02 |     166 |     21 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T2    |  10000 |    100 |  2600 |     2   (0)| 00:00:01 |  10000 |00:00:00.01 |     166 |     21 |
|*  3 |    INDEX RANGE SCAN                  | T2_X1 |  10000 |     40 |       |     1   (0)| 00:00:01 |  10000 |00:00:00.01 |     148 |     21 |
|   4 |  SORT AGGREGATE                      |       |      1 |      1 |    13 |            |          |      1 |00:00:00.03 |     193 |     40 |
|*  5 |   INDEX RANGE SCAN                   | T1_X1 |      1 |  10000 |   126K|    28   (0)| 00:00:01 |  10000 |00:00:00.01 |      27 |     19 |
-------------------------------------------------------------------------------------------------------------------------------------------------


아래 쿼리는 서브 쿼리에 1, 101, 201, 301 ... 순서의 값이 100회 반복 입력된다. 서브 쿼리 Caching 효과가 발생하지 않았고, 버퍼 Pinning 효과도 발생하지 않아 13,421개의 블록 I/O가 발생했다.

-- T1 데이터 조회 순서
T1_C1|T1_C2|
-----+-----+
    1|    1|
  101|    1|
  201|    1|
  301|    1|
  401|    1|
  501|    1|
  601|    1|
  701|    1|
  801|    1|
  901|    1|
 1001|    1|
 1101|    1|
 1201|    1|
 1301|    1|
...

SELECT /*+ INDEX(A) */
COUNT ((SELECT /*+ INDEX(X) */ MAX(x.c2) FROM t2 x WHERE x.c1 = a.c1))
FROM t1 a
WHERE a.c2 > 0
;
 
-------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name  | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
-------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |       |      1 |        |       |   653 (100)|          |      1 |00:00:00.03 |   13448 |     19 |
|   1 |  SORT AGGREGATE                      |       |  10000 |      1 |    26 |            |          |  10000 |00:00:00.02 |   13421 |      0 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T2    |  10000 |    100 |  2600 |     2   (0)| 00:00:01 |  10000 |00:00:00.02 |   13421 |      0 |
|*  3 |    INDEX RANGE SCAN                  | T2_X1 |  10000 |     40 |       |     1   (0)| 00:00:01 |  10000 |00:00:00.01 |   11621 |      0 |
|   4 |  SORT AGGREGATE                      |       |      1 |      1 |    26 |            |          |      1 |00:00:00.03 |   13448 |     19 |
|*  5 |   INDEX RANGE SCAN                   | T1_X2 |      1 |  10000 |   253K|    28   (0)| 00:00:01 |  10000 |00:00:00.01 |      27 |     19 |
-------------------------------------------------------------------------------------------------------------------------------------------------


아래 쿼리는 서브 쿼리에 1에서 100까지의 값이 100회씩 입력된다. 서브 쿼리 Caching 효과와 버퍼 Pinning 효과에 의해 9개의 블록 I/O가 발생했다.

-- T1 데이터 조회 순서
T1_C1|T1_C2|
-----+-----+
    1|    1|
  101|    1|
  201|    1|
  301|    1|
  401|    1|
  501|    1|
  601|    1|
  701|    1|
  801|    1|
  901|    1|
 1001|    1|
 1101|    1|
 1201|    1|
 1301|    1|
...

SELECT /*+ INDEX(A) */
COUNT ((SELECT /*+ INDEX(X) */ MAX(x.c1) FROM t2 x WHERE x.c2 = a.c2))
FROM t1 a
WHERE a.c2 > 0
;
 
-------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name  | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers | Reads  |
-------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |       |      1 |        |       |   115 (100)|          |      1 |00:00:00.01 |      36 |      1 |
|   1 |  SORT AGGREGATE                      |       |    100 |      1 |    26 |            |          |    100 |00:00:00.01 |       9 |      1 |
|   2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T2    |    100 |    100 |  2600 |     2   (0)| 00:00:01 |    100 |00:00:00.01 |       9 |      1 |
|*  3 |    INDEX RANGE SCAN                  | T2_X2 |    100 |     40 |       |     1   (0)| 00:00:01 |    100 |00:00:00.01 |       8 |      1 |
|   4 |  SORT AGGREGATE                      |       |      1 |      1 |    13 |            |          |      1 |00:00:00.01 |      36 |      1 |
|*  5 |   INDEX RANGE SCAN                   | T1_X2 |      1 |  10000 |   126K|    28   (0)| 00:00:01 |  10000 |00:00:00.01 |      27 |      0 |
-------------------------------------------------------------------------------------------------------------------------------------------------


-- 참조
https://hrjeong.tistory.com/359
http://wiki.gurubee.net/pages/viewpage.action?pageId=6259012

댓글