上一节中,根据公式算出基数的时候,对目标列指定的where查询条件都是在该列的最大值和最小值(统计信息里面的值)之间的。本节讨论,如果对该列的查询条件不在它们之间,即谓词越界的现象。
下面例子:
-
select T.low_value,T.high_value,DUMP(T.high_value,16),dump(T.low_value,(16)),T.num_distinct,T.num_nulls from dba_tab_col_statistics T where table_name = 'T7' AND column_name = 'OBJECT_ID';
此时该列的最大值和最小值分别是(因为是raw类型的,需要用下面方法转换成10进制的方法)
SQL> var temp number
SQL> exec dbms_stats.convert_raw_value('C103',:temp);
PL/SQL procedure successfully completed.
TEMP
----------
2
SQL> exec dbms_stats.convert_raw_value('C3085F2F',:temp);
PL/SQL procedure successfully completed.
TEMP
----------
79446
可以看出此时,object_id的最大值和最小值为79446和2。
为了模拟本次实验,我用下面的存储过程插入几万条数据,并且不统计统计信息。
-
declare
-
i int;
-
begin
-
for i in 80000 .. 90000 loop
-
insert into t7
-
(OWNER,
-
OBJECT_NAME,
-
SUBOBJECT_NAME,
-
OBJECT_ID,
-
DATA_OBJECT_ID,
-
OBJECT_TYPE,
-
CREATED,
-
LAST_DDL_TIME,
-
TIMESTAMP,
-
STATUS,
-
TEMPORARY,
-
GENERATED,
-
SECONDARY,
-
NAMESPACE,
-
EDITION_NAME)
-
values
-
('SYS',
-
'ICOL$',
-
null,
-
i,
-
2,
-
'TABLE',
-
to_date('12-12-2014 02:51:05', 'dd-mm-yyyy hh24:mi:ss'),
-
to_date('12-12-2014 02:51:05', 'dd-mm-yyyy hh24:mi:ss'),
-
'2014-12-12:02:51:05',
-
'VALID',
-
'N',
-
'N',
-
'N',
-
1,
-
null);
-
end loop;
-
-
end;
此时没有收集统计信息,所以列的统计信息的值依然是原来的值。
但此时表中列的最大值是 120000
此时我们再执行以下语句
因为没有收集统计信息,所以统计信息都没有变化。
上面的结果集是40000多条数据,cbo计算出的cardinality确为1,这里就是出现了“谓词越界”的现象,即如果对目标列指定的
where查询条件不在该列的最大值和最小值之间,cbo就无法判断出针对该列的查询条件的可选择率,所以只能用一个估算值来
作为针对该目标列的查询条件的可选择率。进而是cbo选错执行计划。
可以针对上述,做一个10053的trace。
这里出现了谓词越界的现象,cbo用了一个很小的值0.000015来做为返回的基数。出现了严重的偏差。进而导致cbo选错了执行计划。
再次收集统计信息后,统计信息回归正常,如下:
此时再执行如上语句,变为了
效率更高。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/30109892/viewspace-1828404/
,如需转载,请注明出处,否则将追究法律责任。