direct path read/write (直接路徑讀/寫)


轉載:http://www.dbtan.com/2010/04/direct-path-readwrite.html

direct path read/write (直接路徑讀/寫):

直接路徑讀(direct path read)通常發生在Oracle直接讀數據到進程PGA時,這個讀取不需要經過SGA。直接路徑讀等待事件的3個參數分別是file number(指絕對文件號)、first dba、block cnt數量。在Oracle 10g/11g中,這個等待事件被歸於User I/O一類。

db file sequential read、db file scattered read、direct path read是常見的集中數據讀方式,下圖簡要描述了這3種方式的讀取示意。

DB file Sequential ReadDB file Scattered ReadDirect Path Read 

這類讀取通常在以下情況被使用:
·磁盤排序IO操作;
·並行查詢從屬進程;
·預讀操作。

最為常見的是第一種情況。在DSS系統中,存在大量的direct path read是很正常的,但是在OLTP系統中,通常顯著的直接路徑讀(direct path read)都意味着系統應用存在問題,從而導致大量的磁盤排序讀取操作。

直接路徑寫(direct paht write)通常發生在Oracle直接從PGA寫數據到數據文件或臨時文件,這個寫操作可以繞過SGA。直接路徑寫等待事件的3個參數分別是:file number(指絕對文件號)、first dba和block cnt數量,在Oracle 10g/11g中,這個等待事件同direct path read一樣被歸於User I/O一類。

這類寫入操作通常在以下情況被使用:
·直接路徑加載;
·並行DML操作;
·磁盤排序;
·對未緩存的“LOB”段的寫入,隨后會記錄為direct path write(lob)等待。

最為常見的直接路徑寫,多數因為磁盤排序導致。對於這一寫入等待,我們應該找到I/O操作最為頻繁的數據文件(如果有過多的排序操作,很有可能就是臨時文件),分散負載,加快其寫入操作。

1. 磁盤排序診斷:
如果系統存在過多的磁盤排序,會導致臨時表空間操作頻繁,對於這種情況,可以考慮為不同用戶分配不同的臨時表空間,使用多個臨時文件,寫入不同磁盤或者裸設備,從而降低競爭,提高性能;對於Oracle 8i的數據庫,應該考慮使用本地管理(Local)的臨時表空間,而不是字典(dictionary)管理。

對於這種情況,在Oracle 9i之前,可以適當增加sort_area_size的大小;從Oracle 9i開始,可以適當增大pga_aggregate_target,以縮減磁盤排序對於磁盤的寫入,從而提高系統及應用響應。但是通常應該及時檢查應用,確認是否因為應用問題導致了過度排序,從而根本上解決問題。

2. 並行查詢導致性能問題:
有時候在應用系統中,不正確的使用並行查詢也會導致應用問題。Statspack的Top 5時間事件輸出顯示direct path read消耗了較高的等待時,而內存排序率很高甚至是100%(In-memory Sort %:100.00)顯然這里的Direct Path Read並不是由於排序引發的,注意到另外一個等待事件(KJC: Wait for msg sends to complete)和並行有關,所以初步判斷這里的direct path read可能和並行有關。

    注:在Statspack的報告中,存在一個性能指標,稱為內存排序率(In-memory Sort Ratio),用於衡量系統的排序操作,這個指標就是由兩個統計信息sorts (disk)和sorts (memory)得出:
    In-memory Sort Ratio = sorts (memory) / [sorts (disk) + sorts (memory)]

進一步檢查Statspack報告中的SQL部分,發現大量並行查詢改寫出來的SQL,這些SQL通過內部提示(Hints)固化其執行路徑。

在很多情況下,並行也許並不是最好的選擇,如果表並不大,並行反而會降低其執行速度。

通過查詢dba_tables字典表可以獲得degree並行度的記錄,並行度大於1的數據表在查詢時會啟用並行,但是注意事實還會有所不同,degree字段的類型及長度是VARCHAR2(10)。所以注意,當使用類似查詢時,可能無法獲得返回值:

sys@CCDB> select table_name from dba_tables where degree = '1' or degree = 'DEFAULT';
no rows selected

我們看一下degree以及instances的記錄方式:

sys@CCDB> select degree,length(degree) from dba_tables group by degree;
DEGREE          LENGTH(DEGREE)
--------------- --------------
         1                  10
sys@CCDB> select instances,length(instances) from dba_tables group by instances;
INSTANCES       LENGTH(INSTANCES)
--------------- -----------------
         1                     10
         0                     10

degreee和instances實際上記錄了10個字符,左端用空格補齊。在dba_tables的創建語句中,可以找到根本原因,以下是這兩個字段的定義來源:

    lpad(decode(t.degree, 32767, 'DEFAULT', nvl(t.degree,1)),10),
    lpad(decode(t.instances, 32767, 'DEFAULT', nvl(t.instances,1)),10),

而需要注意的是,如果degree設置為DEFAULT,則默認數據庫會對該表啟用並行。

最后找到相關的SQL,從AUTOTRACE可以看到這些SQL的執行計划,查看涉及數據表的並行度,注意是否有被設置為DEFAULT的表。

將表的並行度修改為1后,問題得以解決:

alter table <table_name> parallel 1;

這個問題給我們的啟示是:並行並不總是能夠到來性能提升。

3. 磁盤排序與臨時文件:
在Oracle 10g/11g中,為了區分特定的對於臨時文件的直接讀寫操作,Oracle對direct path read/write進行了分離,將這類操作分列出來:

sys@CCDB> select event#,name,wait_class
  2  from v$event_name
  3  where name like 'direct%';
    EVENT# NAME                      WAIT_CLASS
---------- ------------------------- ---------------
       177 direct path read          User I/O
       178 direct path read temp     User I/O
       179 direct path write         User I/O
       180 direct path write temp    User I/O

可以看到,現在的direct path read/write temp就是單指對於臨時文件的直接讀寫操作。結合Oracle 10g的一些特性,來進一步研究一下直接路徑讀/寫與臨時文件。
首先在一個session中執行一個能夠引發磁盤排序的查詢:

tq@CCDB> select sid from v$mystat where rownum <2;
       SID
----------
      1066
tq@CCDB> select a.table_name,b.object_name,b.object_type
  2  from t1 a,t2 b
  3  where a.table_name = b.object_name
  4  order by b.object_name,b.object_type;

在另外sessoin查詢相應等待事件:

tq@CCDB> select event,p1text,p1,p2text,p2,p3text,p3
  2  from v$session_wait_history
  3  where sid = 1066;
EVENT                    P1TEXT             P1 P2TEXT            P2 P3TEXT            P3
------------------------ ------------- ------- ------------ ------- ------------ -------
direct path read temp    file number       201 first dba     313512 block cnt         31
direct path read temp    file number       201 first dba     313481 block cnt         31
direct path read temp    file number       201 first dba     386887 block cnt         31
direct path read temp    file number       201 first dba     317736 block cnt         31
direct path read temp    file number       201 first dba     317193 block cnt         31
direct path read temp    file number       201 first dba     316646 block cnt         31
direct path read temp    file number       201 first dba     316134 block cnt         31
direct path read temp    file number       201 first dba     315622 block cnt         31
direct path read temp    file number       201 first dba     315079 block cnt         31
direct path read temp    file number       201 first dba     314567 block cnt         31
10 rows selected.

從以上輸出可以看到最近10次等待,direct path read temp就是這個查詢引起的磁盤排序。注意這里的file number為201。而實際上,通過v$tempfile來查詢,臨時文件的文件號僅為1:

tq@CCDB> select file#,name from v$tempfile;
     FILE# NAME
---------- -----------------------------------------
         1 /oracle/oradata/ccdb/ccdb/temp01.dbf

如果通過10046事件跟蹤,也可以獲得類似的結果:

WAIT #3: nam='direct path write temp' ela= 1 file number=201 first dba=437862 block cnt=31 obj#=112141 tim=1270780
330976998
WAIT #3: nam='direct path write temp' ela= 1 file number=201 first dba=437416 block cnt=31 obj#=112141 tim=1270780
330977070
WAIT #3: nam='direct path read temp' ela= 7 file number=201 first dba=438471 block cnt=31 obj#=112141 tim=12707803
30982214
WAIT #3: nam='direct path read temp' ela= 4 file number=201 first dba=438502 block cnt=31 obj#=112141 tim=12707803
30983765
WAIT #3: nam='direct path read temp' ela= 8 file number=201 first dba=387015 block cnt=31 obj#=112141 tim=12707803
30993872

在Oracle文檔中,file#被定義為絕對文件號(The Absolute File Number)。這里的原因何在呢?研究這個問題要先研究一下v$tempseg_usage這個視圖,可以從這個視圖出發動手研究一下這個對象究竟來自何方。

查詢dba_objects視圖,發現v$tempseg_usage原來是一個同義詞。

sys@CCDB> select object_type from dba_objects where object_name = 'V$TEMPSEG_USAGE'; 
OBJECT_TYPE
-------------------
SYNONYM

再追本溯源原來v$tempseg_usage是v_$sort_usage的同義詞,也就是和v$sort_usage同源。從Oracle 9i開始,Oracle將v$sort_usage視圖從文檔中移除了,因為這個名稱有所歧義,容易使人誤解僅記錄排序內容,所以v$tempseg_usage視圖被引入,用於記錄臨時段的使用情況:

sys@CCDB> select * from dba_synonyms where synonym_name = 'V$TEMPSEG_USAGE';
OWNER      SYNONYM_NAME         TABLE_OWNER     TABLE_NAME      DB_LINK
---------- -------------------- --------------- --------------- ----------
PUBLIC     V$TEMPSEG_USAGE      SYS             V_$SORT_USAGE

如果再進一步,可以看到這個視圖的構建語句:

sys@CCDB> select view_definition from v$fixed_view_definition 
  2  where view_name = 'GV$SORT_USAGE';                  
VIEW_DEFINITION
--------------------------------------------------------------------------------
select x$ktsso.inst_id, username, username, ktssoses, ktssosno, prev_sql_addr, p
rev_hash_value, prev_sql_id, ktssotsn, decode(ktssocnt, 0, 'PERMANENT', 1, 'TEMP
ORARY'), decode(ktssosegt, 1, 'SORT', 2, 'HASH', 3, 'DATA', 4, 'INDEX', 5, 'LOB_
DATA', 6, 'LOB_INDEX' , 'UNDEFINED'), ktssofno, ktssobno, ktssoexts, ktssoblks,
ktssorfno from x$ktsso, v$session where ktssoses = v$session.saddr and ktssosno
= v$session.serial#

格式化一下,v$sort_usage的創建語句如下:

SELECT   x$ktsso.inst_id,username,username,ktssoses,ktssosno,
         prev_sql_addr,prev_hash_value,prev_sql_id,ktssotsn,
         DECODE (ktssocnt,
                 0,'PERMANENT',
                 1,'TEMPORARY'),
         DECODE (ktssosegt,
                 1, 'SORT',
                 2, 'HASH',
                 3, 'DATA',
                 4, 'INDEX',
                 5, 'LOB_DATA',
                 6, 'LOB_INDEX',
                 'UNDEFINED'),
         ktssofno,ktssobno,
         ktssoexts,ktssoblks,ktssorfno
  FROM   x$ktsso, v$session
WHERE   ktssoses = v$session.saddr AND ktssosno = v$session.serial#;

注意到在Oracle文檔中對v$sort_usage字段SEGFILE#的定義為:

SEGFILE#    NUMBER        File number of initial extent

 

在視圖中,這個字段來自x$ktsso.ktssofno,也就是說這個字段實際上代表的是絕對文件號。那么這個絕對文件號如何與臨時文件關聯呢?能否與v$tempfile中的file#字段關聯呢?

再來看一下v$tempfile的來源,v$tempfile由如下語句創建:

sys@CCDB> select view_definition from v$fixed_view_definition
  2  where view_name = 'GV$TEMPFILE';
VIEW_DEFINITION
--------------------------------------------------------------------------------
select tf.inst_id, tf.tfnum, to_number(tf.tfcrc_scn), to_date(tf.tfcrc_tim,'MM/D
D/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'), tf.tftsn, tf.tfrfn, decode(bitand(tf
.tfsta, 2),0,'OFFLINE',2,'ONLINE','UNKNOWN'), decode(bitand(tf.tfsta, 12), 0,'DI
SABLED',4, 'READ ONLY', 12, 'READ WRITE',
                           'UNKNOWN'), fh.fhtmpfsz*tf.tfbsz, fh.fhtmpfsz,  tf.tf
csz*tf.tfbsz,tf.tfbsz, fn.fnnam  from x$kcctf tf, x$kccfn fn, x$kcvfhtmp fh  whe
re fn.fnfno=tf.tfnum and fn.fnfno=fh.htmpxfil and tf.tffnh=fn.fnnum  and tf.tfdu
p!=0 and bitand(tf.tfsta, 32) <> 32  and fn.fntyp=7 and fn.fnnam is not null

格式化v$tempfile如下:

SELECT   tf.inst_id,tf.tfnum,TO_NUMBER (tf.tfcrc_scn),
         TO_DATE (tf.tfcrc_tim,'MM/DD/RR HH24:MI:SS','NLS_CALENDAR=Gregorian'),
         tf.tftsn,tf.tfrfn,
         DECODE (BITAND (tf.tfsta, 2), 0, 'OFFLINE', 2, 'ONLINE', 'UNKNOWN'),
         DECODE (BITAND (tf.tfsta, 12),
                 0, 'DISABLED',
                 4, 'READ ONLY',
                 12, 'READ WRITE',
                 'UNKNOWN'),
         fh.fhtmpfsz * tf.tfbsz,fh.fhtmpfsz,tf.tfcsz * tf.tfbsz,tf.tfbsz,fn.fnnam
  FROM   x$kcctf tf, x$kccfn fn, x$kcvfhtmp fh
WHERE       fn.fnfno = tf.tfnum
         AND fn.fnfno = fh.htmpxfil
         AND tf.tffnh = fn.fnnum
         AND tf.tfdup != 0
         AND BITAND (tf.tfsta, 32) <> 32
         AND fn.fntyp = 7
         AND fn.fnnam IS NOT NULL;

考察x$kcctf底層表,注意到TFAFN(Temp File Absolute File Number)在這里存在

sys@CCDB> desc x$kcctf
Name             Null?    Type
---------------- -------- ----------------
ADDR                      RAW(8)
INDX                      NUMBER
INST_ID                   NUMBER
TFNUM                     NUMBER
TFAFN                     NUMBER
TFCSZ                     NUMBER
TFBSZ                     NUMBER
TFSTA                     NUMBER
TFCRC_SCN                 VARCHAR2(16)
TFCRC_TIM                 VARCHAR2(20)
TFFNH                     NUMBER
TFFNT                     NUMBER
TFDUP                     NUMBER
TFTSN                     NUMBER
TFTSI                     NUMBER
TFRFN                     NUMBER
TFPFT                     NUMBER
TFMSZ                     NUMBER
TFNSZ                     NUMBER

而這個字段在構建v$tempfile時並未出現,所以不能通過v$sort_usage和v$tempfile直接關聯絕對文件號。可以簡單構建一個排序段使用,然后來繼續研究一下:

sys@CCDB> select username,segtype,segfile#,segblk#,extents,segrfno# from v$sort_usage;
USERNAME     SEGTYPE     SEGFILE#    SEGBLK#    EXTENTS   SEGRFNO#
------------ --------- ---------- ---------- ---------- ----------
SYS          LOB_DATA         201     340361          1          1

看到這里的SEGFILE#=201,而在v$tempfile是找不到這個信息的:

sys@CCDB> select file#,rfile#,ts#,status,blocks from v$tempfile;
     FILE#     RFILE#        TS# STATUS      BLOCKS
---------- ---------- ---------- ------- ----------
         1          1          3 ONLINE      443520

但是可以從x$kcctf中獲得這些信息,v$tempfile.file#實際上來自x$kcctf.tfnum,是臨時文件的文件號而絕對文件號是x$kcctf.tfafn,這個字段才可以與v$sort_usage.segfile#關聯

sys@CCDB> select indx,tfnum,tfafn,tfcsz from x$kcctf;
      INDX      TFNUM      TFAFN      TFCSZ
---------- ---------- ---------- ----------
         0          1        201       2560

再進一步可以知道,實際上,為了分離臨時文件號和數據文件號,Oracle對臨時文件的編號以db_files為起點,所以臨時文件的絕對文件號應該等於db_files+file#

db_files參數的缺省值為200:

sys@CCDB> show parameter db_files
NAME          TYPE           VALUE
------------- -------------- -----------
db_files      integer        200
sys@CCDB> select file#,name from v$tempfile;
     FILE# NAME
---------- ---------------------------------------------
         1 /oracle/oradata/ccdb/ccdb/temp01.dbf

所以在Oracle文檔中v$tempfile.file#被定義為The absolute file number是不確切的。

- The End -


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM