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)