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个指标来判断是否被分析过,什么时候分析的