为了对数据分布不均匀的列产生更好的执行计划,我们可以搜集列的直方图信息,这些信息存放在相应的数据字典中,能够帮助CBO生成更为准确的执行计划。
直方图分为两种,一种是基于高度平衡的(Height-Balanced),一种是基于频率的(Frequency)。无论是哪种直方图都是以Bucket分割的。
当Bucket的个数大于等于distinct(列)时,Bucket存放的是一个值出现的次数,这时使用的是基于频率的直方图。
Connected to Oracle Database 10g Enterprise Edition Release 10.2.0.1.0
Connected as test
SQL> select ID,COUNT(*) from test2 t GROUP BY ID order by id;
ID COUNT(*)
---------- ----------
1 1
2 1
3 1
4 2
5 1
6 1
7 1
8 1
9 61
10 1
10 rows selected
SQL> BEGIN
2 DBMS_STATS.GATHER_table_STATS (OWNNAME => 'TEST', TABNAME => 'TEST2',
3 METHOD_OPT => 'FOR COLUMNS SIZE 20 ID');
4 END;
5 /
PL/SQL procedure successfully completed
SQL> select * from user_HISTOGRAMS where table_name='TEST2';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALUE
------------- -------------- --------------- -------------- ------------------------
TEST2 ID 1 1
TEST2 ID 2 2
TEST2 ID 3 3
TEST2 ID 5 4
TEST2 ID 6 5
TEST2 ID 7 6
TEST2 ID 8 7
TEST2 ID 9 8
TEST2 ID 70 9
TEST2 ID 71 10
10 rows selected
SQL>
SQL> select table_name,
2 column_name,
3 endpoint_number,
4 endpoint_number - lag(endpoint_number, 1, 0) over(order by endpoint_number),
5 endpoint_value
6 from user_histograms
7 where table_name = 'TEST2';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_NUMBER-LAG(ENDPOINT_N ENDPOINT_VALUE
------------- ------------- --------------- ------------------------------ --------------
TEST2 ID 1 1 1
TEST2 ID 2 1 2
TEST2 ID 3 1 3
TEST2 ID 5 2 4
TEST2 ID 6 1 5
TEST2 ID 7 1 6
TEST2 ID 8 1 7
TEST2 ID 9 1 8
TEST2 ID 70 61 9
TEST2 ID 71 1 10
10 rows selected
SQL>
当Bucket的个数小于distinct(列)时,Bucket无法存放单个值出现的次数,而是一个值的范围,在不同的Bucket的这个范围中所有的值的总数尽可能的均匀,这就是基于高度平衡的直方图。
SQL>
SQL> BEGIN
2 DBMS_STATS.GATHER_table_STATS (OWNNAME => 'TEST', TABNAME => 'TEST2',
3 METHOD_OPT => 'FOR COLUMNS SIZE 5 ID'); 4 END; 5 /
PL/SQL procedure successfully completed
SQL> select * from user_histograms where table_name='TEST2';
TABLE_NAME COLUMN_NAME ENDPOINT_NUMBER ENDPOINT_VALUE ENDPOINT_ACTUAL_VALUE
-------------- --------------- --------------- -------------- ------------------------
TEST2 ID 0 1
TEST2 ID 4 9
TEST2 ID 5 10
SQL>
此时1-8值段共有8条记录,9有61条记录,10有1条记录,Bucket只是尽最大的可能做到数据均匀。
在对数据不均匀的情况使用直方图时,如果系统未使用绑定变量,每次sql语句执行都需要硬解析,重新生成执行计划,这样得到的总是正确的执行计划。
如果使用绑定变量,那么就不需要硬解析,Oracle将总是使用第一次调用该语句时生成的执行计划(bind peeking),不幸的是在11g之前的版本都存在这个问题。
对于使用了绑定变量,搜集了直方图信息,又错走了执行计划的系统,真是一个噩梦!
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/14130873/viewspace-617906/ ,如需转载,请注明出处,否则将追究法律责任。