优化原则:永远是小表驱动大表
select * from A where id in(select id from B)
等价于
for select id from B
for select * from A where A.id=B.id
当B表的数据集必须小于A表的数据集时,用in优于exists
也可以不是1,是个常量也行
select * from A where exists(select 1 from B where B.id=A.id)
等价于
for select * from A
for select * from B where B.id=A.id
当A表的数据系小于B表的数据集时,用exists优于in
注意:A表与B表的ID字段应建立索引
Exists
select…from table where exists(subquery)
该语法可以理解为:将主查询的数据,放到子查询中做条件验证,根据验证结果(true或false)来决定主查询的数据结果是否得以保留
- exists(subquery)只返回true或false,因此子查询中的select *也可以是select 1或其他,比如select ‘x’,官方说法是实际执行时会忽略select清单,因此没有区别
- exists子查询的实际执行过程可能经过了优化而不是我们理解上的逐条对比,如果担忧效率问题,可进行实际检验以确定是否有效率问题
- exists子查询往往也可以用条件表达式,其他子查询或者join来替代,何种最优需要具体问题具体分析
指定一个子查询,检测行的存在。遍历循环外表,然后看外表中的记录有没有和内表的数据一样的。匹配上就将结果放入结果集中。
使用exists关键字进行查询的时候,首先,我们先查询的不是子查询的内容,而是查我们的主查询的表,
然后,根据表的每一条记录,执行以下语句,依次去判断where后面的条件是否成立:
如果成立则返回true不成立则返回false。如果返回的是true的话,则该行结果保留,如果返回的是false的话,则删除该行,最后将得到的结果返回。
in
确定给定的值是否与子查询或列表中的值相匹配。in在查询的时候,首先查询子查询的表,然后将内表和外表做一个笛卡尔积,然后按照条件进行筛选。所以相对内表比较小的时候,in的速度较快
in和exists的区别
当A表数据与B表数据一样大时,in与exists效率差不多,可任选一个使用.
in 和 exists的区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。其实我们区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN时不对NULL进行处理。
in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的。
not in和not exists
如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。