2.3.1 in 使用原理

确定给定的值是否与子查询或列表中的值相匹配。in在查询的时候,首先查询子查询的表,然后将内表和外表做一个笛卡尔积,然后按照条件进行筛选。所以相对内表比较小的时候,in的速度较快

实例:

  1. SELECT * FROM `user`
  2. WHERE `user`.id IN (
  3. SELECT `order`.user_id FROM `order` )

语句的意思:通过子查询查到的user_id 的数据,去匹配user表中的id然后得到结果
执行流程:

  • 首先,在数据库内部,查询子查询,即 SELECT order.user_id FROM order
  • 然后,将查询到的结果和原有的user表做一个笛卡尔积
  • 最后,根据我们的user.id IN order.user_id的条件,将结果进行筛选(既比较id列和user_id 列的值是否相等,将不相等的删除)

    2.3.2 exists 使用原理

    指定一个子查询,检测行的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据一样的。匹配上就将结果放入结果集中。

实例:

  1. SELECT * FROM `user`
  2. WHERE EXISTS (
  3. SELECT `order`.user_id FROM `order` WHERE `user`.id = `order`.user_id )

该语句与上述语句结果一样
执行流程:

  • 首先,我们先查询的不是子查询的内容,而是查我们的主查询的表,即 SELECT * FROM user
  • 然后,根据表的每一条记录,执行以下语句,依次去判断where后面的条件是否成立:

SELECT order.user_id FROM order WHERE user.id = order.user_id

  • 如果成立则返回true不成立则返回false。如果返回的是true的话,则该行结果保留,如果返回的是false的话,则删除该行,最后将得到的结果返回。

    2.3.3 区别及应用场景

  • 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in

  • 如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。
  • 其实区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN时不对NULL进行处理。

mysql010.png

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