自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

索引掃描時(shí),對(duì)同一個(gè)葉子塊訪問(wèn)多次的原因初探

運(yùn)維 數(shù)據(jù)庫(kù)運(yùn)維
在觀察索引掃描會(huì)按何種次序進(jìn)行索引塊的訪問(wèn)時(shí),我發(fā)現(xiàn)了一種現(xiàn)象,即會(huì)有部分葉子塊被訪問(wèn)兩次或更多。以下是我自己對(duì)這種現(xiàn)象的重現(xiàn),以及對(duì)產(chǎn)生該現(xiàn)象原因的初步判斷。但截至目前,我并未找到有官方文檔對(duì)相關(guān)內(nèi)容的介紹。

[[397702]]

本文轉(zhuǎn)載自微信公眾號(hào)「數(shù)據(jù)和云」,作者趙勇。轉(zhuǎn)載本文請(qǐng)聯(lián)系數(shù)據(jù)和云公眾號(hào)。

在觀察索引掃描會(huì)按何種次序進(jìn)行索引塊的訪問(wèn)時(shí),我發(fā)現(xiàn)了一種現(xiàn)象,即會(huì)有部分葉子塊被訪問(wèn)兩次或更多。以下是我自己對(duì)這種現(xiàn)象的重現(xiàn),以及對(duì)產(chǎn)生該現(xiàn)象原因的初步判斷。但截至目前,我并未找到有官方文檔對(duì)相關(guān)內(nèi)容的介紹。因此,如果大家有不同的看法,或者可以提供相關(guān)的官方文檔介紹,也歡迎在文末留言區(qū)指正、討論和提供。

先創(chuàng)建以下測(cè)試環(huán)境,以重現(xiàn)相關(guān)現(xiàn)象。創(chuàng)建測(cè)試表,其中C1列為CHAR(256),目的是使該列占用字節(jié)數(shù)較多,使得后面在該列上創(chuàng)建索引時(shí),可以用較少的行數(shù)構(gòu)建出2層的索引。

  1. SQL> create table test0429 (id number,c1 char(256),v1 varchar2(256)); 
  2.  
  3. Table created. 

C1中插入的值為‘01’+254個(gè)空格,‘02’+254個(gè)空格…這樣的值。

  1. SQL> insert into test0429 select rownum id,lpad(rownum,2,'0') c1,rownum v1 from dual connect by rownum<=50; 
  2.  
  3. 50 rows created. 
  4.  
  5.  
  6. SQL> commit
  7.  
  8. Commit complete. 

在C1列上創(chuàng)建索引:

  1. SQL> create index ind_test0429_c1 on test0429(c1); 
  2.  
  3. Index created. 

查詢(xún)?cè)撍饕腛BJECT_ID,以便查看其樹(shù)形結(jié)構(gòu)。

  1. SQL> select object_id,object_name,object_type from user_objects where object_name='IND_TEST0429_C1'
  2.  
  3.  OBJECT_ID OBJECT_NAME                 OBJECT_TYPE 
  4. ---------- ----------------------------------- ------------------- 
  5.      97504 IND_TEST0429_C1             INDEX 
  6.  
  7.  
  8. SQL> alter session set events 'immediate trace name treedump level 97504'
  9.  
  10. Session altered. 
  11.  
  12. SQL> select * from v$diag_info; 
  13.  
  14.    INST_ID NAME 
  15. ---------- ---------------------------------------------------------------- 
  16. VALUE 
  17. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  18.      1 Diag Enabled 
  19. TRUE 
  20.  
  21.      1 ADR Base 
  22. /oradata/app/oracle 
  23.  
  24.      1 ADR Home 
  25. /oradata/app/oracle/diag/rdbms/orcl/orcl 
  26.  
  27.      1 Diag Trace 
  28. /oradata/app/oracle/diag/rdbms/orcl/orcl/trace 
  29.  
  30.      1 Diag Alert 
  31. /oradata/app/oracle/diag/rdbms/orcl/orcl/alert 
  32.  
  33.      1 Diag Incident 
  34. /oradata/app/oracle/diag/rdbms/orcl/orcl/incident 
  35.  
  36.      1 Diag Cdump 
  37. /oradata/app/oracle/diag/rdbms/orcl/orcl/cdump 
  38.  
  39.      1 Health Monitor 
  40. /oradata/app/oracle/diag/rdbms/orcl/orcl/hm 
  41.  
  42.      1 Default Trace File 
  43. /oradata/app/oracle/diag/rdbms/orcl/orcl/trace/orcl_ora_2751.trc 
  44.  
  45.      1 Active Problem Count 
  46.  
  47.      1 Active Incident Count 
  48. 17 
  49.  
  50.  
  51. 11 rows selected. 

在對(duì)應(yīng)的跟蹤文件中,看到的索引結(jié)構(gòu)為1個(gè)根節(jié)點(diǎn),2個(gè)葉子節(jié)點(diǎn)。如下所示:

  1. ----- begin tree dump 
  2. branch: 0x180414b 25182539 (0: nrow: 2, level: 1) 
  3.    leaf: 0x180414c 25182540 (-1: nrow: 26 rrow: 26) 
  4.    leaf: 0x180414d 25182541 (0: nrow: 24 rrow: 24) 
  5. ----- end tree dump 

查詢(xún)根節(jié)點(diǎn)和最左側(cè)葉子節(jié)點(diǎn)的數(shù)據(jù)塊所在文件塊及塊號(hào),準(zhǔn)備DUMP其數(shù)據(jù)塊,以便查看其中的內(nèi)容。

  1. SQL> select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('&&p3_value','xxxxxxxx')) FILE#, 
  2.        DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('&&p3_value','xxxxxxxx')) BLOCK# 
  3. from dual;  2    3   
  4. Enter value for p3_value: 180414b 
  5. old   1: select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('&&p3_value','xxxxxxxx')) FILE#, 
  6. new   1: select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('180414b','xxxxxxxx')) FILE#, 
  7. old   2:    DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('&&p3_value','xxxxxxxx')) BLOCK# 
  8. new   2:    DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('180414b','xxxxxxxx')) BLOCK# 
  9.  
  10.      FILE#     BLOCK# 
  11. ---------- ---------- 
  12.      6  16715 
  13.  
  14. SQL> undefine p3_value 
  15. SQL> select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('&&p3_value','xxxxxxxx')) FILE#, 
  16.        DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('&&p3_value','xxxxxxxx')) BLOCK# 
  17. from dual;   2    3   
  18. Enter value for p3_value: 180414c 
  19. old   1: select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('&&p3_value','xxxxxxxx')) FILE#, 
  20. new   1: select DBMS_UTILITY.DATA_BLOCK_ADDRESS_FILE(to_number('180414c','xxxxxxxx')) FILE#, 
  21. old   2:    DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('&&p3_value','xxxxxxxx')) BLOCK# 
  22. new   2:    DBMS_UTILITY.DATA_BLOCK_ADDRESS_BLOCK(to_number('180414c','xxxxxxxx')) BLOCK# 
  23.  
  24.      FILE#     BLOCK# 
  25. ---------- ---------- 
  26.      6  16716 

DUMP根塊和最左側(cè)葉子塊中的內(nèi)容到跟蹤文件中。

  1. SQL> alter system dump datafile 6 block min 16715 block max 16716; 
  2.  
  3. System altered. 

從跟蹤文件中,可以看到根塊中的主要內(nèi)容如下所示(為節(jié)省篇幅,以下只列出與本主題相關(guān)的主要內(nèi)容,以下其它類(lèi)似內(nèi)容亦做了相關(guān)處理,不再重復(fù)說(shuō)明):

  1. kdxcolev 1 
  2. KDXCOLEV Flags = - - - 
  3. kdxcolok 0 
  4. kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y 
  5. kdxconco 2 
  6. kdxcosdc 0 
  7. kdxconro 1 
  8. kdxcofbo 30=0x1e 
  9. kdxcofeo 8048=0x1f70 
  10. kdxcoavs 8018 
  11. kdxbrlmc 25182540=0x180414c 
  12. kdxbrsno 0 
  13. kdxbrbksz 8056 
  14. kdxbr2urrc 3 
  15. row#0[8048] dba: 25182541=0x180414d 
  16. col 0; len 2; (2):  32 37 
  17. col 1; TERM 
  18. ----- end of branch block dump ----- 

從上面的倒數(shù)第三行的內(nèi)容中可知,最右側(cè)的葉子塊中的最小索引鍵值為‘27’+254個(gè)空格。

從跟蹤文件中,可以看到最左側(cè)葉子塊中的主要內(nèi)容如下所示:

  1. kdxcolev 0 
  2. KDXCOLEV Flags = - - - 
  3. kdxcolok 0 
  4. kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y 
  5. kdxconco 2 
  6. kdxcosdc 0 
  7. kdxconro 26 
  8. kdxcofbo 88=0x58 
  9. kdxcofeo 1090=0x442 
  10. kdxcoavs 1002 
  11. kdxlespl 0 
  12. kdxlende 0 
  13. kdxlenxt 25182541=0x180414d 
  14. kdxleprv 0=0x0 
  15. kdxledsz 0 
  16. kdxlebksz 8032 
  17. row#0[7765] flag: ------, lock: 0, len=267 
  18. col 0; len 256; (256): 
  19.  30 31 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  20.  ...... 
  21.  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  22.  20 20 20 20 20 20 
  23. col 1; len 6; (6):  01 80 41 47 00 00 
  24. row#1[7498] flag: ------, lock: 0, len=267 
  25. col 0; len 256; (256): 
  26.  30 32 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  27.  ...... 
  28. row#25[1090] flag: ------, lock: 0, len=267 
  29. col 0; len 256; (256): 
  30.  32 36 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  31.  ...... 
  32.  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  33.  20 20 20 20 20 20 
  34. col 1; len 6; (6):  01 80 41 47 00 19 
  35. ----- end of leaf block dump ----- 
  36. End dump data blocks tsn: 7 file#: 6 minblk 16715 maxblk 16716 

為跟蹤索引數(shù)據(jù)塊被訪問(wèn)的情況,打開(kāi)10200跟蹤事件。

  1. SQL> alter session set events '10200 trace name context forever,level 1'
  2.  
  3. Session altered. 

查詢(xún)位于最左側(cè)葉子塊中的數(shù)據(jù),由于是等值查詢(xún),且C1列上無(wú)重復(fù)值,故以下查詢(xún)會(huì)返回1行。

  1. SQL> set lines 200 pages 60 
  2.  
  3. SQL> select c1 from test0429 where c1='01';                                                                      
  4.  
  5. C1 
  6. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  7. 01 

由于我們?cè)贑1列上創(chuàng)建的索引不是唯一索引,所以此時(shí),對(duì)索引的訪問(wèn)方法為索引范圍掃描。如下圖所示:

  1. SQL> select * from table(dbms_xplan.display_cursor('','','typical')); 
  2.  
  3. PLAN_TABLE_OUTPUT 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. SQL_ID  3kt1uqh283qbx, child number 0 
  6. ------------------------------------- 
  7. select c1 from test0429 where c1='01' 
  8.  
  9. Plan hash value: 1267036809 
  10.  
  11. ------------------------------------------------------------------------------------ 
  12. | Id  | Operation        | Name            | Rows  | Bytes | Cost (%CPU)| Time     | 
  13. ------------------------------------------------------------------------------------ 
  14. |   0 | SELECT STATEMENT |                 |       |       |     1 (100)|          | 
  15. |*  1 |  INDEX RANGE SCAN| IND_TEST0429_C1 |     1 |   257 |     1   (0)| 00:00:01 | 
  16. ------------------------------------------------------------------------------------ 
  17.  
  18.  
  19. Predicate Information (identified by operation id): 
  20. --------------------------------------------------- 
  21.  
  22.    1 - access("C1"='01'
  23.  
  24.  
  25. 18 rows selected. 

查看10200跟蹤文件中的輸出,我們可以看到先訪問(wèn)了索引根塊,然后訪問(wèn)了最左側(cè)的葉子塊。這是符合預(yù)期的。但我們可以看到,最左側(cè)的葉子塊訪問(wèn)了2次。

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 

之所以被訪問(wèn)兩次,我認(rèn)為其過(guò)程如下:

  1. 訪問(wèn)索引根塊,即訪問(wèn)“block <0x0007 : 0x0180414b>”;
  2. 由于條件值‘01’小于根塊中,指向第二個(gè)葉子塊的索引條目中的值‘27’,所以,需要訪問(wèn)索引最左側(cè)的葉子塊,即訪問(wèn)“<0x0007 : 0x0180414c>”;
  3. 在最左側(cè)的葉子塊中找到了第一行滿足條件的記錄ROW0。暫停繼續(xù)掃描,而將第一行返回;
  4. 繼續(xù)在最左側(cè)的葉子塊中查找是否有滿足條件的記錄。所以,會(huì)再次訪問(wèn)最左側(cè)的葉子塊;
  5. 在訪問(wèn)ROW1時(shí),得到了值‘02’+254個(gè)空格,該值大于‘01’,故整個(gè)索引中已不會(huì)再有滿足條件的記錄,所以,結(jié)束掃描,退出;
  6. 如果在葉子塊的掃描中,還能繼續(xù)找到滿足條件值的記錄,就不是每找到一行,就暫停掃描并返回當(dāng)前結(jié)果了,而是根據(jù)ARRAYSIZE中的值,每湊夠該參數(shù)指定的行數(shù),才會(huì)暫停掃描并返回結(jié)果,然后再繼續(xù)掃描。當(dāng)發(fā)生“再繼續(xù)掃描”這個(gè)動(dòng)作時(shí),相應(yīng)的葉子塊會(huì)被再一次訪問(wèn)。

針對(duì)6中所述,我們進(jìn)行如下測(cè)試。將ARRAYSIZE設(shè)置為3,即每湊夠3行即暫停掃描,返回結(jié)果。而該參數(shù)的默認(rèn)值為15。

  1. SQL> show arraysize 
  2. arraysize 15 
  3. SQL> set arraysize 3 
  4. SQL> show arraysize 
  5. arraysize 3 

執(zhí)行以下查詢(xún),應(yīng)該返回2行。

  1. SQL> select c1 from test0429 where c1<='02'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 01 
  6.  
  7.  
  8. 02 

其對(duì)數(shù)據(jù)塊的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 

執(zhí)行以下查詢(xún),會(huì)返回3行。

  1. SQL> select c1 from test0429 where c1<='03'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 01 
  6.  
  7.  
  8. 02 
  9.  
  10.  
  11. 03 

其對(duì)數(shù)據(jù)塊的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 

執(zhí)行以下查詢(xún),會(huì)返回4行。

  1. SQL> select c1 from test0429 where c1<='04'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 01 
  6.  
  7.  
  8. 02 
  9.  
  10.  
  11. 03 
  12.  
  13.  
  14. 04 

其對(duì)數(shù)據(jù)塊的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  4. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 

這里之所以會(huì)出現(xiàn)對(duì)最左側(cè)葉子塊的第三次訪問(wèn)。是因?yàn)楫?dāng)其返回第一行后,第二次訪問(wèn)葉子塊期間,找到了3行滿足條件的記錄。由于已達(dá)到了ARRAYSIZE的限制,所以,要暫停掃描,返回結(jié)果。然后再繼續(xù)掃描葉子塊中的剩余值,看看是否仍有滿足條件的記錄。因此,會(huì)出現(xiàn)對(duì)最左側(cè)葉子塊的第三次訪問(wèn)。

如果我們發(fā)出一條查詢(xún)最左側(cè)葉子塊中的最大值的SQL,又會(huì)是什么訪問(wèn)情況呢?

  1. SQL> select c1 from test0429 where c1='26'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 26 

我們可以看到是訪問(wèn)了全部三個(gè)索引塊,并且各訪問(wèn)了一次,沒(méi)有重復(fù)訪問(wèn)情況的發(fā)生。

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414d> objd: 0x00017ce0 

之所以發(fā)生這種情況,我認(rèn)為其原因是當(dāng)其從根塊中的指針,訪問(wèn)了最左側(cè)的葉子塊,找到一行滿足該條件的記錄。這時(shí),會(huì)如前所述,暫停繼續(xù)掃描,返回結(jié)果。然后繼續(xù)掃描,但由于在第一次的掃描中,已了解到了該索引條目是本索引塊中的最后一個(gè)索引條目,所以,就直接沿著最左側(cè)葉子塊上指向其后一個(gè)葉子塊的指針,訪問(wèn)了位于其右側(cè)的葉子塊,即訪問(wèn)了“block <0x0007 : 0x0180414d> ”。顯然,由于該塊中的ROW0已經(jīng)是‘27’+254個(gè)空格了,已經(jīng)大于了條件值‘26’,因此,結(jié)束查詢(xún)。

如果我們查詢(xún)的結(jié)果是存在于相鄰的兩個(gè)葉子塊中時(shí),其訪問(wèn)情況如下:在下面的查詢(xún)中,有兩行記錄位于最左側(cè)的葉子塊中,而一行記錄位于其右側(cè)的葉子塊中。

  1. SQL> select c1 from test0429 where c1>='25' and c1<='27'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 25 
  6.  
  7.  
  8. 26 
  9.  
  10.  
  11. 27 

其中索引塊的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  4. ktrget2(): started for block  <0x0007 : 0x0180414d> objd: 0x00017ce0 

而當(dāng)我們查詢(xún)的結(jié)果是存在于相鄰的兩個(gè)葉子塊中,并且會(huì)湊夠ARRAYSIZE參數(shù)所指定的3行時(shí),其訪問(wèn)情況會(huì)有變化。

  1. SQL> select c1 from test0429 where c1>='25' and c1<='28'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 25 
  6.  
  7.  
  8. 26 
  9.  
  10.  
  11. 27 
  12.  
  13.  
  14. 28 

這時(shí),我們觀察到的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017ce0 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017ce0 
  4. ktrget2(): started for block  <0x0007 : 0x0180414d> objd: 0x00017ce0 
  5. ktrget2(): started for block  <0x0007 : 0x0180414d> objd: 0x00017ce0 

如上所示,這里之所以會(huì)對(duì)位于右側(cè)的葉子塊訪問(wèn)2次,其原因是當(dāng)其訪問(wèn)右側(cè)的葉子塊,并獲取到滿足條件的‘27’和‘28’兩條記錄時(shí),此時(shí),已經(jīng)湊夠3條了(另1條是‘26’),所以,要暫停掃描,返回結(jié)果,然后繼續(xù)掃描。因此,這時(shí)會(huì)再次訪問(wèn)右側(cè)的葉子塊。

如果換成唯一索引,其訪問(wèn)行為,又會(huì)有一些差異。刪除原索引,仍在C1列上創(chuàng)建唯一索引。

  1. SQL> drop index ind_test0429_c1; 
  2.  
  3. Index dropped. 
  4.  
  5. SQL> create unique index ind_unique_test0429_c1 on test0429(c1); 
  6.  
  7. Index created. 

查看新的唯一索引OBJECT_ID,以便查看其索引樹(shù)形結(jié)構(gòu)。

  1. SQL> select object_id,object_name,object_type from user_objects where object_name='IND_UNIQUE_TEST0429_C1'
  2.  
  3.  OBJECT_ID OBJECT_NAME                 OBJECT_TYPE 
  4. ---------- ----------------------------------- ------------------- 
  5.      97521 IND_UNIQUE_TEST0429_C1          INDEX 
  6.  
  7. SQL> alter session set events 'immediate trace name treedump level 97521'
  8.  
  9. Session altered. 

如下所示,我們可以看到該結(jié)構(gòu)與此前的樹(shù)形結(jié)構(gòu)是相同的。

  1. branch: 0x180414b 25182539 (0: nrow: 2, level: 1) 
  2.    leaf: 0x180414c 25182540 (-1: nrow: 26 rrow: 26) 
  3.    leaf: 0x180414d 25182541 (0: nrow: 24 rrow: 24) 
  4. ----- end tree dump 

再次DUMP出根塊和最左側(cè)葉子塊中的內(nèi)容,如下所示:

  1. kdxcolev 1 
  2. KDXCOLEV Flags = - - - 
  3. kdxcolok 0 
  4. kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y 
  5. kdxconco 1 
  6. kdxcosdc 0 
  7. kdxconro 1 
  8. kdxcofbo 30=0x1e 
  9. kdxcofeo 8049=0x1f71 
  10. kdxcoavs 8019 
  11. kdxbrlmc 25182540=0x180414c 
  12. kdxbrsno 0 
  13. kdxbrbksz 8056 
  14. kdxbr2urrc 3 
  15. row#0[8049] dba: 25182541=0x180414d 
  16. col 0; len 2; (2):  32 37 

我們可以看到根塊中,顯示位于第二個(gè)葉子塊中的最小值的起始兩位是‘27’,而最左側(cè)葉子塊中的內(nèi)容如下,可以看到該塊中的最大值,仍然是‘26’+254個(gè)空格。

  1. kdxcolev 0 
  2. KDXCOLEV Flags = - - - 
  3. kdxcolok 0 
  4. kdxcoopc 0x80: opcode=0: iot flags=--- is converted=Y 
  5. kdxconco 1 
  6. kdxcosdc 0 
  7. kdxconro 26 
  8. kdxcofbo 88=0x58 
  9. kdxcofeo 1116=0x45c 
  10. kdxcoavs 1028 
  11. kdxlespl 0 
  12. kdxlende 0 
  13. kdxlenxt 25182541=0x180414d 
  14. kdxleprv 0=0x0 
  15. kdxledsz 6 
  16. kdxlebksz 8032 
  17. row#0[7766] flag: ------, lock: 0, len=266, data:(6):  01 80 41 47 00 00 
  18. col 0; len 256; (256): 
  19.  30 31 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  20.  ...... 
  21.  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  22.  20 20 20 20 20 20 
  23. row#1[7500] flag: ------, lock: 0, len=266, data:(6):  01 80 41 47 00 01 
  24. col 0; len 256; (256): 
  25.  30 32 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  26.  ...... 
  27. row#25[1116] flag: ------, lock: 0, len=266, data:(6):  01 80 41 47 00 19 
  28. col 0; len 256; (256): 
  29.  32 36 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  30.  ...... 
  31.  20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
  32.  20 20 20 20 20 20 
  33. ----- end of leaf block dump ----- 
  34. End dump data blocks tsn: 7 file#: 6 minblk 16715 maxblk 16716 

再次執(zhí)行只返回1行的查詢(xún)。

  1. SQL> select c1 from test0429 where c1='01'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 01 

但對(duì)索引的訪問(wèn)方法,已經(jīng)變?yōu)榱怂饕ㄒ粧呙瑁缦旅娴膱?zhí)行計(jì)劃所示:

  1. SQL> select * from table(dbms_xplan.display_cursor('','','typical')); 
  2.  
  3. PLAN_TABLE_OUTPUT 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. SQL_ID  3kt1uqh283qbx, child number 0 
  6. ------------------------------------- 
  7. select c1 from test0429 where c1='01' 
  8.  
  9. Plan hash value: 3124258820 
  10.  
  11. -------------------------------------------------------------------------------------------- 
  12. | Id  | Operation         | Name                   | Rows  | Bytes | Cost (%CPU)| Time     | 
  13. -------------------------------------------------------------------------------------------- 
  14. |   0 | SELECT STATEMENT  |                        |       |       |     1 (100)|          | 
  15. |*  1 |  INDEX UNIQUE SCAN| IND_UNIQUE_TEST0429_C1 |     1 |   257 |     1   (0)| 00:00:01 | 
  16. -------------------------------------------------------------------------------------------- 
  17.  
  18. Predicate Information (identified by operation id): 
  19. --------------------------------------------------- 
  20.  
  21.    1 - access("C1"='01'
  22.  
  23.  
  24. 18 rows selected. 

這時(shí)觀察到的對(duì)索引塊的訪問(wèn)情況如下:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017cf1  
  2. ktrgtc2(): started for block <0x0007 : 0x0180414c> objd: 0x00017cf1 

如上圖所示,我們可以看到,并沒(méi)有發(fā)生對(duì)最左側(cè)葉子塊的兩次訪問(wèn)。這是由于唯一索引的特性導(dǎo)致的。由于唯一索引中不會(huì)有重復(fù)值,所以,當(dāng)找到一行記錄,就不必再判斷是否還有其它滿足條件的記錄了。因?yàn)樵谖ㄒ凰饕?,要么沒(méi)有對(duì)應(yīng)條件值,要么就只會(huì)有一條。因此,找到一行后,就可以結(jié)束了。

如果我們對(duì)最左側(cè)葉子塊中的最大值做查詢(xún),其結(jié)果如下:

  1. SQL> select c1 from test0429 where c1='26'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 26 

如下所示,我們可以看到,仍然是訪問(wèn)2個(gè)索引塊。并且,不會(huì)去訪問(wèn)第二個(gè)葉子塊。

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017cf1 
  2. ktrgtc2(): started for block <0x0007 : 0x0180414c> objd: 0x00017cf1 

但是,當(dāng)執(zhí)行以下查詢(xún)時(shí),情況會(huì)發(fā)生變化。

  1. SQL> select c1 from test0429 where c1<='04'
  2.  
  3. C1 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. 01 
  6.  
  7.  
  8. 02 
  9.  
  10.  
  11. 03 
  12.  
  13.  
  14. 04 

由于WHERE子句中不是等值比較,所以,盡管是在唯一索引上的掃描,但訪問(wèn)方法又回到了索引范圍掃描的方法。如下所示:

  1. SQL> select * from table(dbms_xplan.display_cursor('','','typical')); 
  2.  
  3. PLAN_TABLE_OUTPUT 
  4. -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
  5. SQL_ID  9g9p54332fyd4, child number 0 
  6. ------------------------------------- 
  7. select c1 from test0429 where c1<='04' 
  8.  
  9. Plan hash value: 3622766470 
  10.  
  11. ------------------------------------------------------------------------------------------- 
  12. | Id  | Operation        | Name                   | Rows  | Bytes | Cost (%CPU)| Time     | 
  13. ------------------------------------------------------------------------------------------- 
  14. |   0 | SELECT STATEMENT |                        |       |       |     2 (100)|          | 
  15. |*  1 |  INDEX RANGE SCAN| IND_UNIQUE_TEST0429_C1 |     4 |  1028 |     2   (0)| 00:00:01 | 
  16. ------------------------------------------------------------------------------------------- 
  17.  
  18. Predicate Information (identified by operation id): 
  19. --------------------------------------------------- 
  20.  
  21.    1 - access("C1"<='04'
  22.  
  23.  
  24. 18 rows selected. 

而且,其訪問(wèn)索引塊的情況,也與此前在非唯一索引上訪問(wèn),并返回4行結(jié)果時(shí)的情形相同了。如下所示:

  1. ktrgtc2(): started for block <0x0007 : 0x0180414b> objd: 0x00017cf1 
  2. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017cf1 
  3. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017cf1 
  4. ktrget2(): started for block  <0x0007 : 0x0180414c> objd: 0x00017cf1 

關(guān)于作者

趙勇,云和恩墨北區(qū)SQL審核和優(yōu)化團(tuán)隊(duì)總監(jiān),從業(yè)超過(guò)20年,專(zhuān)職于SQL優(yōu)化與SQL質(zhì)量管控的服務(wù)工作,作為項(xiàng)目負(fù)責(zé)人和主要實(shí)施人員,深度融入金融、保險(xiǎn)、政府,運(yùn)營(yíng)商等多個(gè)行業(yè),結(jié)合行業(yè)系統(tǒng)特性,為客戶優(yōu)化了大量問(wèn)題SQL,同時(shí)也為運(yùn)營(yíng)商、銀行等客戶的核心系統(tǒng)提供SQL質(zhì)量審核服務(wù),助其防患于未然,為系統(tǒng)高質(zhì)量運(yùn)行提供保障。

 

責(zé)任編輯:武曉燕 來(lái)源: 數(shù)據(jù)和云
相關(guān)推薦

2016-12-15 08:54:52

線程sessionopenSession

2015-10-16 13:41:52

程序對(duì)象設(shè)計(jì)

2016-12-20 13:55:52

2009-06-09 12:38:12

NetBeanseclipse

2019-08-20 10:24:39

HTTPSSSHLinux

2009-11-20 17:10:43

Oracle B樹(shù)索引

2022-08-11 16:01:26

勒索軟件網(wǎng)絡(luò)攻擊

2021-08-16 20:48:34

嵌入式單片機(jī)信息

2024-09-05 16:01:55

2017-08-17 10:53:10

Google代碼倉(cāng)庫(kù)

2024-04-28 18:31:03

2022-07-26 00:00:02

TCPUDPMAC

2024-03-18 08:21:06

TCPUDP協(xié)議

2021-04-08 14:51:20

Python編碼語(yǔ)言

2024-03-05 10:07:22

TCPUDP協(xié)議

2023-09-13 13:05:01

Java項(xiàng)目

2015-11-12 15:14:48

ZD至頂網(wǎng)CIO與應(yīng)用

2019-01-28 09:43:21

IP地址子網(wǎng)掩碼

2019-07-09 14:42:17

SQLexplain索引

2024-11-29 09:41:17

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)