SQL 查詢語句中in與not in查出來的條數不是互補,即用in查出來的條數不等於總數減去not in查出來的條數。java
例如:數據庫表中有10條記錄,用select count(*) from person where name in('xiaochen'); 查出來的記錄條數是2,而用select count(*) from person where name not in('xiaochen');查出來的記錄條數是2,也就是說1條記錄「沒了」;mysql
形成這結果緣由是:person表中的name字段的值是存在null,它既不在in的記錄範圍內,也不在not in的範圍內,因此沒查出。sql
person表數據庫
id name ageoop
1 xiaochen 22spa
2 dick 19code
3 fsdfsdfss 22orm
4 null 24排序
5 xiaochen 22索引
select count(*) from person where name in('xiaochen'); --結果是:2
select count(*) from person where name not in('xiaochen'); --結果是:2
select count(*) from person; --結果是:5
in和exists
in :把外表和內表做hash 鏈接
Exists:對外表做loop循環,每次loop循環再對內表進行查詢。
效率比
一直以來認爲exists比in效率高的說法是不許確的。
若是查詢的兩個表大小至關,那麼用in和exists差異不大。
若是兩個表中一個較小,一個是大表,則子查詢表大的用exists,子查詢表小的用in:
例如:表A(小表),表B(大表)
select * from A where cc in (select cc from B) 效率低,用到了A表上cc列的索引;
select * from A where exists(select cc from B where cc=A.cc) 效率高,用到了B表上cc列的索引。
相反的:表A(大表),表B(小表)
select * from B where cc in (select cc from A) 效率高,用到了B表上cc列的索引;
select * from B where exists(select cc from A where cc=B.cc) 效率低,用到了A表上cc列的索引。
not in 和not exists
not in :內外表都進行全表掃描,沒有用到索引;
not extsts :子查詢依然能用到表上的索引。
因此不管那個表大,用not exists都比not in要快。
not in 邏輯上不徹底等同於not exists,若是你誤用了not in,當心你的程序存在致命的BUG:
請看下面的例子:
CREATE TABLE `t1` (
`c1` DECIMAL(10,0) DEFAULT NULL,
`c2` DECIMAL(10,0) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8
CREATE TABLE `t2` (
`c1` DECIMAL(10,0) DEFAULT NULL,
`c2` DECIMAL(10,0) DEFAULT NULL
) ENGINE=INNODB DEFAULT CHARSET=utf8
INSERT INTO t1 VALUES (1,2);
INSERT INTO t1 VALUES (1,3);
INSERT INTO t2 VALUES (1,2);
INSERT INTO t2 VALUES (1,NULL);
select * from t1 where c2 not in (select c2 from t2);
no rows found
select * from t1 where not exists (select 1 from t2 where t1.c2=t2.c2);
c1 c2
1 3
正如所看到的,not in 出現了不指望的結果集,存在邏輯錯誤。若是看一下上述兩個select語句的執行計劃,也會不一樣。後者使用了hash_aj。
所以,請儘可能不要使用not in(它會調用子查詢),而儘可能使用not exists(它會調用關聯子查詢)。
若是子查詢中返回的任意一條記錄含有空值,則查詢將不返回任何記錄,正如上面例子所示。
除非子查詢字段有非空限制,這時可使用not in ,而且也能夠經過提示讓它使用hasg_aj或merge_aj鏈接
在mysql中,用in查詢,查詢結果,並非按照id自己順序出,而是亂序的。以下:
SELECT question_id FROM question WHERE question_id IN (164,165,166,161,162,163,167)
可結果以下:
若是須要結果根據傳入的ids順序出,須要加 order by field(question_id,164,165,166,161,162,163,167) 指定排序
SELECT question_id FROM question WHERE question_id IN (164,165,166,161,162,163,167) ORDER BY FIELD(question_id,164,165,166,161,162,163,167)