SQL调优:带函数的谓词导致CBO Cardinality计算误差
生活随笔
收集整理的這篇文章主要介紹了
SQL调优:带函数的谓词导致CBO Cardinality计算误差
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
今天處理了這樣一問題,where條件中存在函數fun(date)<to_date('9999-01-01','YYYY-MM-DD')這樣的無實際意義謂詞,導致CBO計算基數時cardinality遠小于實際情況,導致優化器認為2個源數據集的基數都不大,從而選擇了HASH JOIN Right SEMI+SORT ORDER BY的執行計劃,但是由于實際基數遠大于computed 計算值所以變成了大的數據集做HASH JOIN并全數據排序,而實際該SQL只要求返回幾十行數據而已,使用NESTED LOOP SEMI JOIN可以立即返回排序的前20行數據。 這里就需要解釋帶函數的謂詞時CBO如何計算基數,我們通過下面的例子來說明: ? ? create or replace function check_date( RDATE in date) return date is
begin
IF rdate< to_date('2099-01-01','YYYY-MM-DD') then return rdate; ELSIF rdate >=to_date('2099-01-01','YYYY-MM-DD') then return to_date('2000-01-01');end if;end check_date;/SQL> select check_date (sysdate) from dual;CHECK_DAT
---------
06-DEC-12drop table tab1;SQL> create table tab1 tablespace users as select * from dba_objects where rownum create view vtab1 as select object_id as id , object_name as name, object_type as type , check_date(created) cdata from tab1;View created.SQL> select count(distinct cdata) from vtab1;COUNT(DISTINCTCDATA)
--------------------130SQL> exec dbms_stats.gather_table_stats('','TAB1', method_opt=>'FOR ALL COLUMNS SIZE 254');PL/SQL procedure successfully completed. ? ? 因為我們指定收集了直方圖所以若直接以"created"為條件查詢時可以獲得較好的計算基數 SQL> select count(*) from tab1 where created >= to_date('0001-10-10','YYYY-MM-DD');COUNT(*)
----------10000Execution Plan
----------------------------------------------------------
Plan hash value: 1117438016---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 8 | 40 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 8 | | |
|* 2 | TABLE ACCESS FULL| TAB1 | 10000 | 80000 | 40 (0)| 00:00:01 |
---------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("CREATED">=TO_DATE(' 0001-10-10 00:00:00', 'syyyy-mm-ddhh24:mi:ss'))Statistics
----------------------------------------------------------1 recursive calls0 db block gets133 consistent gets0 physical reads0 redo size526 bytes sent via SQL*Net to client523 bytes received via SQL*Net from client2 SQL*Net roundtrips to/from client0 sorts (memory)0 sorts (disk)1 rows processed ? ? 在以上查詢中>= to_date('0001-10-10','YYYY-MM-DD'); 這樣的過濾條件實際無意義,在直接使用 "created"列作為謂詞的情況下,CBO可以獲得很好的基數10000。 ? ? SQL> select * from TABLE(dbms_xplan.display_cursor(NULL,NULL,'ALLSTATS LAST'));PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 6zy2k9dy4cv73, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ count(*) from vtab1 where cdata
>= to_date('0001-10-10','YYYY-MM-DD')Plan hash value: 1117438016-------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.25 | 154 |
| 1 | SORT AGGREGATE | | 1 | 1 | 1 |00:00:00.25 | 154 |
|* 2 | TABLE ACCESS FULL| TAB1 | 1 | 500 | 10000 |00:00:00.31 | 154 |
-------------------------------------------------------------------------------------Predicate Information (identified by operation id):
---------------------------------------------------2 - filter("CHECK_DATE"("CREATED")>=TO_DATE(' 0001-10-10 00:00:00','syyyy-mm-dd hh24:mi:ss'))21 rows selected. ? ? 通過gather_plan_statistics HINT,我們得到E-Rows 即CBO評估的基數,和 A-Rows實際的基數,可以看到這里E-Rows=500, 即在謂詞左邊存在使用內部函數或隱身裝換的情況下,CBO無法通過現有統計信息的DISTINCT、DENSITY和HISTOGRAM獲得較好的Cardinality,其基數總是統計信息中表的總行數/20,如上例中的 10000/20=500。 這就會引入不少的麻煩,因為開發人員有時候為了方便會在視圖字段中嵌入自定義的函數,之后若在查詢中使用該字段作為謂詞條件,則可能導致CBO為相應表計算的基數偏少,是本身應當成本非常高的執行計劃的COST變低,而容易被優化器選擇。 對于上述問題可選的常見方案是若有這樣問題的SQL較少則考慮加HINT或者SQL PROFILE,若較多還是需要考慮減少這種謂詞左邊有函數的現象。 implicit data_type conversion functions in Filter Predicates. Review Execution Plans. If Filter Predicatesinclude unexpected INTERNAL_FUNCTION to perform an implicit data_type conversion, be sure it is not preventing a column from being used as an Access Predicate.
轉載于:https://www.cnblogs.com/macleanoracle/archive/2013/03/19/2968127.html
總結
以上是生活随笔為你收集整理的SQL调优:带函数的谓词导致CBO Cardinality计算误差的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于iPhone的UIView刷新(转)
- 下一篇: 通过SQL Server操作MySQL的