嵌套查询(子查询)能够使用SELECT语句来建立一个单列的查询结果,而后把这个结果做为过滤条件用在另外一个查询中。嵌套查询写起来简单,也容易理解。可是,有时候能够被更有效率的链接(JOIN)替代。微信
如今假如要找出历来没有在网站中消费的客户,也就是查询在客户customer表中可是不在支付payment表中的客户信息。post
嵌套查询:性能
explain select * from customer where customer_id not in (select customer_id from payment);
学习
链接改写:优化
explain select * from customer a left join payment b on a.customer_id = b.customer_id where b.customer_id is null;
网站
画外音:链接查询效率更高的缘由,是由于MySQL不须要在内存中建立临时表来完成这个逻辑上须要两个步骤的查询工做;而且Not exists表示MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行, 就再也不搜索了。spa
在MySQL中作分页查询,MySQL 并非跳过 offset 行,而是取 offset+N 行,而后返回放弃前 offset 行,返回 N 行,那当 offset 特别大的时候,效率就很是的低下。例如“limit 1000,20”,此时MySQL排序出前1020条数据后仅仅须要第1001到1020条记录,前1000条数据都会被抛弃,查询和排序的代价很是高。因而可知MySQL的分页处理并非十分完美,须要咱们在分页SQL上作一些优化,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。3d
画外音:控制返回的总页数并非那么靠谱,毕竟每页的数据量也不能过大,数据多起来以后,控制返回的总页数就变的不现实了。因此仍是要对超过特定阈值的页数进行 SQL 改写。code
如今假设要对电影表film排序后取某一页数据blog
explain select * from film order by title limit 50,5;
能够看到优化器实际上作了全表扫描,处理效率不高。
在索引上完成排序分页的操做,最后根据主键关联回表查询所须要的其余列内容。
画外音:此处涉及到了SQL优化的两个重要概念,索引覆盖和回表,我在前面的文章中详细介绍过这两个概念。经过索引覆盖在索引上完成扫描和排序(索引有序),最后经过主键(InnoDB引擎索引会经过主键回表)回表查询,最大限度减小回表查询的I/O次数。
explain select * from film a inner join (select film_id from film order by title limit 50,5)b on a.film_id = b.film_id;
把LIMIT查询转换成某个位置的查询,减小分页翻页的压力。
假设如今每页10条数据,要取第42页的数据。
explain select * from film order by title limit 410,10;
如今须要多传一个参数,就是上一页(第41页)的最后一条数据的主题title,
SQL能够改写为:
explain select * from film where title>'HOLES BRANNIGAN' order by title limit 10;
这样就把LIMIT m,n 转换成了LIMIT n的查询,可是这种方案只适合在不会出现重复值的特定环境,不然分页结果可能会丢失数据。
对于嵌套查询和分页查询的优化,归根结底就是遵循SQL优化原则之一——减小回表查询的I/O次数。对于分页查询优化,更建议使用第一种优化方案,性能更好,稳定性更高。
《深刻浅出MySQL》