mysql中exists 和 in的用法你还真不知道

exists与in的查询方式

In:是把外表和内表做Hash 连接

exists:是对外表作loop 循环,每次loop循环再对内表进行查询

mysql中exists 和 in的用法你还真不知道

 

典型的连接类型共有3种:

排序- 合并连接(Sort Merge Join (SMJ) )

嵌套循环(Nested Loops (NL) )

哈希连接(Hash Join)

效率分析

比如:

A表(主查询,即:外表)和B表(子查询,即:内表)关联查询;

当A表和B表大小相当时,用in和exists查询效率差不多;

当A表(主查询)比B表(子查询)大的时,即子查询表小的时候用In效率高;

当A表(主查询)比B表(子查询)小的时,即子查询表大的时候用exists效率高;

格式不同

1、In:

select a.* from A where a.id in (select b.id from B b)

2、exists:

select a.* from A where exists (select b.id from B b where a.id=b.id)

例如 :

表A(主查询)大,B表(子查询)小

in 查看:

select a.* from A where a.id in (select bid from B b)

相当于:

select * from A a, (select b.id from B b) c where a.id = c.id

效率低的原因

全程扫描B表,用到A 表上的a.id的索引,因为A表大

exists 查看

select * from a where exists (select b.id from B b where b.id = a.id) 

效率高的原因:

全程扫描A表,用到B表上的b.id的索引,因为B表大

Not in 和Not Exists 的 效率

格式不同:

In:

select a.* from A where a.id not in (select b.id from B b)

exists:

select a.* from A where not exists (select b.id from B b where a.id=b.id)

如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。 所以无论那个表大,用not exists都比not in要快。

关联子查询与非关联子查询

关联子查询需要在内部引用外部表,而非关联子查询不要引用外部表。对于父查询中处理的记录来说,一个关联子查询是每行计算一次,然而一个非关联子查询只会执行一次,而且结果集被保存在内存中(如果结果集比较小),或者放在一张oracle临时数据段中(如果结果集比较大)。一个“标量”子查询是一个非关联子查询,返回唯一记录。如果子查询仅仅返回一个记录,那么oracle优化器会将结果缩减为一个常量,而且这个子查询只会执行一次。

如何选择?

根据外部查询,以及子查询本身所返回的记录的数目。如果两种查询返回的结果是相同的,哪一个效率更好?

关联子查询的系统开销:对于返回到外层查询的记录来说,子查询会每次执行一次。因此,必须保证任何可能的时候子查询都要使用索引。

非关联子查询的系统开销:子查询只会执行一次,而且结果集通常是排好序的,并保存在临时数据段中,其中每一个记录在返回时都会被父级查询引用,在子查询返回大量记录的情况下,将这些结果集排序回增大系统的开销。

所以:如果父查询只返回较少的记录,那么再次执行子查询的开销不会非常大,如果返回很多数据行,那么直查询就会执行很多次。 如果子查询返回较少的记录,那么为内存中保存父查询的结果集的系统开销不会非常大,如果子查询返回多行,那么需要将结果放在临时段上,然后对数据段排序,以便为负查询中的每个记录服务。