等於NULL的查詢條件導致查詢結果不正確
今天有人找我確認一個bug,查詢包含等於NULL的條件,導致外連線的結果不正確。
之所以懷疑是BUG,是由於在10.2.0.1中存在這個問題,但是在10.2.0.3中,同樣的查詢沒有問題。
由於提交給我SQL十分複雜,下面做了一個簡單的例子:
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL> CREATE TABLE T (ID NUMBER);
表已建立。
SQL> INSERT INTO T
2 SELECT ROWNUM
3 FROM TAB;
已建立23行。
SQL> COMMIT;
提交完成。
SQL> CREATE TABLE T1 (ID NUMBER);
表已建立。
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID IS NULL) T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
23
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID = '') T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
0
可以看到,查詢T1的時候如果指定ID IS NULL,就可以得到正確的結果,而如果查詢時指定ID = ‘’,則會導致查詢結果錯誤。
看看Oracle的執行計劃:
SQL> SET AUTOT ON EXP
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID IS NULL) T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
23
執行計劃
----------------------------------------------------------
Plan hash value: 720849874
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 6 (17)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | HASH JOIN OUTER | | 23 | 598 | 6 (17)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 23 | 299 | 3 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 1 | 13 | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T"."ID"="ID"(+))
4 - filter("ID"(+) IS NULL)
Note
-----
- dynamic sampling used for this statement
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID = '') T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
0
執行計劃
----------------------------------------------------------
Plan hash value: 1485723496
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 0 (0)| |
| 1 | SORT AGGREGATE | | 1 | 26 | | |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN OUTER | | 23 | 598 | 6 (17)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T | 23 | 299 | 3 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T1 | 1 | 13 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(NULL IS NOT NULL)
3 - access("T"."ID"="ID"(+))
Note
-----
- dynamic sampling used for this statement
顯然,Oracle在HASH JOIN OUTER上面新增了一個恆為假的條件,NULL IS NOT NULL,從而將整個查詢過濾。而這種方法對於存在外連線的情況是不正確的。
下面看看10.2.0.3的情況:
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Solaris: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production
SQL> DESC T
名稱 是否為空? 型別
----------------------------------------- -------- ----------------------------
ID NUMBER
SQL> DESC T1
名稱 是否為空? 型別
----------------------------------------- -------- ----------------------------
ID NUMBER
SQL> SELECT COUNT(*) FROM T;
COUNT(*)
----------
0
SQL> INSERT INTO T VALUES (1);
已建立 1 行。
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID IS NULL) T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
1
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID = '') T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
1
SQL> SET AUTOT ON EXP
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID = '') T1
4 WHERE T.ID = T1.ID(+);
COUNT(*)
----------
1
執行計劃
----------------------------------------------------------
Plan hash value: 1102683273
----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16 | 0 (0)| |
| 1 | SORT AGGREGATE | | 1 | 16 | | |
|* 2 | HASH JOIN OUTER | | 1 | 16 | 8 (13)| 00:00:01 |
| 3 | TABLE ACCESS FULL| T | 1 | 13 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| T1 | 1 | 3 | 5 (0)| 00:00:01 |
----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("T"."ID"="ID"(+))
4 - filter("ID"(+)=TO_NUMBER(NULL))
SQL> SELECT COUNT(*)
2 FROM T,
3 (SELECT ID FROM T1 WHERE ID = '') T1
4 WHERE T.ID = T1.ID;
COUNT(*)
----------
0
執行計劃
----------------------------------------------------------
Plan hash value: 3380581376
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 16 | 0 (0)| |
| 1 | SORT AGGREGATE | | 1 | 16 | | |
|* 2 | FILTER | | | | | |
|* 3 | HASH JOIN | | 1 | 16 | 8 (13)| 00:00:01 |
| 4 | TABLE ACCESS FULL| T | 1 | 13 | 2 (0)| 00:00:01 |
| 5 | TABLE ACCESS FULL| T1 | 1 | 3 | 5 (0)| 00:00:01 |
-----------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(NULL IS NOT NULL AND NULL IS NOT NULL)
3 - access("T"."ID"="ID")
在10.2.0.3中,利用FILTER直接過濾查詢的最佳化方式仍然存在,但是當存在外連線的時候,Oracle就不會選擇這種方法了。
在metalink中,這個錯誤對應的bug號是5089814,這個錯誤影響的版本是10.2.0.1和10.2.0.2。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-660632/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mybatis lambdaQuery 查詢條件導致空指標MyBatis指標
- mongodb條件查詢不等於MongoDB
- Laravel 多條件查詢時粗心導致的一個 BUGLaravel
- mysql條件查詢MySql
- MongoDB查詢條件MongoDB
- MySQL bit型別增加索引後查詢結果不正確案例淺析MySql型別索引
- Laravel 多條件查詢Laravel
- mysql,where條件查詢等學習筆記MySql筆記
- 20240719資料庫關聯查詢、條件查詢資料庫
- 34. 過濾條件、多表查詢、子查詢
- 寫一個“特殊”的查詢構造器 – (四、條件查詢:複雜條件)
- mysql查詢結果多列拼接查詢MySql
- [20190502]查詢條件不等於測試.txt
- SQL-基礎語法 - 條件查詢 - 模糊查詢SQL
- 連結伺服器查詢導致的阻塞伺服器
- SpringBoot Jpa多條件查詢Spring Boot
- AntDesignBlazor示例——列表查詢條件Blazor
- golang beego orm 查詢條件 or andGolangORM
- Javaweb-DQL-條件查詢JavaWeb
- 查詢條件封裝物件封裝物件
- 【mybatis-plus】條件查詢MyBatis
- mysql like查詢 - 根據多個條件的模糊匹配查詢MySql
- mysql多條件過濾查詢之mysq高階查詢MySql
- [20201224]order by欄位順序與查詢條件為NULL.txtNull
- Laravel 關聯查詢限制條數和分組查詢顯示為零的結果Laravel
- Linq查詢之多個排序條件排序
- Linq兩個from查詢條件
- 菜品條件分頁查詢
- hyperf關聯模型條件查詢模型
- mysql拆分字串做條件查詢MySql字串
- oracle 精確查詢和模糊查詢Oracle
- Mysql-基本練習(10-設定分組條件、查詢結果排序、限制查詢結果返回的數量、TRUNCATE刪除表記錄)MySql排序
- SQL 查詢中的 NULL 值SQLNull
- [20190306]奇怪的查詢結果.txt
- MybatisPlus入門(五)MybatisPlus條件查詢MyBatis
- Vue請求介面查詢條件拼接Vue
- mybatis-plus QueryWrapper條件查詢器MyBatisAPP
- 查詢條件和條數,先查詢兩條免費的,後面為vip
- SSH實現客戶按條件查詢\上傳檔案等