【新炬網路名師大講堂】CBO中”與NULL在cardinality計算上的差別
在ORACLE裡,一般認為”與NULL是等價的,除了一些特別的語法,比如有id is null,但是沒有id is ”,以及”作為字元型別的特殊性,在decode等函式要求型別匹配的時候,與NULL可能不等價。本篇文章主要說明下”與NULL在SQL最佳化器中也有很大的區別,如果不瞭解這個區別,很可能SQL語句的效能,將要陷入災難境地。此問題來源於:http://www.itpub.net/thread-1838241-1-1.html 討論
1.示例分析
create table t1 as select * from dba_objects ; create table t2 as select * from dba_objects ; create table t3 as select * from dba_objects ; / begin for xx in 1 .. 5 loop insert into t1 select * from t1; insert into t2 select * from t2; insert into t3 select * from t3; commit; end loop; end; / create index i1 on t1(object_name); create index i2 on t2(object_name); create index i3 on t3(object_name); create index i4 on t1(subobject_name); create index i5 on t2(subobject_name); create index i6 on t3(subobject_name);
–收集統計資訊省略 |
針對下列語句,ORACLE對t2,t3走了FULL TABLE SCAN:
dingjun123@ORADB> show rel release 1102000100
dingjun123@ORADB> set autotrace traceonly exp
Execution Plan |
看錶t2、t3對應謂詞的實際基數情況:
dingjun123@ORADB> SELECT COUNT(*) FROM t2 WHERE ”=’T’ OR “T2″.”OBJECT_NAME”=’T'; COUNT(*) ———- 128 1 row selected. Elapsed: 00:00:11.50
dingjun123@ORADB> SELECT COUNT(*) FROM t3 WHERE ”=’T’ OR “T3″.”SUBOBJECT_NAME”=’T'; |
CBO最佳化器估算的對應謂詞的基數與實際的技術差別如下:
表名 | 估算基數 | 實際基數 | 差別倍數 |
T2 | 24167 | 128 | 188.80 |
T3 | 26045 | 0 | 26045 |
很顯然,實際基數與估算的基數差別太大,從而最佳化器選擇了錯誤的執行路徑,正確的執行路徑應該是走索引的。究其原因,可以分析下,
dingjun123@ORADB> SELECT COUNT(*) FROM t2 WHERE ”T2″.”OBJECT_NAME”=’T'; Elapsed: 00:00:00.00 Execution Plan ———————————————————- Plan hash value: 2583336616 ————————————————————————– | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ————————————————————————– | 0 | SELECT STATEMENT | | 1 | 24 | 3 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 24 | | | |* 2 | INDEX RANGE SCAN| I2 | 52 | 1248 | 3 (0)| 00:00:01 | ————————————————————————– Predicate Information (identified by operation id): ————————————————— 2 – access(“T2″.”OBJECT_NAME”=’T')
dingjun123@ORADB> SELECT COUNT(*) FROM t2 WHERE ”=’T'; |
很顯然,是由於謂詞”=’T'造成了最佳化器的估算錯誤,”=’T'最佳化器估算100%的選擇性,透過OR一合併,針對表T2的最終基數是24167,因此,最佳化器選擇全表掃描。這很顯然是錯誤的,”=’T',走FILTER應該轉為NULL IS NOT NULL的形式,最終此分支根本無需計算才對。下面換成NULL測試:
dingjun123@ORADB> SELECT COUNT(*) FROM t2 WHERE NULL=’T'; Elapsed: 00:00:00.00 Execution Plan ———————————————————- Plan hash value: 402395414 ——————————————————————– | Id | Operation | Name | Rows | Cost (%CPU)| Time | ——————————————————————– | 0 | SELECT STATEMENT | | 1 | 0 (0)| | | 1 | SORT AGGREGATE | | 1 | | | |* 2 | FILTER | | | | | | 3 | TABLE ACCESS FULL| T2 | 2411K| 9411 (1)| 00:01:53 | ——————————————————————– Predicate Information (identified by operation id): ————————————————— 2 – filter(NULL IS NOT NULL) |
換成NULL=’T'後,FILTER自動轉為NULL IS NOT NULL,顯然,這是個永遠不成立的條件,所以,根本無須執行ID=3的操作,最終ID=0的結果COST=0,針對這種FILTER單分支的執行計劃注意,雖然子步驟3COST=9411,但是實際可能沒有執行,詳細的計劃可以用DBMS_XPLAN.DISPLAY_CURSOR檢視:
dingjun123@ORADB> alter session set statistics_level=all; Session altered. Elapsed: 00:00:00.04
dingjun123@ORADB> SELECT COUNT(*) FROM t2 WHERE NULL=’T';
dingjun123@ORADB> @display_cursor
20 rows selected. |
透過ID=3步驟的Starts=0,很清晰地看出,最終未執行ID=3的步驟。從這點上說,最佳化器針對”與NULL的相關計算方式還是有很大區別。
2.問題解決
透過以上分析,將”改為NULL,問題得到有效解決或者把謂詞寫到每個子SQL裡面。當然,只要是非”的都是可以的,比如’ ‘(空格)。
dingjun123@ORADB> SELECT * 2 FROM (SELECT t1.subobject_name, t1.object_name, t1.object_type 3 FROM t1 4 UNION ALL 5 SELECT NULL, t2.object_name, t2.object_type 6 FROM t2 7 UNION ALL 8 SELECT t3.subobject_name, NULL, t3.object_type FROM t3) t 9 WHERE (t.subobject_name = ‘T’ OR t.object_name = ‘T’);
256 rows selected.
Execution Plan
Predicate Information (identified by operation id):
Statistics |
ORACLE最佳化器雖然強大,但是最佳化器要判斷的東西實在太多太複雜,導致ORACLE強大的最佳化器也不一定是很完善的,有各種各樣的BUG,或未完善的地方,值得我們注意,但是,相信各種新的版本上,會有更多驚喜的特性。
注:以上問題,在RBO中同樣存在。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29960155/viewspace-1372540/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【新炬網路名師大講堂】svn在linux下的使用Linux
- 【新炬網路名師大講堂】SOA套件介紹套件
- 【新炬網路名師大講堂】weblogic整合ejbWeb
- 【新炬網路名師大講堂】總結和結論
- 【新炬網路名師大講堂】Oracle中的回收站(Recycle Bin)Oracle
- 【新炬網路名師大講堂】關於LOG FILE SYNC的解惑
- 【新炬網路名師大講堂】j2ee與weblogic簡介Web
- 【新炬網路名師大講堂】TUXEDO的配置最佳化之路一UX
- 【新炬網路名師大講堂】TUXEDO的配置最佳化之路二UX
- 【新炬網路名師大講堂】初識mysql的體系結構MySql
- 【新炬網路名師大講堂】關於IMSI/MSISDN/IMEI的介紹
- 【新炬網路名師大講堂】Oracle Database 12c 新特性總結OracleDatabase
- 【新炬網路名師大講堂】Data Guard–物理主備庫切換
- 【新炬網路名師大講堂】cursor: pin S wait on X模擬AI
- 【新炬網路名師大講堂】clone oracle 12c pluggable databasesOracleDatabase
- 【新炬網路名師大講堂】AIX上的配置網路調優引數AI
- 【新炬網路名師大講堂】GoldenGate的ADD SCHEMATRANDATA命令研究Go
- 【新炬網路名師大講堂】解決CBO對TABLE函式基數估算導致的效能問題函式
- 【新炬網路名師大講堂】MySQL複製與監控系列文章(1)——篇首MySql
- 【新炬網路名師大講堂】12c新特性:備份CDBs和PDBs
- 【新炬網路名師大講堂】12c新特性:使用RMAN連線CDB
- 【新炬網路名師大講堂】Oracle 11g rac 刪除節點Oracle
- 【新炬網路名師大講堂】oracle application server之核心技術opmnOracleAPPServer
- 【新炬網路名師大講堂】RAC環境下SYSDATE返回錯誤時間
- 【新炬網路名師大講堂】不同資料庫取前幾條記錄資料庫
- 【新炬網路名師大講堂】關於Oracle 12c Flex ASM特性的理解OracleFlexASM
- 【新炬網路名師大講堂】Oracle小知識- Oracle KILLED會話的釋放Oracle會話
- 【新炬網路名師大講堂】在AIX機器上使用xlc編譯c的動態庫AI編譯
- 【新炬網路名師大講堂】軟體測試中常見問題與解決辦法
- 【新炬網路名師大講堂】WAS控制檯資料來源資訊無故丟失
- 【新炬網路名師大講堂】有限條件下怎樣做好恢復演練
- 【新炬網路名師大講堂】理解TimesTen錯誤日誌資訊”waiting for latch”AI
- 【新炬網路名師大講堂】DATABASE REPLAY加壓播放引數之SCALE_UP_MULTIPLIERDatabase
- 【新炬網路大師講堂】敏捷性與更高CMMI級別的實踐敏捷
- 【新炬網路名師大講堂】12c高可用新特性what-if command evaluation介紹
- 【新炬網路名師大講堂】記一次打PSU遇到的Copy failed的問題AI
- 【新炬網路名師大講堂】執行計劃順序不符合一般規則
- 【新炬網路名師大講堂】11gR203 RAC一個比較嚴重的bug