一、in与not in不是互补的
SQL 查询语句中in与not in查出来的条数不是互补,即用in查出来的条数不等于总数减去not in查出来的条数。
例如:数据库表中有10条记录,用select count(*) from person where name in('xiaochen'); 查出来的记录条数是2,而用select count(*) from person where name not in('xiaochen');查出来的记录条数是2,也就是说1条记录“没了”;
造成这结果原因是:person表中的name字段的值是存在null,它既不在in的记录范围内,也不在not in的范围内,所以没查出。
person表
id name age
1 xiaochen 22
2 dick 19
3 fsdfsdfss 22
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与not in不是互补的补救方法---not exists
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排序问题(MySQL 查询in操作,查询结果按in集合顺序显示)
在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)