[20190815]索引快速全掃描的成本.txt

lfree發表於2019-08-16

[20190815]索引快速全掃描的成本.txt

--//昨天聽一個講座,提到索引快速全掃描的成本由索引的統計資訊葉子塊數量決定,與其他無關比如blevel。
--//我開始非常不理解,不是聽錯了吧。索引快速全掃描就是把索引當作表,其掃描成本的計算方式與全表掃描的方式一樣。
--//這樣掃描的塊數量應該是索引的hwm之下的塊,不分索引根節點塊,分支節點塊,葉子節點塊全部掃描,充分利用多塊讀取的特性完
--//成掃描操作。如果計算索引快速全掃描的成本由索引的統計資訊葉子塊數量決定,這樣豈不是漏調索引根節點塊,分支節點塊的數量。
--//算出來的成本不是偏小了嗎?
--//溫習Jonathan Lewis的<基於成本的Oracle最佳化法則>中文版P30,書中提到葉塊的數量。我還是透過例子驗證看看。
--//英文 P61
So what number does the optimizer use as the basis for the cost of the index fast full scan?
The answer seems to be the number of leaf blocks—which is fairly reasonable, because in a
nice, clean randomly generated index, with no catastrophic updates and deletes, the number
of leaf blocks is probably within 1% of the total number of blocks below the high water mark.
Strangely, if you have not collected statistics on an index, Oracle uses its knowledge of the high
water mark from the index’s segment header block to get the right answer.

--//翻譯:
那麼,最佳化器使用什麼數字作為索引快速全掃描成本的基礎?答案似乎是葉塊的數量-這是相當合理的,因為在一個很好的、乾淨的隨機
生成的索引中,沒有大量的更新和刪除,葉塊的數量可能在高水位以下的塊總數的1%以內。奇怪的是,如果您還沒有收集索引的統計數
據,Oracle就會使用它對索引的段頭塊中的高水標記的知識來獲得正確的答案。

--//其中一段"在一個很好的、乾淨的隨機生成的索引中,沒有大量的更新和刪除,葉塊的數量可能在高水位以下的塊總數的1%以內"
--//非常不理解,是指葉塊的空塊嗎?還是指索引根節點以及分支塊節點,而根本不是葉塊。
--//測試例子來自<基於成本的Oracle最佳化法則>。

1.環境:
SCOTT@test01p> @ ver1

PORT_STRING                    VERSION        BANNER                                                                               CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0           12.2.0.1.0     Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production              0

SCOTT@test01p> show parameter db_block_size
NAME          TYPE    VALUE
------------- ------- -----
db_block_size integer 8192

SCOTT@test01p> show parameter db_file_multiblock_read_count
NAME                          TYPE    VALUE
----------------------------- ------- -----
db_file_multiblock_read_count integer 8

SCOTT@test01p> execute dbms_stats.delete_system_stats;
PL/SQL procedure successfully completed.

SCOTT@test01p> alter session set "_optimizer_cost_model"=io;
Session altered.
--//主要不計cpu的成本。

2.建立測試例子:

create table t1
pctfree 99
pctused 1
as
select
    rownum                          id,
    trunc(100 * dbms_random.normal) val,
    rpad('x',100)                   padding
from all_objects where rownum <= 10000 ;

create index i_t1_val_padding on t1(val,padding) pctfree 99;
--//注意我修改索引定義增加欄位padding,並且pctfree屬性等於99;

begin
    dbms_stats.gather_table_stats(
        user,
        't1',
        cascade => true,
        estimate_percent => null,
        method_opt => 'for all columns size 1'
    );
end;
/

SCOTT@test01p> select * from user_indexes where index_name = 'I_T1_VAL_PADDING'
               @ prxx
==============================
INDEX_NAME                    : I_T1_VAL_PADDING
INDEX_TYPE                    : NORMAL
TABLE_OWNER                   : SCOTT
TABLE_NAME                    : T1
TABLE_TYPE                    : TABLE
UNIQUENESS                    : NONUNIQUE
COMPRESSION                   : DISABLED
PREFIX_LENGTH                 :
TABLESPACE_NAME               : USERS
INI_TRANS                     : 2
MAX_TRANS                     : 255
INITIAL_EXTENT                : 65536
NEXT_EXTENT                   : 1048576
MIN_EXTENTS                   : 1
MAX_EXTENTS                   : 2147483645
PCT_INCREASE                  :
PCT_THRESHOLD                 :
INCLUDE_COLUMN                :
FREELISTS                     :
FREELIST_GROUPS               :
PCT_FREE                      : 99
LOGGING                       : YES
BLEVEL                        : 3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
LEAF_BLOCKS                   : 10000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISTINCT_KEYS                 : 570
AVG_LEAF_BLOCKS_PER_KEY       : 17
AVG_DATA_BLOCKS_PER_KEY       : 17
CLUSTERING_FACTOR             : 10000
STATUS                        : VALID
NUM_ROWS                      : 10000
SAMPLE_SIZE                   : 10000
LAST_ANALYZED                 : 2019-08-15 20:37:57
DEGREE                        : 1
INSTANCES                     : 1
PARTITIONED                   : NO
TEMPORARY                     : N
GENERATED                     : N
SECONDARY                     : N
BUFFER_POOL                   : DEFAULT
FLASH_CACHE                   : DEFAULT
CELL_FLASH_CACHE              : DEFAULT
USER_STATS                    : NO
DURATION                      :
PCT_DIRECT_ACCESS             :
ITYP_OWNER                    :
ITYP_NAME                     :
PARAMETERS                    :
GLOBAL_STATS                  : YES
DOMIDX_STATUS                 :
DOMIDX_OPSTATUS               :
FUNCIDX_STATUS                :
JOIN_INDEX                    : NO
IOT_REDUNDANT_PKEY_ELIM       : NO
DROPPED                       : NO
VISIBILITY                    : VISIBLE
DOMIDX_MANAGEMENT             :
SEGMENT_CREATED               : YES
ORPHANED_ENTRIES              : NO
INDEXING                      : FULL
PL/SQL procedure successfully completed.
--//可以發現沒有一個統計相關索引HWM下的資料塊數量。基本1個鍵值佔1個資料塊。

3.測試:
SCOTT@test01p> alter session set statistics_level = all;
Session altered.

SCOTT@test01p> select /*+ index_ffs(t1) */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  2f5bkshzhmg78, child number 1
-------------------------------------
select /*+ index_ffs(t1) */ count(*) from t1 where val > 100
Plan hash value: 643509802
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  1519 |      1 |00:00:00.03 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |       |      1 |00:00:00.03 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3638 | 14552 |  1519 |   1537 |00:00:00.03 |   10159 |
--------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T1@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("VAL">100)
Note
-----
   - cpu costing is off (consider enabling it)
---//COST=1519.再看看全表掃描的成本:

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  b7ddr3041ysa4, child number 0
-------------------------------------
select /*+ full(t1) */ count(*) from t1 where val > 100
Plan hash value: 3724264953
-----------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |       |  1541 |      1 |00:00:00.04 |   10044 |
|   1 |  SORT AGGREGATE    |      |      1 |      1 |     4 |       |      1 |00:00:00.04 |   10044 |
|*  2 |   TABLE ACCESS FULL| T1   |      1 |   3638 | 14552 |  1541 |   1537 |00:00:00.04 |   10044 |
-----------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1
   2 - SEL$1 / T1@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("VAL">100)
Note
-----
   - cpu costing is off (consider enabling it)

SCOTT@test01p> select NUM_ROWS,BLOCKS from user_tables where table_name='T1';
  NUM_ROWS     BLOCKS
---------- ----------
     10000      10143

--//db_file_multiblock_read_count=8 的情況下,adjusted_dbf_mbrc=6.588,這個數值可以看<基於成本的Oracle最佳化法則>裡面提到。
--//10143/6.588 = 1539.61 約等於 1540。,_table_scan_cost_plus_one=true,cost還要+1,這樣cost = 1541
--//索引快速全掃描的成本? cost呢 = LEAF_BLOCKS/adjusted_dbf_mbrc+1
--//10000/6.588 = 1517.91 約等於 1518,_table_scan_cost_plus_one=true,cost還要+1,cost= 1519.
--//這樣基本能對上,是否blevel部分很小,hack統計資訊看看。

4.hack統計資訊驗證看看。
SCOTT@test01p> exec dbms_stats.set_index_stats(ownname=> NULL,indname=>'I_T1_VAL_PADDING',indlevel=> 10);
PL/SQL procedure successfully completed.

SCOTT@test01p> select BLEVEL,LEAF_BLOCKS from user_indexes where index_name = 'I_T1_VAL_PADDING';
    BLEVEL LEAF_BLOCKS
---------- -----------
        10       10000

SCOTT@test01p> alter system flush shared_pool;
System altered.

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  au98arwahm1df, child number 0
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val > 100
Plan hash value: 643509802
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  1519 |      1 |00:00:00.04 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |       |      1 |00:00:00.04 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3638 | 14552 |  1519 |   1537 |00:00:00.04 |   10159 |
--------------------------------------------------------------------------------------------------------------------
--//可以發現cost依舊等於1519.說明索引快速全掃描的成本與blevel無關。

SCOTT@test01p> execute dbms_stats.set_index_stats(ownname=> NULL,indname=>'I_T1_VAL_PADDING',numlblks=> 5000);
PL/SQL procedure successfully completed.

SCOTT@test01p> alter system flush shared_pool;
System altered.

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  au98arwahm1df, child number 0
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val > 100
Plan hash value: 643509802
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |   760 |      1 |00:00:00.02 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |       |      1 |00:00:00.02 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3638 | 14552 |   760 |   1537 |00:00:00.02 |   10159 |
--------------------------------------------------------------------------------------------------------------------

--//cost = LEAF_BLOCKS/adjusted_dbf_mbrc+1, 5000/6.588+1 = 759.95 約等於760.基本一致。
--//再來看看E-Row輸入計算的。

SCOTT@test01p> @ tab_lh scott t1 val
DISPLAY TABLE_NAME OF COLUMN_NAME INFORMATION.
INPUT   OWNER TABLE_NAME COLUMN
SAMPLE  : @ TAB_LH TABLE_NAME [COLUMN_NAME]
IF NOT INPUT COLUMN_NAME ,USE "" .

COLUMN_NAME DATA_TYPE DATA_LENGTH N NUM_DISTINCT    DENSITY SAMPLE_SIZE TRANS_LOW TRANS_HIGH NUM_NULLS NUM_BUCKETS LAST_ANALYZED       HISTOGRAM DATA_DEFAULT
----------- --------- ----------- - ------------ ---------- ----------- --------- -------------------- ----------- ------------------- --------- ------------
VAL         NUMBER             22 Y          570 .001754386       10000 -339      351                0           1 2019-08-15 20:37:48 NONE

SCOTT@test01p> @ prxx
==============================
COLUMN_NAME                   : VAL
DATA_TYPE                     : NUMBER
DATA_LENGTH                   : 22
NULLABLE                      : Y
NUM_DISTINCT                  : 570
DENSITY                       : .00175438596491228
SAMPLE_SIZE                   : 10000
TRANS_LOW                     : -339
TRANS_HIGH                    : 351
NUM_NULLS                     : 0
NUM_BUCKETS                   : 1
LAST_ANALYZED                 : 2019-08-15 20:37:48
HISTOGRAM                     : NONE
DATA_DEFAULT                  :
PL/SQL procedure successfully completed.

--//val在 -339 - 351 之間。查詢條件是where val > 100.直方圖不存在的情況下。
--//選擇率=(TRANS_HIGH-100)/(TRANS_HIGH-TRANS_LOW)
--//選擇率等於(351-100)/(351+339) = .36376811594202898550
--//num_rows=10000,這樣card = 3637.68,四捨五入等於3638.
--//如果查詢條件是where val >= 100,這樣選擇率=(TRANS_HIGH-100)/(TRANS_HIGH-TRANS_LOW)+1/NUM_DISTINCT
--//選擇率等於(351-100)/(351+339) +1/570 = .36552250190694126620
--//num_rows=10000,這樣card = 3655.22,四捨五入等於3655.簡單驗證看看。?

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val >=100;
  COUNT(*)
----------
      1572

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  1w1v82g1xmkhg, child number 0
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val >=100

Plan hash value: 643509802

--------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  1519 |      1 |00:00:00.04 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |       |      1 |00:00:00.04 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3655 | 14856 |  1519 |   1572 |00:00:00.04 |   10159 |
--------------------------------------------------------------------------------------------------------------------
--//基本一致。

5.順便提一下:
--//開始我並沒有設定alter session set "_optimizer_cost_model"=io;。這樣算出來差異很大,後面才知道實際上這樣採用的是
--//noworkload模式。

SCOTT@test01p> execute dbms_stats.set_index_stats(ownname=> NULL,indname=>'I_T1_VAL_PADDING',numlblks=> 10000);
PL/SQL procedure successfully completed.

--//注:這裡numlblks實際上就是修改LEAF_BLOCKS的統計值,感覺在這裡存在一些歧義。

SCOTT@test01p> exec dbms_stats.set_index_stats(ownname=> NULL,indname=>'I_T1_VAL_PADDING',indlevel=> 3);
PL/SQL procedure successfully completed.

SCOTT@test01p> select * from sys.aux_stats$;
SNAME                PNAME                     PVAL1 PVAL2
-------------------- -------------------- ---------- ------------------------------
SYSSTATS_INFO        STATUS                          COMPLETED
SYSSTATS_INFO        DSTART                          08-15-2019 20:35
SYSSTATS_INFO        DSTOP                           08-15-2019 20:35
SYSSTATS_INFO        FLAGS                         0
SYSSTATS_MAIN        CPUSPEEDNWG                2771
SYSSTATS_MAIN        IOSEEKTIM                    10
SYSSTATS_MAIN        IOTFRSPEED                 4096
SYSSTATS_MAIN        SREADTIM
SYSSTATS_MAIN        MREADTIM
SYSSTATS_MAIN        CPUSPEED
SYSSTATS_MAIN        MBRC
SYSSTATS_MAIN        MAXTHR
SYSSTATS_MAIN        SLAVETHR
13 rows selected.

--//SREADTIM= IOSEEKTIM+db_block_size/IOTFRSPEED = 10+8192/4096=12ms
--//MREADTIM= IOSEEKTIM+db_file_multiblock_read_count*db_block_size/IOTFRSPEED = 10+8*8192/4096=26ms.

SCOTT@test01p> alter session set statistics_level = all;
Session altered.

SCOTT@test01p> alter system flush shared_pool;
System altered.

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  au98arwahm1df, child number 0
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val > 100
Plan hash value: 643509802
------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  2712 (100)|          |      1 |00:00:00.02 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |            |          |      1 |00:00:00.02 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3638 | 14552 |  2712   (1)| 00:00:01 |   1537 |00:00:00.02 |   10159 |
------------------------------------------------------------------------------------------------------------------------------------

--//這樣計算的cost=2712與前面的測試1519相差甚遠。
--//cost = LEAF_BLOCKS/db_file_multiblock_read_count*MREADTIM/SREADTIM +1 = 10000/8*26/12 +1  = 2709.333
--//CPU 的成本佔1%之內。也就是 2712 - 2709 = 3.換1個方式計算:

SCOTT@test01p> explain plan for select /*+ index_ffs() */ count(*) from t1 where val > 100;
Explained.

SCOTT@test01p> select cpu_cost from plan_table;
  CPU_COST
----------
  72914400

  72914400

--//這樣可以看到cpu_cost的消耗72914400,其他方式如何看到我不清楚。
--//計算公式: CPU_COST/(CPUSPEEDNW*1000000)/1000/SREADTIM,注CPUSPEEDNW的單位是MHZ。SREADTIM的單位ms(毫秒)。
--// CPU_COST/(CPUSPEEDNW*1000000) 計算出來的單位是秒,必須要除以1000才能毫秒。
--//疑問:sys.aux_stats$中的欄位CPUSPEEDNW,CPUSPEED 有什麼區別?
--//72914400/(2771*1000000)*1000 /12 = 2.19278238902923132416 , CPU的cost=3.
--// cost = 2709+3 = 2712,基本能對上。

SCOTT@test01p> execute dbms_stats.delete_system_stats;
PL/SQL procedure successfully completed.

SCOTT@test01p> select * from sys.aux_stats$;
SNAME                PNAME                     PVAL1 PVAL2
-------------------- -------------------- ---------- -----------------------------
SYSSTATS_INFO        STATUS                          COMPLETED
SYSSTATS_INFO        DSTART                          08-15-2019 22:37
SYSSTATS_INFO        DSTOP                           08-15-2019 22:37
SYSSTATS_INFO        FLAGS                         0
SYSSTATS_MAIN        CPUSPEEDNW                 1050
SYSSTATS_MAIN        IOSEEKTIM                    10
SYSSTATS_MAIN        IOTFRSPEED                 4096
SYSSTATS_MAIN        SREADTIM
SYSSTATS_MAIN        MREADTIM
SYSSTATS_MAIN        CPUSPEED
SYSSTATS_MAIN        MBRC
SYSSTATS_MAIN        MAXTHR
SYSSTATS_MAIN        SLAVETHR
13 rows selected.
--//很奇怪,我每次刪除system統計,CPUSPEEDNW都會變。

SCOTT@test01p> alter system flush shared_pool;
System altered.

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  au98arwahm1df, child number 0
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val > 100

Plan hash value: 643509802

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  2716 (100)|          |      1 |00:00:00.03 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     4 |            |          |      1 |00:00:00.03 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   3638 | 14552 |  2716   (1)| 00:00:01 |   1537 |00:00:00.03 |   10159 |
------------------------------------------------------------------------------------------------------------------------------------
--//cost=2716
--//cpu_cost= 72914400/(1050*1000000)*1000 /12  = 5.78685714285714285666,
--// cost= 2709 +6  = 2715 ?? 相差1。
--//或許應該是這樣計算
--//io_cost  = LEAF_BLOCKS/db_file_multiblock_read_count*MREADTIM/SREADTIM +1 = 10000/8*26/12 +1  = 2709.333
--//cpu_cost = CPU_COST/(CPUSPEEDNW*1000000)/1000/SREADTIM = 72914400/(1050*1000000)*1000 /12 = 5.78685714285714285666
--// cost = io_cost + cpu_cost =  2709.333+5.786 = 2715.119 ,最後ceil(2715.119) = 2716.

6.繼續測試:
SCOTT@test01p> delete from t1 where val between 1 and 100;
3334 rows deleted.

SCOTT@test01p> commit ;
Commit complete.

begin
    dbms_stats.gather_table_stats(
        user,
        't1',
        cascade => true,
        estimate_percent => null,
        method_opt => 'for all columns size 1'
    );
end;
/

SCOTT@test01p> select * from user_indexes where index_name = 'I_T1_VAL_PADDING'
  2  @ prxx
==============================
INDEX_NAME                    : I_T1_VAL_PADDING
INDEX_TYPE                    : NORMAL
TABLE_OWNER                   : SCOTT
TABLE_NAME                    : T1
TABLE_TYPE                    : TABLE
UNIQUENESS                    : NONUNIQUE
COMPRESSION                   : DISABLED
PREFIX_LENGTH                 :
TABLESPACE_NAME               : USERS
INI_TRANS                     : 2
MAX_TRANS                     : 255
INITIAL_EXTENT                : 65536
NEXT_EXTENT                   : 1048576
MIN_EXTENTS                   : 1
MAX_EXTENTS                   : 2147483645
PCT_INCREASE                  :
PCT_THRESHOLD                 :
INCLUDE_COLUMN                :
FREELISTS                     :
FREELIST_GROUPS               :
PCT_FREE                      : 99
LOGGING                       : YES
BLEVEL                        : 3
LEAF_BLOCKS                   : 6666
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DISTINCT_KEYS                 : 470
AVG_LEAF_BLOCKS_PER_KEY       : 14
AVG_DATA_BLOCKS_PER_KEY       : 14
CLUSTERING_FACTOR             : 6666
STATUS                        : VALID
NUM_ROWS                      : 6666
SAMPLE_SIZE                   : 6666
LAST_ANALYZED                 : 2019-08-15 23:08:03
DEGREE                        : 1
INSTANCES                     : 1
PARTITIONED                   : NO
TEMPORARY                     : N
GENERATED                     : N
SECONDARY                     : N
BUFFER_POOL                   : DEFAULT
FLASH_CACHE                   : DEFAULT
CELL_FLASH_CACHE              : DEFAULT
USER_STATS                    : NO
DURATION                      :
PCT_DIRECT_ACCESS             :
ITYP_OWNER                    :
ITYP_NAME                     :
PARAMETERS                    :
GLOBAL_STATS                  : YES
DOMIDX_STATUS                 :
DOMIDX_OPSTATUS               :
FUNCIDX_STATUS                :
JOIN_INDEX                    : NO
IOT_REDUNDANT_PKEY_ELIM       : NO
DROPPED                       : NO
VISIBILITY                    : VISIBLE
DOMIDX_MANAGEMENT             :
SEGMENT_CREATED               : YES
ORPHANED_ENTRIES              : NO
INDEXING                      : FULL
PL/SQL procedure successfully completed.
--//產生一些索引空塊。LEAF_BLOCKS: 6666。

SCOTT@test01p> alter session set "_optimizer_cost_model"=io;
Session altered.

SCOTT@test01p> select /*+ index_ffs() */ count(*) from t1 where val > 100;
  COUNT(*)
----------
      1537

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  au98arwahm1df, child number 1
-------------------------------------
select /*+ index_ffs() */ count(*) from t1 where val > 100
Plan hash value: 643509802
--------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name             | Starts | E-Rows |E-Bytes| Cost  | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |                  |      1 |        |       |  1013 |      1 |00:00:00.02 |   10159 |
|   1 |  SORT AGGREGATE       |                  |      1 |      1 |     5 |       |      1 |00:00:00.02 |   10159 |
|*  2 |   INDEX FAST FULL SCAN| I_T1_VAL_PADDING |      1 |   2425 | 12125 |  1013 |   1537 |00:00:00.02 |   10159 |
--------------------------------------------------------------------------------------------------------------------
--//cost=1013
--//索引快速全掃描的成本cost = LEAF_BLOCKS/adjusted_dbf_mbrc+1
--//6666/6.588+1 = 1012.8397,不過如果檢視Buffers=10159對比前面沒有減少。

7.總結:
--//索引快速全掃描的成本由索引的統計資訊葉子塊數量決定.
--//cost的計算在11g以後發生了變化,cost計算依賴採用noworkload模式。大部分系統實際上並不採集system統計。
--//不小心又寫的太長,好久不做這些探究,腦子有點遲鈍。

--//在寫這篇文章結尾,正好看了
--//裡面提到exadata:
MBRC       :          128
MREADTIM   :
SREADTIM   :
CPUSPEED   :
CPUSPEEDNW :          918
IOSEEKTIM  :           10
IOTFRSPEED :      204,800
MAXTHR     :
SLAVETHR   :
PL/SQL procedure successfully completed.

It's also important to note that Oracle will use the 128 MBRC value in its calculation of the cost of the tablescan –
even if you've set the db_file_mulitblock_read_count parameter for the session or system to something smaller; and if
you have set the db_file_multiblock_read_count that's the maximum size of multiblock read that the run-time engine will
use.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/267265/viewspace-2653964/,如需轉載,請註明出處,否則將追究法律責任。

相關文章