【Oracle】11g direct path read介紹:10949 event、_small_table_threshold與_serial_direct_read

轉自劉相兵老師的博文:

http://www.askmaclean.com/archives/11g-direct-path-read-10949-_small_table_threshold-_serial_direct_read.html

在11g之前串行的掃描大表默認總是先將數據讀取到Oracle高速緩衝中,其等待事件常爲db file scattered read。

 

從11g開始Oracle通過內部算法來決定串行掃描大表是通過直接路徑讀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。

 

direct path read的優勢:

 

 

1. 減少了對閂(latch)的使用,避免可能的閂爭用

 

2.物理IO的大小不再取決於buffer_cache中所存在的塊;試想某個8個塊的extent中1,3,5,7號塊在高速緩存中,而2,4,6,8塊沒有被緩存,傳統的方式在讀取該extent時將會是對2,4,6,8塊進行4次db file sequential

read,其效率往往要比單次讀取這個區間的所有8個塊還要低得多,Oracle爲了避免這種情況總是儘可能的不緩存大表的塊(讀入後總是放在隊列最冷的一端);而direct path read則可以完全避免這類問題,儘可能地單次讀入更多的物理塊。

 

 

當然直接路徑讀取也會引入一些缺點:

 

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’;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章