轉載自劉向兵老師:http://www.askmaclean.com/archives/11g-direct-path-read-10949-_small_table_threshold-_serial_direct_read.htmlhtml
在11g以前串行的掃描大表默認老是先將數據讀取到Oracle高速緩衝中,其等待事件常爲db file scattered read。算法
從11g開始Oracle經過內部算法來決定串行掃描大表是經過直接路徑讀direct path read,仍是先讀入到buffer cache中,此算法依據表的大小評估。數據庫
_small_table_threshold 隱藏參數指定了 ORACLE中大表的閥值,其單位爲block,即大於_small_table_threshold 所指定的塊數的表被視做大表,c#
否之視爲」small table」。 對於大表」large table」,SQL執行層認爲存在直接路徑讀取的意義(direct path read)。 對於小表,將它緩存在buffer cache中的收益更大,因此直接路徑讀取不具備意義。_small_table_threshold 隱藏參數的值在實例啓動時動態決定,通常爲 2% * DB_CACHE_SIZE。緩存
direct path read的優點:session
1. 減小了對閂(latch)的使用,避免可能的閂爭用oracle
2.物理IO的大小再也不取決於buffer_cache中所存在的塊;試想某個8個塊的extent中1,3,5,7號塊在高速緩存中,而2,4,6,8塊沒有被緩存,傳統的方式在讀取該extent時將會是對2,4,6,8塊進行4次db file sequentialide
read,其效率每每要比單次讀取這個區間的全部8個塊還要低得多,Oracle爲了不這種狀況老是儘量的不緩存大表的塊(讀入後老是放在隊列最冷的一端);而direct path read則能夠徹底避免這類問題,儘量地單次讀入更多的物理塊。spa
固然直接路徑讀取也會引入一些缺點:htm
1.即使在buffer cache足夠大到能夠放下整個大表的狀況下,direct path read沒法從高速緩衝受益,每次掃描大表均需重複等量的直接路徑物理讀取IO
2.在直接路徑讀取某段前須要對該對象進行一次段級的檢查點(A segment checkpoint).
3.可能致使重複的延遲塊清除操做
該11g自動判斷direct path read的特性適用場景:
1. 對大表不頻繁地串行全表掃描的場景
2. Db Cache Size高速緩衝大小遠小於表的大小的場景
不推薦在如下場景中開啓該11g自動判斷direct path read特性:
1. 從運行穩定的老版本(9i、10g)升級到11g的數據庫
2. 對大表頻繁地串行全表掃描的場景
SQL> select * from v$version;
BANNER
——————————————————————————–
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 – 64bit Production
PL/SQL Release 11.2.0.3.0 – Production
CORE 11.2.0.3.0 Production
TNS for Linux: Version 11.2.0.3.0 – Production
NLSRTL Version 11.2.0.3.0 – Production
col name for a30
col value for a20
col DESCRIB for a60
set linesize 140 pagesize 1400
SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV (‘Instance’)
AND y.inst_id = USERENV (‘Instance’)
AND x.indx = y.indx
AND (x.ksppinm =’_small_table_threshold’ or x.ksppinm=’_serial_direct_read’);
NAME VALUE DESCRIB
—————————— ——————– ————————————————————
_small_table_threshold 1143 lower threshold level of table size for direct reads
_serial_direct_read auto enable direct read in serial
其中_small_table_threshold 隱藏參數指定了 ORACLE中大表的閥值,其單位爲block,即大於_small_table_threshold 所指定的塊數的表被視做大表,
否之視爲」small table」。 對於大表」large table」,SQL執行層認爲存在直接路徑讀取的意義(direct path read)。 對於小表,將它緩存在buffer cache中的收益更大,因此直接路徑讀取不具備意義。
_small_table_threshold 隱藏參數的值在實例啓動時動態決定,通常爲 2% * DB_CACHE_SIZE。
SQL> alter system set db_cache_size=1024M scope=spfile;
System altered.
RESTART INSTANCE:
SQL> col name for a30
SQL> col value for a20
SQL> col DESCRIB for a60
SQL> set linesize 140 pagesize 1400
SQL>
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
2 FROM SYS.x$ksppi x, SYS.x$ksppcv y
3 WHERE x.inst_id = USERENV (‘Instance’)
4 AND y.inst_id = USERENV (‘Instance’)
5 AND x.indx = y.indx
6 AND (x.ksppinm =’_small_table_threshold’ or x.ksppinm=’_serial_direct_read’);
NAME VALUE DESCRIB
—————————— ——————– ————————————————————
_small_table_threshold 2522 lower threshold level of table size for direct reads
_serial_direct_read auto enable direct read in serial
2522 block = 2522 * 8k = = 19.7 M 約等於 1024 * 2%
SQL> create table tmac (t1 char(2000)) pctfree 99 pctused 1 tablespace users;
Table created.
SQL> insert into tmac select ‘MACLEAN’ from dual connect by level <=2530;
2530 rows created.
SQL> commit;
Commit complete.
SQL> exec dbms_stats.gather_table_stats(‘SYS’,’TMAC’);
PL/SQL procedure successfully completed.
SQL> select blocks from dba_tables where table_name=’TMAC’;
BLOCKS
———-
2638
SQL> alter system flush buffer_cache;
SQL> select count(*) from tmac;
COUNT(*)
———-
2530
SQL> select vm.sid, vs.name, vm.value
2 from v$mystat vm, v$sysstat vs
3 where vm.statistic# = vs.statistic#
4 and vs.name in (‘cleanouts only – consistent read gets’,
5 ‘session logical reads’,
6 ‘physical reads’,
7 ‘physical reads direct’);
SID NAME VALUE
———- —————————————————————- ———-
135 session logical reads 2859
135 physical reads 2763
135 physical reads direct 2576
135 cleanouts only – consistent read gets 0
physical reads direct 增長說明上面的查詢使用了direct path read
SQL> alter session set 「_serial_direct_read」=never;
Session altered.
SQL> select count(*) from tmac;
COUNT(*)
———-
2530
SQL> select vm.sid, vs.name, vm.value
2 from v$mystat vm, v$sysstat vs
3 where vm.statistic# = vs.statistic#
4 and vs.name in (‘cleanouts only – consistent read gets’,
5 ‘session logical reads’,
6 ‘physical reads’,
7 ‘physical reads direct’);
SID NAME VALUE
———- —————————————————————- ———-
135 session logical reads 5497
135 physical reads 5339
135 physical reads direct 2576
135 cleanouts only – consistent read gets 0
SQL> select count(*) from tmac;
COUNT(*)
———-
2530
SQL> select vm.sid, vs.name, vm.value
2 from v$mystat vm, v$sysstat vs
3 where vm.statistic# = vs.statistic#
4 and vs.name in (‘cleanouts only – consistent read gets’,
5 ‘session logical reads’,
6 ‘physical reads’,
7 ‘physical reads direct’);
SID NAME VALUE
———- —————————————————————- ———-
135 session logical reads 8135
135 physical reads 5339
135 physical reads direct 2576
135 cleanouts only – consistent read gets 0
physical reads direct 再也不增長說明以上2次查詢未使用direct path read
隱藏參數」_serial_direct_read」 指定了是否啓用串行全表掃描下的直接路徑讀取(direct path read),其默認值爲AUTO,設置爲NEVER時禁用11g自動direct path read的特性
SQL> alter session set 「_serial_direct_read」=auto;
Session altered.
還原session級別的_serial_direct_read 參數
SQL> delete tmac where rownum<2000;
1999 rows deleted.
SQL> commit;
Commit complete.
SQL> alter table tmac move tablespace users pctfree 10 pctused 90;
Table altered.
SQL> exec dbms_stats.gather_table_stats(‘SYS’,’TMAC’);
PL/SQL procedure successfully completed.
SQL> select blocks from dba_tables where table_name=’TMAC’;
BLOCKS
———-
189
將TMAC表縮小到 _small_table_threshold如下
SQL> alter system flush buffer_cache;
System altered.
SQL> select count(*) from tmac;
COUNT(*)
———-
531
SQL> select vm.sid, vs.name, vm.value
2 from v$mystat vm, v$sysstat vs
3 where vm.statistic# = vs.statistic#
4 and vs.name in (‘cleanouts only – consistent read gets’,
5 ‘session logical reads’,
6 ‘physical reads’,
7 ‘physical reads direct’);
SID NAME VALUE
———- —————————————————————- ———-
135 session logical reads 524
135 physical reads 349
135 physical reads direct 0
135 cleanouts only – consistent read gets 1
以上演示證實對於small table(塊數小於_small_table_threshold),SQL執行層自動並不決定使用direct path read,而是將之讀取到buffer cache中並邏輯讀。
結論:
其中_small_table_threshold 隱藏參數指定了 ORACLE中大表的閥值,其單位爲block,即大於_small_table_threshold 所指定的塊數的表被視做大表,
否之視爲」small table」。 對於大表」large table」,SQL執行層認爲存在直接路徑讀取的意義(direct path read)。 對於小表,將它緩存在buffer cache中的收益更大,因此直接路徑讀取不具備意義。
_small_table_threshold 隱藏參數的值在實例啓動時動態決定,通常爲 2% * DB_CACHE_SIZE。
隱藏參數」_serial_direct_read」 指定了是否啓用串行全表掃描下的直接路徑讀取(direct path read),其默認值爲AUTO,設置爲NEVER時禁用11g自動direct path read的特性
「As of 11.2.0.2 the legal settings are
true, false, always, auto, and never
true is the same effect as always
false is the same effect as auto
Default value is 「auto」
Setting event 10949 or event 10354 may also have the side effect of making oracle behave as if _serial_direct_read = never」
該參數能夠動態在實例或會話級別修改,而無需重啓實例。
相似的10949 EVENT事件也能夠起到相似的做用。
設置event 10949能夠避免採用直接路徑讀取方式,該事件能夠在線設置,但對現有session可能不會生效:
在實例級別設置:
ALTER SYSTEM SET EVENTS ‘10949 TRACE NAME CONTEXT FOREVER’;
設置到SPFILE中:
alter system set event=’10949 TRACE NAME CONTEXT FOREVER’ scope=spfile;
在session級別設置:
ALTER SESSION SET EVENTS ‘10949 TRACE NAME CONTEXT FOREVER’;
轉載自劉向兵老師:http://www.askmaclean.com/archives/11g-direct-path-read-10949-_small_table_threshold-_serial_direct_read.html