關於ORACLE MYSQL NOT IN和NOT exists需要注意的 NULL值
首先說明NOT IN 和NOT EXISTS 並不完全等價 ORACLE MYSQL 都是如此
源表:
SQL> select * from testa1;
NAME ID
-------------------- -----------
gaopeng 1
gaopeng 2
gaopeng 3
gaopeng 4
SQL> select * from testb1;
NAME ID
-------------------- -----------
gaopeng 1
gaopeng 2
gaopeng
因為NOT IN是對NULL 敏感的而NOT exists卻不是,所以ORACLE使用的執行計劃如下:
select * from testa1 where not exists (select * from testb1 where testa1.id=testb1.id );
NAME ID
-------------------- -----------
gaopeng 4
gaopeng 3
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4225223740
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 152 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN ANTI | | 4 | 152 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TESTB1 | 3 | 39 | 2 (0)| 00:00:01 |
普通的反連線
select * from testa1 where testa1.id not in (select testb1.id from testb1 );
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2176127487
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 152 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN ANTI NA | | 4 | 152 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TESTB1 | 3 | 39 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
11g後改良的HASH JOIN ANTI NA 連線方式如果我們改變最佳化器到9I其執行計劃為
select /*+ optimizer_features_enable('9.2.0') */ * from testa1 where testa1.id not in (select testb1.id from testb1 );
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1097631637
-------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 100 | 4 |
|* 1 | FILTER | | | | |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 |
|* 3 | TABLE ACCESS FULL| TESTB1 | 78 | 1014 | 2 |
-------------------------------------------------------------
可以看到老的執行計劃是用不了的。
關於MYSQL 我也實驗了一樣和ORACLE一樣 其執行計劃如下:
mysql> explain select * from testa1 where testa1.id not in (select testb1.id from testb1 );
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | testa1 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 2 | SUBQUERY | testb1 | ALL | NULL | NULL | NULL | NULL | 3 | NULL |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
2 rows in set (0.00 sec)
mysql> explain select * from testa1 where not exists (select * from testb1 where testa1.id=testb1.id );
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | testa1 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 2 | DEPENDENT SUBQUERY | testb1 | ALL | NULL | NULL | NULL | NULL | 3 | Using where |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
當然 in 和 exists 是等價的
源表:
SQL> select * from testa1;
NAME ID
-------------------- -----------
gaopeng 1
gaopeng 2
gaopeng 3
gaopeng 4
SQL> select * from testb1;
NAME ID
-------------------- -----------
gaopeng 1
gaopeng 2
gaopeng
因為NOT IN是對NULL 敏感的而NOT exists卻不是,所以ORACLE使用的執行計劃如下:
select * from testa1 where not exists (select * from testb1 where testa1.id=testb1.id );
NAME ID
-------------------- -----------
gaopeng 4
gaopeng 3
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4225223740
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 152 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN ANTI | | 4 | 152 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TESTB1 | 3 | 39 | 2 (0)| 00:00:01 |
普通的反連線
select * from testa1 where testa1.id not in (select testb1.id from testb1 );
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2176127487
-----------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 152 | 5 (20)| 00:00:01 |
|* 1 | HASH JOIN ANTI NA | | 4 | 152 | 5 (20)| 00:00:01 |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 (0)| 00:00:01 |
| 3 | TABLE ACCESS FULL| TESTB1 | 3 | 39 | 2 (0)| 00:00:01 |
-----------------------------------------------------------------------------
11g後改良的HASH JOIN ANTI NA 連線方式如果我們改變最佳化器到9I其執行計劃為
select /*+ optimizer_features_enable('9.2.0') */ * from testa1 where testa1.id not in (select testb1.id from testb1 );
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1097631637
-------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 100 | 4 |
|* 1 | FILTER | | | | |
| 2 | TABLE ACCESS FULL| TESTA1 | 4 | 100 | 2 |
|* 3 | TABLE ACCESS FULL| TESTB1 | 78 | 1014 | 2 |
-------------------------------------------------------------
可以看到老的執行計劃是用不了的。
關於MYSQL 我也實驗了一樣和ORACLE一樣 其執行計劃如下:
mysql> explain select * from testa1 where testa1.id not in (select testb1.id from testb1 );
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | testa1 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 2 | SUBQUERY | testb1 | ALL | NULL | NULL | NULL | NULL | 3 | NULL |
+----+-------------+--------+------+---------------+------+---------+------+------+-------------+
2 rows in set (0.00 sec)
mysql> explain select * from testa1 where not exists (select * from testb1 where testa1.id=testb1.id );
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | testa1 | ALL | NULL | NULL | NULL | NULL | 4 | Using where |
| 2 | DEPENDENT SUBQUERY | testb1 | ALL | NULL | NULL | NULL | NULL | 3 | Using where |
+----+--------------------+--------+------+---------------+------+---------+------+------+-------------+
當然 in 和 exists 是等價的
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-1588867/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- oracle中關於in和exists,not in 和 not existsOracle
- mysql 關於exists 和in分析MySql
- in,exists和not exists ,not in與null的一些關係記載Null
- 用decode和nvl處理null值時需要注意的地方Null
- 關於 oracle NULLOracleNull
- 關於null值的小知識Null
- ORACLE關於NULL的總結OracleNull
- oracle sql_not exists與null的測試OracleSQLNull
- [Oracle] exists 和 not existsOracle
- oracle中關於null的定義OracleNull
- 【NULL】Oracle null值介紹NullOracle
- mysql 空值(null)和空字元('')的區別MySqlNull字元
- 關於mysql設定varchar 欄位的預設值''和null的區別,以及varchar和char的區別MySqlNull
- 關於NULL值在索引裡的兩個疑惑Null索引
- MySQL中is not null和!=null和<>null的區別MySqlNull
- oracle中的exists和not exists和in用法詳解Oracle
- oracle中的exists 和not exists 用法詳解Oracle
- MySQL null值儲存,null效能影響MySqlNull
- 關於內購支付的流程和一些需要注意的坑
- 關於NULLNull
- 你還不知道mysql中空值和null值的區別嗎?MySqlNull
- NULL在oracle和mysql索引上的區別NullOracleMySql索引
- mysql中null與“空值”的坑MySqlNull
- MySQL裡null與空值的辨析MySqlNull
- 【NULLS】Oracle對SQL排序後NULL值位置的“特殊關照”NullOracleSQL排序
- 關於mysql,需要掌握的基礎(二):JDBC和DAO層MySqlJDBC
- oracle over()的使用和需要特別注意的地方Oracle
- 不再迷惑,無值和 NULL 值Null
- NOT IN、JOIN、IS NULL、NOT EXISTS效率對比Null
- oracle中in和exists的區別Oracle
- MySQL 的 NULL 值是怎麼儲存的?MySqlNull
- MySQL null和''分析MySqlNull
- Go 1.16 中關於 go get 和 go install 你需要注意的地方Go
- in、exists操作與null的一點總結Null
- 關於Oracle和MySQL中的無密碼登入OracleMySql密碼
- 關於零值和nil
- 從Access轉到MySql以後遇到的關於null問題MySqlNull
- (轉)ORACLE 中IN和EXISTS的區別Oracle