반응형

Result Cache 관련 latch는 result cache 에 데이터가 있고 , 그 상태에서 해당 정보에 접근하기 위하여 획득하여야 한다는 것을 전 포스트에서 확인 할 수 있었다.

이번에는 result cache관련 다른 이벤트인 Enq : RC – Result Cache : Contention에 대해서 확인 해 보도록 하자.

다음 쿼리를 이용하여 Result Cache관련 추가된 이벤트가 무엇이 있는지 확인 할 수 있다.


11:28:50 HR 5036>SELECT name , wait_class , PARAMETER1 ,PARAMETER2 ,PARAMETER3 FROM v$event_name WHERE name like '%Result%' ;

NAME                                          WAIT_CLASS     PARAMETER1   PARAMETER2  PARAMETER3
--------------------------------- -------------- --------------- --------------- -------------- enq: RC - Result Cache: Contention    Application     name|mode        chunkNo          blockNo


해당 enqueue가 몇 번이나 발생 하였는지는 v$enque_stat 뷰를 확인 하면 알 수 있다. 그럼 어떠한 경우에 해당 enqueue의 요청이 있는지 확인해 보도록 하자.

테스트를 위해서 데이터 베이스를 Restart한 후 테스트를 진행 해 보았다.



14:09:23 HR 6805>SELECT * FROM v$result_cache_objects ;

no rows selected

14:09:32 HR 6805>SELECT * FROM v$enqueue_stat WHERE eq_type = 'RC' ;

No rows selected


위와 같이 조회를 해 보면 아직 RC enqueue가 사용되지 않음을 확인 할 수 있다.


- Test Case#1


Result cache에 등록된 데이터는 없는 상태이다. 새로운 Result 데이터를 등록해 본 후 Enqueue 요청을 확인해 보자.



14:12:10 HR 6805>select /*+ result_cache */ count(*) from test_rc ;

COUNT(*)
----------
103

14:12:24 HR 6805>set autotrace on exp stat
14:12:36 HR 6805>select /*+ result_cache */ count(*) from test_rc ;

COUNT(*)
----------
103

Execution Plan
----------------------------------------------------------
Plan hash value: 1775316367

---------------------------------------------------------------------------------
| Id | Operation                                        | Name | Rows | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT                       |          |        1 |             3 (0)| 00:00:01 |
| 1 | RESULT CACHE                            | 3dhb1js3x6ghf0zdkxtn6cwvsp
| 2 | SORT AGGREGATE                           |           |       1 |                   |             |
| 3 | TABLE ACCESS FULL| TEST_RC       |            |    103 |            3 (0)| 00:00:01 |
----------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=1; dependencies=(HR.TEST_RC); attributes=(single-row); name="select /*+ result_cache */ count(*) from test_rc "

Note
-----
- dynamic sampling used for this statement

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
419 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

14:12:43 HR 6805>SELECT name , type , scan_count , object_no , invalidations FROM v$result_cache_objects ;

NAME                                       TYPE         SCAN_COUNT  OBJECT_NO INVALIDATIONS
------------------------------ ------------ ------------- ------------ ----------------
HR.TEST_RC                             Dependency       0                    76779               0
select /*+ result_cache */ cou   Result                 1                          0               0
nt(*) from test_rc


14:16:32 HR 6805>SELECT * FROM v$enqueue_stat WHERE eq_type = 'RC' ;


INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
1          RC                     2                  0                     2                0                       0



위의 테스트 결과를 보면 Total_req# 이 2번 있고 Succ_req# 값이 2 이다. 즉 두번의 RC enqueue 요청이 있었고 두번의 요청이 모두 성공적으로 enqueue를 획득 하였다는 뜻이다.


-Test Case#2

latch 와 마찬가지로 result cache관련 조회 시 Enqueue요청이 증가 하는지 확인해 보도록 하자.


14:19:15 HR 6805>select /*+ result_cache */ count(*) from test_rc ;
                       
COUNT(*)
----------
       103

Execution Plan
----------------------------------------------------------
Plan hash value: 1775316367

-----------------------------------------------------------------------------
| Id | Operation                                  | Name | Rows | Cost (%CPU)|   Time   |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT                  |          |        1 |            3 (0)| 00:00:01 |
| 1 | RESULT CACHE | 3dhb1js3x6ghf0zdkxtn6cwvsp                              |
| 2 | SORT AGGREGATE                     |           |        1 |                  |             |
| 3 | TABLE ACCESS FULL| TEST_RC  |           |     103 |           3 (0)| 00:00:01 |
-----------------------------------------------------------------------------

Statistics
----------------------------------------------------------
75 recursive calls
0 db block gets
14 consistent gets
8 physical reads
0 redo size
419 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)


14:21:48 HR 6805>SELECT * FROM v$enqueue_stat WHERE eq_type = 'RC' ;

INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
        1      RC                   2                    0                 2                    0                       0


Result Cache를 사용할 때는 Enqueue에 대한 요청이 발생하지 않음을 확인 할 수 있다.


-Test Case#3

기존의 Result cache 데이터를 변경하기 위해서 test_rc테이블에 대하여 DML을 발생 시킨 후 RC enqueue가 변화 하는지 확인해 보도록 하자


- Check.sql

SELECT name , type , scan_count , object_no , invalidations FROM v$result_cache_objects ; SELECT * FROM v$enqueue_stat WHERE eq_type = 'RC' ;



14:27:02 HR 6805>insert into test_rc values ( 104, 'N 104') ;

1 row created.

14:28:35 HR 6805>@check

NAME                                       TYPE         SCAN_COUNT  OBJECT_NO INVALIDATIONS
------------------------------ ------------ ------------- ------------ ----------------
HR.TEST_RC                            Dependency                  0             76779                      0
select /*+ result_cache */ cou   Result                           2                   0                      0
nt(*) from test_rc

INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
       1      RC                    2               0                 2                      0                       0


14:29:53 HR 6805>commit ;

14:30:21 HR 6805>@check

NAME                                       TYPE         SCAN_COUNT  OBJECT_NO INVALIDATIONS
------------------------------ ------------ ------------- ------------ ----------------
HR.TEST_RC                            Dependency                   0            76779                    1
select /*+ result_cache */ cou   Result                            2                  0                   0
nt(*) from test_rc


INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
       1       RC                   3                   0                 3                     0                       0


Result Cache를 Invalidation 시켜 보기 위해서 데이터를 변경 시킨 후에 v$result_cache_objects , v$enqueue_stat뷰를 조회해 보면 Dependency 테이블이 invalidation되면서 RC enqueue 요청이 한번 있었다. 새로운 Result를 Caching 시키기 위해서는 Dependency에 한번 쿼리와 연관된 부분을 참조 하기 위해서 한번 이렇게 두 번의 요청이 있었고 , Dependency 부분에 대한 변경을 가할 경우 RC Enqueue 요청이 한번 있음을 확인 할 수 있다.


- Test Case#3

Dependency 가 존재 하는 상태에서 새로운 쿼리 Result 등록시에 RC Enqueue 요청이 몇 번 일어날까 ?



14:36:32 HR 6805>SELECT /*+ result_cache */ max(empno) FROM test_rc ;

MAX(EMPNO)
------------
            105


Execution Plan
----------------------------------------------------------
Plan hash value: 1775316367

-----------------------------------------------------------------------------
| Id | Operation                                  | Name | Rows | Cost (%CPU)|   Time   |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT                  |       1 |      13 |             3 (0)| 00:00:01 |
| 1 | RESULT CACHE | 93dajfjcxpd1t5474wnnz6kzjb
| 2 | SORT AGGREGATE                      |       1 |     13 |                    |             |
| 3 | TABLE ACCESS FULL| TEST_RC   |    104 |  1352 |             3 (0)| 00:00:01 |
------------------------------------------------------------------------------

Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=1; dependencies=(HR.TEST_RC); attributes=(single-row); name="SELECT /*+ result_cache */ max(empno) FROM test_rc "


Statistics
----------------------------------------------------------
183 recursive calls
0 db block gets
36 consistent gets
9 physical reads
124 redo size
421 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
1 rows processed


14:36:35 HR 6805>@check

NAME                                       TYPE         SCAN_COUNT  OBJECT_NO INVALIDATIONS
------------------------------ ------------ ------------- ------------ ---------------- HR.TEST_RC                            Dependency                    0           76779                      1 SELECT /*+ result_cache */ max Result                    0                 0                      0 (empno) FROM test_rc
select /*+ result_cache */ cou  Result                             2                  0                      0
nt(*) from test_rc


INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
       1      RC                    5                   0                  5                    0                       0


기존에 Dependency 가 존재 하더라도 두 번의 RC enqueue 요청이 발생 하였다. Dependency의 invalidation 상태를 체크 한 후에 쿼리 Result를 등록 시도 하는 것으로 추정이 된다. 아직 Oracle 11g 관련 문서의 부재로 테스트에 의존 할 수 밖에 없는 상황이라서 확실히 결론을 내리기는 어렵다.


- Test Case#4


RC Enqueue 경합을 발생 시켜서 v$enqueue_stat 뷰 및 세션 10046 Trace이용하여 wait Event를 확인 해 보도록 하자.

서로 다른 세션에서 dml.sql을 수행하게 한 후 10046 Trace 확인



- dml.sql

declare
   v_cnt number ;
begin
   for i IN 1..100000 LOOP
          insert into test_rc values ( 105 , 'N 105' ) ;
          commit ;
          select /*+ result_cache */ count(*) into v_cnt from test_rc ;
          delete test_rc where empno = 105 ;
          commit ;
   end loop;
end;
/




- Session #1

14:43:26 HR 7940>alter session set events '10046 trace name context forever ,level 12' ; 
  
   Session altered.

14:43:41 HR 7940>@dml




- Session #2

14:44:13 HR 7969>alter session set events '10046 trace name context forever , level 12' ;

   Session altered.

14:44:29 HR 7969>@dml




- DBA Session

14:46:33 SYS 8037>SELECT * FROM v$lock WHERE type = 'RC';
  
    ADDR  KADDR            SID TYPE          ID1             ID2    LMODE  REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- ---------- -------32367818 32367844           170   RC               1             31              6              0               0       0


14:46:35 SYS 8037>/

   ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844          138     RC             2         76779              4              0             0          0

14:48:08 SYS 8037>/

   ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844          138     RC             1              31              6              0            0           0

14:48:27 SYS 8037>/

   ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844           170  RC               1              30             6                0            0        0
3236788C 323678B8          138  RC              1               31             6                0            0        0

14:52:52 SYS 8037>SELECT * FROM v$lock WHERE type = 'RC';

  ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844           138    RC              2        76779              3              0             0        0

14:53:59 SYS 8037>/

  ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844           138   RC              2         76779              4               0            0           0
3236788C 323678B8          170   RC              1             30              4               0            0           0

14:54:33 SYS 8037>/

  ADDR  KADDR            SID   TYPE         ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844           138   RC              2          76779             4               0             0          0
3236788C 323678B8          170   RC              1               31            4               0             0          0

14:55:17 SYS 8037>/

  ADDR  KADDR            SID TYPE          ID1             ID2    LMODE   REQUEST   CTIME     BLOCK
-------- -------- ---------- ---- ---------- ---------- ---------- ---------- --------- -------32367818 32367844          170   RC               1              31              6           0           0            1
3236788C 323678B8         138   RC               1              31              0             4           0            0


위와 같이 v$lock 뷰를 조회해 보면 Object id 가 76779(TEST_RC-TABLE) , 30(I_COBJ#-INDEX) , 31(CDEF$-TABLE)에 대한 요청이 발생하고 있다. 이 시점에 v$result_cache_objects뷰를 조회해 보면 동일 SELECT /*+ result_cache */ COUNT(*) FROM TEST_RC 쿼리가 여러 개 등록 됨을 확인 할 수 있다. 즉 하나 하나 새로운 쿼리 Result를 등록하고 사용하고 등록하고 사용하고 하는 것이다.



15:21:20 SYS 8606>@check

NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.TEST_RC                          Dependency Published            0        76779         2298194
SELECT /*+ result_cache */ COU Result    Published           0              0                  0
NT(*) FROM TEST_RC
select /*+ result_cache */ cou Result              Invalid           2              0                  0
nt(*) from test_rc
SELECT /*+ result_cache */ max Result           Invalid            0               0                  0
(empno) FROM test_rc
SELECT /*+ result_cache */ COU Result          Invalid            0              0                   0
NT(*) FROM TEST_RC
.....같은 데이터 생략

32 rows selected.


INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
        1     RC        10235843           229662     10054184            181655                27890


15:21:45 SYS 8606>set serveroutput on
15:23:33 SYS 8606>exec dbms_result_cache.memory_report(true) ;

R e s u l t C a c h e M e m o r y R e p o r t
[Parameters]
Block Size = 1K bytes
Maximum Cache Size = 3296K bytes (3296 blocks)
Maximum Result Size = 164K bytes (164 blocks)
[Memory]
Total Memory = 103528 bytes [0.112% of the Shared Pool]
... Fixed Memory = 5132 bytes [0.006% of the Shared Pool]
....... Cache Mgr = 108 bytes
....... Memory Mgr = 124 bytes
....... Bloom Fltr = 2K bytes
....... State Objs = 2852 bytes
... Dynamic Memory = 98396 bytes [0.107% of the Shared Pool]
....... Overhead = 65628 bytes
........... Hash Table = 32K bytes (4K buckets)
........... Chunk Ptrs = 12K bytes (3K slots)
........... Chunk Maps = 12K bytes
........... Miscellaneous = 8284 bytes
....... Cache Memory = 32K bytes (32 blocks)
........... Unused Memory = 0 blocks
........... Used Memory = 32 blocks
............... Dependencies = 1 blocks (1 count)
............... Results = 31 blocks
................... SQL = 1 blocks (1 count)
................... Invalid = 30 blocks (30 count)

PL/SQL procedure successfully completed.

15:23:45 SYS 8606>show parameter result_cache_max_size

                      NAME                                     TYPE                           VALUE
------------------------------------ ---------------------- ------------------------------
 result_cache_max_size                                  big integer                      3296K


15:25:09 SYS 8606>SELECT name , GETS ,MISSES ,SPIN_GETS FROM v$latch WHERE name like '%Result%' ;

              NAME                          GETS      MISSES    SPIN_GETS
------------------------------ ---------- ---------- ----------
Result Cache: Latch                    28045823       131600       108373
Result Cache: SO Latch                         4              0               0


Cache Memory에서 1K사이즈 블록을 32개 사용 중이며, 그 중 1개는 Dependency 정보이고 나머지 31개가 SQL Result 이다. 그 중 현재 사용되는 SQL result가 1개 이고 나머지는 invalid 상태임을 확인 할 수 있다.


이 부분은 전혀 예상하지 못했던 부분이다. 단지 RC enqueue 요청 횟수와 v$lock에서의 정보를 확인 해 보기 위한 테스트 였는데 전혀 뜻밖에 동일 SQL이 invalid 되면서 새로운 데이터가 캐시 되고 사용되고 하는 것을 확인 할 수 있다. 이는 latch 요청 증가를 확인해도 알 수 있다.


- Test Case#5


그럼 왜 ? 동일 SQL을 수행하는데 각각의 쿼리들이 새로 등록이 되고 사용이 되는 것일까 ? 어느 경우 이런 경우가 발생 하는지 확인 해 보도록 하자.



16:04:30 HR 11983>@check

no rows selected

no rows selected

16:04:47 HR 11983>set autotrace on exp stat
16:05:23 HR 11983>select /*+ result_cache */ count(*) from test_rc ;

COUNT(*)
----------
106

Execution Plan
----------------------------------------------------------
Plan hash value: 1775316367

------------------------------------------------------------------------------------------
 | Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 (0)| 00:00:01 |
| 1 | RESULT CACHE | 3dhb1js3x6ghf0zdkxtn6cwvsp | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | TABLE ACCESS FULL| TEST_RC | 106 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------

Statistics
----------------------------------------------------------
75 recursive calls
0 db block gets
14 consistent gets
0 physical reads
0 redo size
419 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
1 rows processed


16:05:32 HR 11983>@check

NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.TEST_RC                        Dependency Published              0        76779             0
select /*+ result_cache */ cou Result        Published             1              0              0
nt(*) from test_rc

INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
      1        RC                  2                    0                 2                     0                      0


정상적으로 하나의 Result 데이터를 로드 하였다. DML을 발생 후 어떠한 변화가 있는지 확인해 보자



16:05:35 HR 11983> insert into test_rc values ( 1000 , 'N1000') ;
1 row created.
16:08:41 HR 11983>commit ;
Commit complete.
16:08:44 HR 11983>@check

NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.TEST_RC                         Dependency Published            0          76779             1
select /*+ result_cache */ cou Result              Invalid           1                 0             0
nt(*) from test_rc

INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
       1       RC                   3                   0                  3                    0                        0


DML발생 후에도 Result Cache에 데이터는 늘어 나지 않았다. 이 시점에 동일 SQL문을 재 수행 해 보도록 하겠다.



16:09:16 HR 11983>select /*+ result_cache */ count(*) from test_rc ;

COUNT(*)
----------
107

Execution Plan
----------------------------------------------------------
Plan hash value: 1775316367

------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 (0)| 00:00:01 |
| 1 | RESULT CACHE | 3dhb1js3x6ghf0zdkxtn6cwvsp | | | |
| 2 | SORT AGGREGATE | | 1 | | |
| 3 | TABLE ACCESS FULL| TEST_RC | 107 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------------------


Statistics
----------------------------------------------------------
1229 recursive calls
10 db block gets
213 consistent gets
13 physical reads
124 redo size
419 bytes sent via SQL*Net to client
420 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
17 sorts (memory)
0 sorts (disk)
1 rows processed


16:10:30 HR 11983>@check

NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.TEST_RC                           Dependency Published           0         76779                 1
select /*+ result_cache */ cou   Result         Published           0               0                 0
nt(*) from test_rc
select /*+ result_cache */ cou   Result              Invalid           1               0                 0
nt(*) from test_rc


Elapsed: 00:00:00.03


INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
      1        RC                   5                   0                  5                    0                      0


16:18:03 SYS >set serveroutput on
16:18:07 SYS >exec dbms_result_cache.memory_report(true);

R e s u l t C a c h e M e m o r y R e p o r t
[Parameters]
Block Size = 1K bytes
Maximum Cache Size = 3296K bytes (3296 blocks)
Maximum Result Size = 164K bytes (164 blocks)
[Memory]
Total Memory = 103528 bytes [0.099% of the Shared Pool]
... Fixed Memory = 5132 bytes [0.005% of the Shared Pool]
....... Cache Mgr = 108 bytes
....... Memory Mgr = 124 bytes
....... Bloom Fltr = 2K bytes
....... State Objs = 2852 bytes
... Dynamic Memory = 98396 bytes [0.094% of the Shared Pool]
....... Overhead = 65628 bytes
........... Hash Table = 32K bytes (4K buckets)
........... Chunk Ptrs = 12K bytes (3K slots)
........... Chunk Maps = 12K bytes
........... Miscellaneous = 8284 bytes
....... Cache Memory = 32K bytes (32 blocks)
.......... Unused Memory = 29 blocks
........... Used Memory = 3 blocks
............... Dependencies = 1 blocks (1 count)
............... Results = 2 blocks
................... SQL = 1 blocks (1 count)
................... Invalid = 1 blocks (1 count)

PL/SQL procedure successfully completed.


위와 같이 참조 Object가 invalid 된 후 재 수행된 SQL문은 cache id 는 같지만 새로운 메모리 영역을 사용함을 확인 할 수 있다. 마치 동일 SQL이지만 실행 계획이 여러 개 생성 될 경우 Child LCO가 늘어 나는 거 같은 느낌이다. 혹시 library cache 영역과 관계가 있을까 해서 v$sqlarea , v$sql 쿼리를 수행해 보지만 select /*+ result_cache */ count(*) from test_rc 라는 SQL문은 찾아 볼 수 없다. 기존에 SQL 수행 단계에서 library cache영역을 확인하기 전에 Result Cache 영역을 조사하는 로직이 하나 추가된 것으로 추정이 된다. library cache 영역과 별개로 Result Cache영역이 사용되고 있음을 확인 할 수있다.


그럼 SQL Result만 새로 추가 되는 것인지 , 아니면 펑션을 사용하는 Result도 재 등록 되는지 확인해 보도록 하자.



create or replace function f_test_rc return number result_cache
as
    v_cnt number ;
begin
    select count(*) into v_cnt from test_rc ;
    return v_cnt ;
end ;



16:27:10 HR 11983>SELECT f_test_rc FROM dual ;

F_TEST_RC
----------
107

16:27:27 HR 11983>@check


NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.F_TEST_RC                     Dependency   Published           0         76788                  0
HR.TEST_RC                        Dependency    Published          0          76779                 1
"HR"."F_TEST_RC"::8."F_TEST_RC Result     Published          0                0                 0
"#9689ba467a19cd19 #1
select /*+ result_cache */ cou      Result      Published          0               0                  0
nt(*) from test_rc
select /*+ result_cache */ cou      Result         Invalid            1               0                  0
nt(*) from test_rc



INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
      1      RC                     7                   0                 7                     0                      0


16:28:24 HR 11983>alter function f_test_rc compile ;

Function altered.

Elapsed: 00:00:00.12

16:29:46 HR 11983>SELECT f_test_rc FROM dual ;

F_TEST_RC
----------
108


16:29:57 HR 11983>@check


NAME                                      TYPE       STATUS SCAN_COUNT OBJECT_NO INVALIDATIONS
------------------------------ --------- --------- ---------- ---------- ------------- HR.F_TEST_RC                     Dependency   Published            0           76788            1
HR.TEST_RC                        Dependency   Published            0           76779            2
"HR"."F_TEST_RC"::8."F_TEST_RC
Result Published     0                  0            0
"#9689ba467a19cd19 #1
select /*+ result_cache */ cou Result          Invalid                  1                0            0
nt(*) from test_rc
select /*+ result_cache */ cou Result          Invalid                 0                 0             0
nt(*) from test_rc
"HR"."F_TEST_RC"::8."F_TEST_RC Result Invalid           0                 0              0 "#9689ba467a19cd19 #1

6 rows selected.

INST_ID EQ_T  TOTAL_REQ#  TOTAL_WAIT# SUCC_REQ# FAILED_REQ# CUM_WAIT_TIME
------ ------ -------------- ------------- ------------ -------------- ----------------
      1       RC                   11                  0                11                     0                      0


위와 같이 새로이 등록됨을 확인 할 수 있다. Invalidation 되는 경우가 많지 않은 경우에 Result Cache를 사용해야지 그렇지 않을 경우 다른 Result Cache 데이터 까지 age out 되어서 불 필요한 RC enqueue 및 Result Cache latch 경합이 발생할 소지가 높다.


그러면 특정 한 Result를 keep 시키는 명령어는 존재를 할 것인가 ? 아쉽게도 dbms_result_cache 패키지로는 불가능 하다.


여기까지 RC Enqueue 는 Result Cache에 대한 등록 및 변경 작업이 있을 경우 획득하는 lock임을 확인 할 수 있었고, 잦은 DML이 발생하는 테이블에 대해서는 Result Cache를 사용하지 말아야 한다는 것을 테스트를 통해 확인 할 수 있었다.


추후 특정 Result Cache 에 대해서 keep 시킬 수 있는 방법을 알게 된다면 추가 하도록 하겠다.




반응형

+ Recent posts