日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

SQL调优:带函数的谓词导致CBO Cardinality计算误差

發布時間:2023/12/9 数据库 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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计算误差的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。