经常会遇到由于日期字段统计信息的边界值不准确,导致Oracle SQL执行计划发生改变,通常是最大值没有及时更新或者最大值过大。
下面是遇到的一个案例,SQL的执行计划突然改变,原先使用的是index range scan,突然变成了index full scan。 导致SQL语句非常缓慢。
-
select count(*) from prd_t1 where input_date>trunc(sysdate-1)
-
and input_date
原来的执行计划:
-
SQL> select count(*) from prd_t1 where input_date > trunc(sysdate);
-
-
COUNT(*)
-
----------
-
-
193311
-
-
Execution Plan
-
----------------------------------------------------------
-
-
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=8)
-
1 0 SORT (AGGREGATE)
-
2 1 INDEX (RANGE SCAN) OF 'IDX_PRD_T1' (NON-UNIQU
-
E) (Cost=4 Card=2 Bytes=16)
变差的执行计划:
-
SQL> select count(*) from prd_t1 where input_date > trunc(sysdate);
-
-
COUNT(*)
-
----------
-
-
193311
-
-
Execution Plan
-
----------------------------------------------------------
-
-
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=8)
-
1 0 SORT (AGGREGATE)
-
2 1 INDEX (FAST FULL SCAN) OF 'IDX_PRD_T1' (NON-UNIQU
-
E) (Cost=6458 Card=6130163 Bytes=49041304)
检查和字段的统计信息有关系,字段input_date的最小值和最大值分别是18-JAN-2016和15-MAY-2026。所以选择了fast full scan。
修改完最大值和最小值,执行计划恢复成使用rang scan
-
SQL> select table_name,TO_CHAR(TO_DATE(TRUNC(ENDPOINT_VALUE),'J'),'DD-MON-YYYY')
-
2 from dba_tab_histograms where table_name='PRD_T1' and column_name='INPUT_DATE';
-
-
TABLE_NAME TO_CHAR(TO_DATE(TRUNC(ENDPOINT
-
------------------------------ ------------------------------
-
-
PRD_T1 19-APR-2016
-
PRD_T1 18-APR-2017
具体方法如下:
-
DECLARE
-
srec DBMS_STATS.STATREC;
-
v_distcnt NUMBER;
-
v_density NUMBER;
-
v_nullcnt NUMBER;
-
v_avgclen NUMBER;
-
numvals DBMS_STATS.NUMARRAY;
-
charvals DBMS_STATS.CHARARRAY;
-
datevals DBMS_STATS.DATEARRAY;
-
BEGIN
-
-- Date Type
-
-
-
DBMS_STATS.get_column_stats (ownname => 'DBO',
-
tabname => 'PRD_T1',
-
colname => 'INPUT_DATE',
-
distcnt => v_distcnt,
-
density => v_density,
-
nullcnt => v_nullcnt,
-
srec => srec,
-
avgclen => v_avgclen
-
);
-
datevals := DBMS_STATS.datearray (sysdate-365, sysdate);
-
DBMS_STATS.prepare_column_values (srec, datevals);
-
DBMS_STATS.set_column_stats (ownname => 'DBO',
-
tabname => 'PRD_T1',
-
colname => 'INPUT_DATE',
-
distcnt => v_distcnt,
-
density => v_density,
-
nullcnt => v_nullcnt,
-
srec => srec,
-
avgclen => v_avgclen
-
);
-
COMMIT;
-
END;
-
/
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/25105315/viewspace-2132015/
,如需转载,请注明出处,否则将追究法律责任。