Тема неновая, относится к “бородатым” новым фичам Oracle 11g, однако, технология хорошо работающая и, что важно, позволяющая при определённых условиях, существенно экономить ресурсы сервера RDBMS
Далее привожу результаты успешного практического применения кэша результатов запроса для ресурсоёмкого частовыполняемого (т.е. выполняющегося чаще, чем обновляются данные) запроса, оптимизировать который другим методом было бы объективно непросто – встречаются запросы, которые просто обязаны много читать :)
Практическая часть
По умолчанию режим RESULT CACHE ручной (до 11.2.0.3 включительно), регулируется параметром result_cache_mode на уровне сессии/системы и/или подсказкой /*+ RESULT_CACHE*/ на уровне запроса:
Connected to:
Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
11.1.0.7@SQL> @param result_cache_mode
NAME VALUE IS_DEF IS_MOD DSC
------------------ ------- -------- ---------- --------------------------------
result_cache_mode MANUAL TRUE FALSE result cache operator usage mode
11.1.0.7@SQL> @pvalid result_cache_mode
Valid values for parameters %result_cache_mode%
PARAMETER ORD VALUE DEFAULT
------------------ ---------- ------------------------------ -------
result_cache_mode 1 AUTO
2 MANUAL DEFAULT
3 FORCE
Режимы MANUAL и FORCE интуитивно понятны, смысл значения AUTO объясняется в Is Initialization Parameters “Result_cache_mode=Auto” supported in 11.1 and 11.2 ? [ID 1345119.1]:
With AUTO option it decides if the result_cache needs to be enabled based on the costing in oracle internal function. With this mode the decision to use result_cache is purely cost based
- красиво задумано – автоматическое включение кэширования результатов запросов в зависимости от стоимости выполнения (CBO), также было бы логично учитывать частоту выполнения запроса и частоту изменений данных сегмента
Однако на практике мне не удалось заставить работать кэш в автоматическом режиме, несмотря на то, что план выполнения рапортовал об успешном применении кэша:
11.1.0.7@SQL> alter session set RESULT_CACHE_MODE='AUTO';
SQL> set autotrace traceonly exp stat
SQL> select ...
SQL>/
SQL>/
...
64176 rows selected.
Elapsed: 00:00:03.00
...
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5926 | 289K| 995 (3)| 00:00:14 | | |
| 1 | RESULT CACHE | 6v9x47h96p7hf7n2jqrw2utg3w | | | | | | |
| 2 | HASH UNIQUE | | 5926 | 289K| 995 (3)| 00:00:14 | | |
|* 3 | HASH JOIN | | 5926 | 289K| 994 (3)| 00:00:14 | | |
| 4 | NESTED LOOPS | | 10445 | 275K| 130 (4)| 00:00:02 | | |
|* 5 | INDEX RANGE SCAN | IDX_LINK | 678K| 11M| 126 (1)| 00:00:02 | | |
|* 6 | INDEX RANGE SCAN | IDX_ENTITY_BY_TYPE2 | 1 | 9 | 1 (0)| 00:00:01 | | |
| 7 | PARTITION LIST SINGLE| | 3612K| 79M| 845 (1)| 00:00:12 | KEY | KEY |
|* 8 | INDEX FULL SCAN | TEST_IDX1 | 3612K| 79M| 845 (1)| 00:00:12 | 1 | 1 |
-----------------------------------------------------------------------------------------------------------------------
Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=2; type=AUTO; dependencies=(ENTITY_ATTR, ENTITY, LINK); parameters=(nls); name="select distinct e.entity_id, ea.attr_as_str
from (select * from entity where entity_type_id = 4) e
join link ch_"
Statistics
----------------------------------------------------------
...
0 db block gets
25651 consistent gets
0 physical reads
...
64176 rows processed
- не уменьшающееся кол-во прочитанных блоков (25651 consistent gets) и большое время выполнения (3 сек) говорят об обратном – режим AUTO не работает, что давным-давно подтверждал Lutz Hartmann. No AUTO RESULT_CACHE_MODE!!! из инсайдерских источников:
The guys from Server Technologies told me that it will probably never work and will never be supported with AUTO
Коственно неработоспособность AUTO режима можно из системного обзора V$RESULT_CACHE_OBJECTS:
11.1@SYSTEM SQL> @rcache CACHE_ID STATUS SPACE CREATION_ DEPEND_COUNT BLOCK_COUNT COLUMN_COUNT ROW_COUNT BUILD_TIME ------------------------------ --------- ----- --------- ------------ ----------- ------------ ---------- ---------- 6v9x47h96p7hf7n2jqrw2utg3w Published AUTO 12-JAN-12 0 1 1 1 0
- странные значения количества зависимостей, блоков, строк и т.д. Будем надеяться, что красоту автоматического режима можно будет оценить в будущем (Oracle 12c ?)
Ручной режим работает отлично:
11.1.0.7@SQL> alter session set RESULT_CACHE_MODE='MANUAL';
Session altered.
11.1.0.7@SQL> select/*+ RESULT_CACHE*/
...
9 /
64176 rows selected.
Elapsed: 00:00:06.54
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5926 | 289K| 995 (3)| 00:00:14 | | |
| 1 | RESULT CACHE | 6v9x47h96p7hf7n2jqrw2utg3w | | | | | | |
| 2 | HASH UNIQUE | | 5926 | 289K| 995 (3)| 00:00:14 | | |
|* 3 | HASH JOIN | | 5926 | 289K| 994 (3)| 00:00:14 | | |
| 4 | NESTED LOOPS | | 10445 | 275K| 130 (4)| 00:00:02 | | |
|* 5 | INDEX RANGE SCAN | IDX_LINK | 678K| 11M| 126 (1)| 00:00:02 | | |
|* 6 | INDEX RANGE SCAN | IDX_ENTITY_BY_TYPE2 | 1 | 9 | 1 (0)| 00:00:01 | | |
| 7 | PARTITION LIST SINGLE| | 3612K| 79M| 845 (1)| 00:00:12 | KEY | KEY |
|* 8 | INDEX FULL SCAN | TEST_IDX1 | 3612K| 79M| 845 (1)| 00:00:12 | 1 | 1 |
-----------------------------------------------------------------------------------------------------------------------
Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=2; dependencies=(ENTITY_ATTR, ENTITY, LINK); parameters=(nls); name="select/*+ RESULT_CACHE*/ distinct e.entity_id, ea.attr_as_str
from (select * from .entity where entity_type_id = 4) e
j"
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
25651 consistent gets
0 physical reads
...
64176 rows processed
11.1.0.7@SQL> /
64176 rows selected.
Elapsed: 00:00:00.17
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
...
64176 rows processed
- при использовании хинта RESULT_CACHE последующие выполнения запроса используют кэш, заметно (до 0) снижая кол-во чтений из буферного кэша (и физических чтений, соответственно) и время выполнения – с 3 до 0,17 сек.
Кэшированные результаты занимают часть SGA – оттуда и читаются:
11.1.0.7@SQL> select free, object_id, count(*) from V$RESULT_CACHE_MEMORY group by free, object_id; FREE OBJECT_ID COUNT(*) ---- ---------- ---------- NO 2 1 NO 3 1 NO 77826 862
При этом данные обзора V$RESULT_CACHE_OBJECTS для ручного режима (SPACE=”SQL” – последняя строка) выглядят гораздо разумнее, чем для автоматического (SPACE=”AUTO” – предпоследняя строка, первые три строки – зависимости кэша):
11.1.0.7@SQL> @rcache CACHE_ID STATUS NAME SPACE CREATION_ DEPEND_COUNT BLOCK_COUNT COLUMN_COUNT SCAN_COUNT ROW_COUNT BUILD_TIME SPACE_UNUSED SPACE_OVERHEAD ------------------------------ --------- ---------------------------- ----- --------- ------------ ----------- ------------ ---------- ---------- ---------- ------------ -------------- SCOTT.LINK Published SCOTT.LINK 12-JAN-12 1 1 0 0 0 0 0 0 SCOTT.ENTITY Published SCOTT.ENTITY 12-JAN-12 1 1 0 0 0 0 0 0 SCOTT.ENTITY_ATTR Published SCOTT.ENTITY_ATTR 12-JAN-12 1 1 0 0 0 0 0 0 6v9x47h96p7hf7n2jqrw2utg3w Published AUTO 12-JAN-12 0 1 1 3 1 0 517 240 6v9x47h96p7hf7n2jqrw2utg3w Published select/*+ RESULT_CACHE*/... SQL 12-JAN-12 3 862 2 2 64176 199 510 21064
Статистика выполнения запроса (на боевой бд) с включённым на уровне запроса кэшем стала заметно лучше (интересно, что операция RESULT CACHE, появляющаяся в плане выполнения запроса с подсказкой RESULT_CACHE абсолютно “прозрачна” – plan_hash_value не меняется!):
11.1.0.7@SQL> select 2 sql_text, 3 executions, 4 round(buffer_gets/executions) as buffer_gets_per_exec, 5 round(rows_processed/executions) as rows_processed_per_exec, 6 round(cpu_time/executions) as cpu_time_per_exec, 7 round(elapsed_time/executions) as elapsed_time_per_exec 8 from v$sql 9 where plan_hash_value = 2376964164 --10 and is_shareable = 'Y' 11 / SQL_TEXT EXECUTIONS BUFFER_GETS_PER_EXEC ROWS_PROCESSED_PER_EXEC CPU_TIME_PER_EXEC ELAPSED_TIME_PER_EXEC ----------------------------- ---------- -------------------- ----------------------- ----------------- --------------------- select /*+ RESULT_CACHE*/ ... 35876 13493 64331 564718 934934 select ... 14276 940 64323 3665495 3827038
- по крайне мере, если судить по среднему времени выполнения, при этом статистика блоков BUFFER_GETS_PER_EXEC выглядит довольно забавно – видимо, из-за совпадения plan_hash_value :)
Значительное уменьшение времени выполнения подтверждаются данными AWR
Было без кэша:
Elapsed CPU Elap per % Total Time (s) Time (s) Executions Exec (s) DB Time SQL Id ---------- ---------- ------------ ---------- ------- ------------- 14,709 8,340 1,679 8.8 16.1 6tftx2f5714zp Module: b-p select ...
Стало с кэшем:
Elapsed CPU Elap per % Total Time (s) Time (s) Executions Exec (s) DB Time SQL Id ---------- ---------- ------------ ---------- ------- ------------- 2,652 1,621 1,401 1.9 4.0 a1vsm7td6hkac Module: b-p select /*+ RESULT_CACHE*/ ...
- запрос ушёл c 1-го места в топе по DB Time, среднее (Elap per exec) и суммарное (Elapsed Time) время выполнения уменьшилось в 4-5 раз за счёт того, что только один раз из четырёх или пяти запрос действительно вынужден выполняться из-за инвалидации кэша (изменений данных). В том же отчёте AWR появляется характерное блокировка/ожидание enq: RC – Result Cache: Contention:
Avg
%Time Total Wait wait Waits % DB
Event Waits -outs Time (s) (ms) /txn time
-------------------------- ------------ ----- ---------- ------- -------- ------
...
enq: RC - Result Cache: Co 390 0 938 2405 0.0 1.4
- с достаточно большим средним временем ~ 2,4 сек., и хотя ожиданий таких немало – 390 на 1401 выполнений запроса (Executions), время выполнение запроса, складывающееся из времен процессора и ожидания RC блокировки:
Elapsed Time (s) ~ CPU Time (s) + Total Wait Time (s)
2,652 ~ 1,621 + 938
в разы меньше времени выполнения того же запроса без использования кэша. Максимальное время ожидания от уже работающего запроса готовых результатов кэша результатов (enq: RC – Result Cache: Contention) ограничено параметром:
11.1.0.7@SQL> @param_ _result_cache_timeout NAME VALUE IS_DEF IS_MOD IS_ADJ DSC ---------------------- ------ -------- ---------- -------- ----------------------------------------------- _result_cache_timeout 10 TRUE FALSE FALSE maximum time (sec) a session waits for a result
- значение по умолчанию 10 секунд вполне разумно для запроса со средним временем выполнения 8 сек.
Статистика кэша:
11.1.0.7@SQL> select name, to_char(value) from V$RESULT_CACHE_STATISTICS; NAME TO_CHAR(VALUE) ------------------------------------------ ----- Block Size (Bytes) 1024 Block Count Maximum 41952 Block Count Current 2912 Result Size Maximum (Blocks) 2097 Create Count Success 8588 --Create Count Failure 687 Find Count 37318 --Invalidation Count 8587 --Delete Count Invalid 8585 --Delete Count Valid 0
Замечания и наблюдения
1. Кэш результатов инвалидируется при изменении любой партиции используемых в запросе таблиц, независимо от того используется ли эта партиция при выполнении запроса:
11.2.0.3.@SQL> create table scott.xxx_test
2 partition by list (object_type)
3 ( partition P001 values ('PACKAGE','PACKAGE BODY') tablespace users,
4 partition P002 values ('WINDOW') tablespace users,
5 partition PDEF values (default) tablespace users)
6 as select * from dba_objects
7 /
Table created.
11.2.0.3.@SQL> select/*+ RESULT_CACHE*/ count(*) from scott.xxx_test where object_type = 'PACKAGE';
----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 11 | 17 (0)| 00:00:01 | | |
| 1 | RESULT CACHE | 6q45ud3wadw905n6bskqvxu15f | | | | | | |
| 2 | SORT AGGREGATE | | 1 | 11 | | | | |
| 3 | PARTITION LIST SINGLE| | 1282 | 14102 | 17 (0)| 00:00:01 | KEY | KEY |
|* 4 | TABLE ACCESS FULL | XXX_TEST | 1282 | 14102 | 17 (0)| 00:00:01 | 1 | 1 |
----------------------------------------------------------------------------------------------------------------------
...
Result Cache Information (identified by operation id):
------------------------------------------------------
1 - column-count=1; dependencies=(SCOTT.XXX_TEST); attributes=(single-row); parameters=(nls); name="select/*+ RESULT_CACHE*/ count(*) from scott.xxx_test where object_type = 'PACKAGE'"
Statistics
----------------------------------------------------------
...
0 db block gets
152 consistent gets
77 physical reads
...
11.2.0.3.@SQL> /
...
Statistics
----------------------------------------------------------
...
0 db block gets
0 consistent gets
0 physical reads
...
- кэш создан и успешно используется для запроса, судя по плану Oracle знает, что запрос выполняется используя данные только одной партиции P001 таблицы XXX_TEST (PARTITION LIST SINGLE Pstart=1 Pstop=1), однако после изменения данных в партиции P002:
11.2.0.3.@SQL> update scott.xxx_test set object_id = object_id where object_type = 'WINDOW'; 9 rows updated. 11.2.0.3.@SQL> commit; Commit complete. 11.2.0.3.@SQL> select/*+ RESULT_CACHE*/ count(*) from scott.xxx_test where object_type = 'PACKAGE'; ... Statistics ---------------------------------------------------------- ... 0 db block gets 80 consistent gets 0 physical reads ...
- судя по ненулевому значению consistent gets кэш не используется, что точно отражено в обзоре V$RESULT_CACHE_OBJECTS:
11.2.0.3.@SQL> @rcache 6q45ud3wadw905n6bskqvxu15f
ID CACHE_ID STATUS NAME SPACE TIMESTAMP
---------- ------------------------------ --------- ------------------------------ ----- -------------------
119 6q45ud3wadw905n6bskqvxu15f Invalid select/*+ RESULT_CACHE*/ ... SQL 18.01.2012 17:09:50
120 6q45ud3wadw905n6bskqvxu15f Published select/*+ RESULT_CACHE*/ ... SQL 18.01.2012 17:10:29
- старый кэш инвалидирован (Invalid), новый – создан (Published)
2. Интенесным представляется кэширование данных “удалённых” (реально или через loopback db link) таблиц / обзоров / материализованных представлений с помощью параметра result_cache_remote_expiration:
11.2.0.3.@SQL> @param result_cache_remote_expiration NAME VALUE IS_DEF IS_MOD DSC ------------------------------- ------ -------- ------- ------------------------------------------------------------ result_cache_remote_expiration 0 TRUE FALSE maximum life time (min) for any result using a remote object
- по умолчанию такое кэширование отключено, при включении результаты запросов к “удалённым” объектам успешно кэшируются независимо от изменений данных:
11.2.0.3.@SQL> create table xxx_t2 tablespace users as select 1 as object_id from dual; Table created. 11.2.0.3.@SQL> create or replace view remote_view as select * from xxx_test where object_id >100; View created. 11.2.0.3.@SQL> alter session set result_cache_remote_expiration=10; Session altered. 11.2.0.3.@SQL> select /*+ RESULT_CACHE*/ 2 count(*) 3 from remote_view@LOOPBACK.DB.LINK remote, xxx_t2 local 4 where remote.object_type = 'PACKAGE' 5 and remote.object_id > local.object_id; Elapsed: 00:00:00.18 -------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT| -------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 27 | 203 (3)| 00:00:03 | | | | 1 | RESULT CACHE | 26r80qavk9msp1y346aymbsd3j | | | | | | | | 2 | SORT AGGREGATE | | 1 | 27 | | | | | | 3 | MERGE JOIN | | 1560 | 42120 | 203 (3)| 00:00:03 | | | | 4 | SORT JOIN | | 1 | 3 | 3 (34)| 00:00:01 | | | | 5 | TABLE ACCESS FULL| XXX_T2 | 1 | 3 | 2 (0)| 00:00:01 | | | |* 6 | SORT JOIN | | 1560 | 37440 | 200 (2)| 00:00:03 | | | | 7 | REMOTE | REMOTE_VIEW | 1560 | 37440 | 198 (2)| 00:00:03 | LOOPB~ | R->S | -------------------------------------------------------------------------------------------------------------------- Statistics ---------------------------------------------------------- ... 0 db block gets 2 consistent gets 0 physical reads ... 11.2.0.3.@SQL> @rcache 26r80qavk9msp1y346aymbsd3j ID CACHE_ID STATUS NAME SPACE TIMESTAMP DEPEND_COUNT BLOCK_COUNT COLUMN_COUNT SCAN_COUNT ROW_COUNT ---------- ------------------------------ --------- ------------------------------ ----- ------------------- ------------ ----------- ------------ ---------- ---------- 36 26r80qavk9msp1y346aymbsd3j Published select /*+ RESULT_CACHE*/ SQL 28.01.2012 12:03:50 1 1 1 0 1 11.2.0.3.@SQL> update xxx_test set object_id = object_id - 1 where object_type='PACKAGE'; 1398 rows updated. 11.2.0.3.@SQL> commit; Commit complete. 11.2.0.3.@SQL> select /*+ RESULT_CACHE*/ 2 count(*) 3 from remote_view@LOOPBACK.DB.LINK remote, xxx_t2 local 4 where remote.object_type = 'PACKAGE' 5 and remote.object_id > local.object_id; Elapsed: 00:00:00.01 ... Statistics ---------------------------------------------------------- ... 0 db block gets 0 consistent gets 0 physical reads 11.2.0.3.@SQL> @rcache 26r80qavk9msp1y346aymbsd3j ID CACHE_ID STATUS NAME SPACE TIMESTAMP DEPEND_COUNT BLOCK_COUNT COLUMN_COUNT SCAN_COUNT ROW_COUNT ---------- ------------------------------ --------- ------------------------------ ----- ------------------- ------------ ----------- ------------ ---------- ---------- 36 26r80qavk9msp1y346aymbsd3j Published select /*+ RESULT_CACHE*/ SQL 28.01.2012 12:03:50 1 1 1 1 1
- после обновления “удалённой” таблицы/обзора результаты запроса получаются из кэша – что видно по статистике consistent gets, счётчик V$RESULT_CACHE_OBJECTS.SCAN_COUNT соответственно увеличился до 1
Попутно стоит можно отметить, что использование кэша результатов (стимулируемое подсказкой RESULT_CACHE) не позволяет управлять стороной db link‘а, на которой будет выполняться запрос с помощью посказки DRIVING_SITE.
Без использования кэша выполнение запроса легко переносится на дальнюю сторону линка, становясь полность удалённым (SELECT STATEMENT REMOTE с доступом к локальной таблице XXX_T2 как к удалённой – строка 3):
11.2.0.3.@SQL> select--+ DRIVING_SITE(remote) 2 count(*) 3 from scott.xxx_test@LOOPBACK.DB.LINK remote, scott.xxx_t2 local 4 where remote.object_type = 'PACKAGE' 5 and remote.object_id > local.object_id; -------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop | Inst |IN-OUT| -------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT REMOTE | | 1 | 19 | 19 (0)| 00:00:01 | | | | | | 1 | SORT AGGREGATE | | 1 | 19 | | | | | | | | 2 | NESTED LOOPS | | 1398 | 26562 | 19 (0)| 00:00:01 | | | | | | 3 | REMOTE | XXX_T2 | 1 | 3 | 2 (0)| 00:00:01 | | | ! | R->S | | 4 | PARTITION LIST SINGLE| | 1398 | 22368 | 17 (0)| 00:00:01 | KEY | KEY | | | |* 5 | TABLE ACCESS FULL | XXX_TEST | 1398 | 22368 | 17 (0)| 00:00:01 | 1 | 1 | BALAN~ | | -------------------------------------------------------------------------------------------------------------------- Note ----- - fully remote statement
Попытка использовать кэш меняет план запроса на локальный с доступом к удалённой таблице (строка 7 плана), что логично с точки зрения локального размещения кэша:
11.2.0.3.@SQL> select--+ DRIVING_SITE(remote) RESULT_CACHE 2 count(*) 3 from scott.xxx_test@LOOPBACK.DB.LINK remote, scott.xxx_t2 local 4 where remote.object_type = 'PACKAGE' 5 and remote.object_id > local.object_id; -------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Inst |IN-OUT| -------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 27 | 203 (3)| 00:00:03 | | | | 1 | RESULT CACHE | 9hh2ndnycnhdg1sm4t42wv737t | | | | | | | | 2 | SORT AGGREGATE | | 1 | 27 | | | | | | 3 | MERGE JOIN | | 1560 | 42120 | 203 (3)| 00:00:03 | | | | 4 | SORT JOIN | | 1 | 3 | 3 (34)| 00:00:01 | | | | 5 | TABLE ACCESS FULL| XXX_T2 | 1 | 3 | 2 (0)| 00:00:01 | | | |* 6 | SORT JOIN | | 1560 | 37440 | 200 (2)| 00:00:03 | | | | 7 | REMOTE | XXX_TEST | 1560 | 37440 | 198 (2)| 00:00:03 | LOOPB~ | R->S | --------------------------------------------------------------------------------------------------------------------
Кроме стандартных ограничений использования (точнее, неиспользования) кэша результатов для запросов, содержащих:
- Temporary or Dictionary tables
- Nondeterministic PL/SQL functions
- Sequence CURRVAL and NEXTVAL
- SQL functions CURRENT_DATE,SYSDATE,SYS_GUID, and so on
, кэш не применяется при использовании в запросах любых объектов (включая db link’и) из схем SYS и SYSTEM
Полезная нота (с видео) Complete Reference To 11g New Feature : SQL Query Result Cache [Video] [ID 1108133.1]

