2013-08-08 星期四


-------索引的改变对于执行计划的影响--------------------------------------


SQL> create index ind_g_l_a on test(gender,location,age_group);


Index created.


SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true,estimate_percent=>100);


PL/SQL procedure successfully completed.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> set linesize 1000

SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

  27538608          3         90 0%


1、大批量删除数据后对执行计划的影响。


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';


Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |    20   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |  5036 | 70504 |    20   (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')


SQL> delete from test where rownum<=300000;


300000 rows deleted.


SQL> commit;


Commit complete.


SQL> set linesize 1000

SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true,estimate_percent=>100);


PL/SQL procedure successfully completed.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

  27538608                               3                       90               30%    


删除率到了30%。


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';


Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |    17   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |  3512 | 49168 |    17   (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')

Statistics

----------------------------------------------------------

         0  recursive calls

         0  db block gets

        24  consistent gets

         0  physical reads

         0  redo size

       412  bytes sent via SQL*Net to client

       400  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


COST减小了,实际上并没有减小,HWM没有下降的,扫块还是那么多。这个执行计划已经有异常了。


SQL> delete from test where rownum<=500000;


500000 rows deleted.


SQL> commit;


Commit complete.


SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true,estimate_percent=>100);


PL/SQL procedure successfully completed.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

  27538608                                   3                  84            78%


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';



Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |     8   (0)| 00:00:01 |  

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |   999 | 13986 |     8   (0)| 00:00:01 |

--------------------------------------------------------------------------------


执行计划显示的是oracle认为索引是正常情况下的执行计划,但是实际上执行的时候并不是这样做的,

所以按照计划,但是计划在实际做得时候是发生了变化的。

按照下面显示的内容,实际读取的时候IO会多出一倍。


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')



Statistics

----------------------------------------------------------

         0  recursive calls

         0  db block gets

        24  consistent gets   --真正的SQL语句的IO消耗,但是执行计划上看到的值是很离谱的,误差很大的。

         0  physical reads

         0  redo size

       412  bytes sent via SQL*Net to client

       400  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


SQL> alter index ind_g_l_a rebuild;


Index altered.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

   5525364                                 3                        90         0%


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';



Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |     8   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |   999 | 13986 |     8   (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')



Statistics

----------------------------------------------------------

         1  recursive calls

         0  db block gets

        12  consistent gets

         0  physical reads

         0  redo size

       412  bytes sent via SQL*Net to client

       400  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


插入大量数据的时候,对执行计划的影响:


insert into test select decode(ceil(dbms_random.value(0,2)),'1','M','2','F') gender,

ceil(dbms_random.value(1,50)) location,

decode(ceil(dbms_random.value(0,5)),'1','18 and under','2','19-25','3','26-30','4','31-50','5','41 and over') age_group,

rpad('*',20,'*') data from t2;


SQL> commit;


Commit complete.


SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true,estimate_percent=>100);


PL/SQL procedure successfully completed.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

  52790648                                3                             57     0%


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';



Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |    38   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |  6061 | 84854 |    38   (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')



Statistics

----------------------------------------------------------

         0  recursive calls

         0  db block gets

        40  consistent gets

         0  physical reads

         0  redo size

       412  bytes sent via SQL*Net to client

       400  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


SQL> alter index ind_g_l_a rebuild;


Index altered.


SQL> analyze index ind_g_l_a validate structure;


Index analyzed.


SQL> select btree_space,height,pct_used,(del_lf_rows/decode(lf_rows,0,1,lf_rows))*100||'%' as delete_pct from index_stats;


BTREE_SPACE     HEIGHT   PCT_USED DELETE_PCT

----------- ---------- ---------- -----------------------------------------

  33039920                                  3                         90        0%


SQL> select count(1) from test where gender='M' and location in(1,10,30) and age_group='41 and over';



Execution Plan

----------------------------------------------------------

Plan hash value: 2282520444


--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |    14 |    23   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE    |           |     1 |    14 |            |          |

|   2 |   INLIST ITERATOR  |           |       |       |            |          |

|*  3 |    INDEX RANGE SCAN| IND_G_L_A |  6061 | 84854 |    23   (0)| 00:00:01 |

--------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


  3 - access("GENDER"='M' AND ("LOCATION"=1 OR "LOCATION"=10 OR

             "LOCATION"=30) AND "AGE_GROUP"='41 and over')



Statistics

----------------------------------------------------------

        15  recursive calls

         0  db block gets

        31  consistent gets

         0  physical reads

         0  redo size

       412  bytes sent via SQL*Net to client

       400  bytes received via SQL*Net from client

         2  SQL*Net roundtrips to/from client

         0  sorts (memory)

         0  sorts (disk)

         1  rows processed


索引的相关指标不在要求范围内的时候,发现执行计划是有偏差的,

这就是索引难以维护对SQL语句执行带来的巨大影响。


实验:

1、作shrink操作之前和之后执行计划的变化。

2、删除x行数据,再x行数据之后,碎片空间被重用后,执行计划的变化情况。

3、大批量update操作之前和之后,执行计划的变化。

4、作move操作之前和之后执行计划的变化。


index_stats的存储结构


要先分析analyze index ind_g_l_a validate structure;

在同一个会话中查询才有信息查询的。


树的总块数=4224


LF_BLKS=4118

BR_BLKS=14

RT_BLKS=1

合计:4133块    剩下的块都是位图块。


SQL> set linesize 100

SQL> desc index_stats;

Name                                                  Null?    Type

----------------------------------------------------- -------- ------------------------------------

HEIGHT                                                         NUMBER --索引树的高度

BLOCKS                                                         NUMBER  --索引的总块数

NAME                                                           VARCHAR2(30) --索引名字

PARTITION_NAME                                                 VARCHAR2(30)  --索引分区名字

LF_ROWS                                                        NUMBER    --叶子行数

LF_BLKS                                                        NUMBER    --叶子总块数

LF_ROWS_LEN                                                    NUMBER    --叶子行的总长度

LF_BLK_LEN                                                     NUMBER    --叶子块的总长度

BR_ROWS                                                        NUMBER     --分支块中存储的键值个数

BR_BLKS                                                        NUMBER    --分支的总块数

BR_ROWS_LEN                                                    NUMBER    --分支行的总长度

BR_BLK_LEN                                                     NUMBER    --分支块的长度

DEL_LF_ROWS                                                    NUMBER    --删除的叶子行数

DEL_LF_ROWS_LEN                                                NUMBER     --删除的叶子行总长度

DISTINCT_KEYS                                                  NUMBER      --不重复的值有多少个

MOST_REPEATED_KEY                                              NUMBER     --最大的重复次数

BTREE_SPACE                                                    NUMBER     --树的空间大小

USED_SPACE                                                     NUMBER     --索引已经使用的空间大小

PCT_USED                                                       NUMBER     --B树中已经分配的空间使用的百分比

ROWS_PER_KEY                                                   NUMBER     --每个值平均的行数

BLKS_GETS_PER_ACCESS                                           NUMBER     --平均每次访问的索引块数

PRE_ROWS                                                       NUMBER

PRE_ROWS_LEN                                                   NUMBER

OPT_CMPR_COUNT                                                 NUMBER

OPT_CMPR_PCTSAVE                                               NUMBER


select * from user_indexes  --主要存储分配的相关参数


如何判断一个表或者是索引被分析过以及最后一次分析的时间?

分析的结果数据被存储在oracle的数据字典中,解析的时候会利用这些分析信息生成执行计划。


SQL> set linesize 1000

SQL> select num_rows,avg_row_len,blocks,last_analyzed from user_tables where table_name='TEST';


 NUM_ROWS AVG_ROW_LEN     BLOCKS LAST_ANALYZED

---------- ----------- ---------- -------------------

         1200000                              34                       6766  2013-08-08 09:52:04


SQL> select blevel,leaf_blocks,distinct_keys,last_analyzed from user_indexes where table_name='TEST';


   BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED

---------- ----------- ------------- -------------------

                        2                           4118           490                     2013-08-08 09:53:37


删除统计信息

SQL> exec dbms_stats.delete_index_stats(user,'ind_g_l_a');


PL/SQL procedure successfully completed.


SQL> select blevel,leaf_blocks,distinct_keys,last_analyzed from user_indexes where table_name='TEST';


   BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED

---------- ----------- ------------- -------------------



SQL> exec dbms_stats.delete_table_stats(user,'test');


PL/SQL procedure successfully completed.


SQL> select num_rows,avg_row_len,blocks,last_analyzed from user_tables where table_name='TEST';


 NUM_ROWS AVG_ROW_LEN     BLOCKS LAST_ANALYZED

---------- ----------- ---------- -------------------



SQL> exec dbms_stats.gather_table_stats(user,'test',cascade=>true,estimate_percent=>100);


PL/SQL procedure successfully completed.


SQL> select num_rows,avg_row_len,blocks,last_analyzed from user_tables where table_name='TEST';


 NUM_ROWS AVG_ROW_LEN     BLOCKS LAST_ANALYZED

---------- ----------- ---------- -------------------

  1200000          34       6766 2013-08-08 10:29:23


SQL> select blevel,leaf_blocks,distinct_keys,last_analyzed from user_indexes where table_name='TEST';


   BLEVEL LEAF_BLOCKS DISTINCT_KEYS LAST_ANALYZED

---------- ----------- ------------- -------------------

        2        4118           490 2013-08-08 10:29:27



exec dbms_stats.delete_table_stats(user,'test',cascade=>true);


--将表和索引的统计分析信息一起删除


注意:收集性能数据不仅仅是只统计上面8个字段的值,统计指标有很多,


只是我们可以通过这8个指标来判断是否被分析过,什么时候分析的