4. 子查询优化
 
 MySQL 
 从 
 4.1 
 版本开始支持子查询,使用子查询可以进行 
 SELECT 
 语句的嵌套查询,即一个 
 SELECT 
 查询的结果作为另一个SELECT 
 语句的条件。  
 子查询可以一次性完成很多逻辑上需要多个步骤才能完成的 
 SQL 
 操作  
 。  
 
 
 子查询是  
 MySQL  
 的一项重要的功能,可以帮助我们通过一个  
 SQL  
 语句实现比较复杂的查询。但是,子 
 查询的执行效率不高。 
 原因:  
 
 
 ① 执行子查询时, 
 MySQL 
 需要为内层查询语句的查询结果  
 建立一个临时表  
 ,然后外层查询语句从临时表中查询记录。查询完毕后,再  
 撤销这些临时表  
 。这样会消耗过多的 
 CPU 
 和 
 IO 
 资源,产生大量的慢查询。  
 
 
 ② 子查询的结果集存储的临时表,不论是内存临时表还是磁盘临时表都  
 不会存在索引  
 ,所以查询性能会受到一定的影响。  
 
 
 ③ 对于返回结果集比较大的子查询,其对查询性能的影响也就越大。  
 
 
 
 在 
 MySQL 
 中,可以使用连接( 
 JOIN 
 )查询来替代子查询。 
 连接查询  
 不需要建立临时表  
 ,其  
 速度比子查询要快  
 ,如果查询中使用索引的话,性能就会更好。  
 
结论:尽量不要使用NOT IN 或者 NOT EXISTS,用LEFT JOIN xxx ON xx WHERE xx IS NULL替代
8.优先考虑覆盖索引
8.1 什么是覆盖索引?
 
 理解方式一 
 :索引是高效找到行的一个方法,但是一般数据库也能使用索引找到一个列的数据,因此它不必读取整个行。毕竟索引叶子节点存储了它们索引的数据;当能通过读取索引就可以得到想要的数据,那就不需要读取行了。 
 一个索引包含了满足查询结果的数据就叫做覆盖索引。  
 
 
 理解方式二 
 :非聚簇复合索引的一种形式,它包括在查询里的 
 SELECT 
 、 
 JOIN 
 和 
 WHERE 
 子句用到的所有列 (即建索引的字段正好是覆盖查询条件中所涉及的字段)。  
 
 
 
 简单说就是,  
 索引列 
 + 
 主键  
 包含  
 SELECT  
 到  
 FROM 
 之间查询的列  
 。  
 
8.2 覆盖索引的利弊
 
 好处:  
 
 
 1.  
 避免 
 Innodb 
 表进行索引的二次查询(回表)  
 
 
 2.  
 可以把随机 
 IO 
 变成顺序 
 IO 
 加快查询效率  
 
 
 
 弊端:  
 
 
 索引字段的维护  
 总是有代价的。因此,在建立冗余索引来支持覆盖索引时就需要权衡考虑了。这是业务 DBA,或者称为业务数据架构师的工作。  
 
 
10. 使用索引下推
 
  Index Condition Pushdown(ICP) 
  是 
  MySQL 5.6 
  中新特性,是一种在存储引擎层使用索引过滤数据的一种优化方式。ICP 
  可以减少存储引擎访问基表的次数以及 
  MySQL 
  服务器访问存储引擎的次数。  
 
 
 10.1 使用前后的扫描过程对比
 
  在不使用 
  ICP 
  索引扫描的过程:  
 
 
  
  storage 
  层:只将满足 
  index key 
  条件的索引记录对应的整行记录取出,返回给 
  server 
  层  
 
 
  
  server  
  层:对返回的数据,使用后面的 
  where 
  条件过滤,直至返回最后一行。 
 
 
  
 
 
   server层在生成执行计划后, 按如下步骤执行查询: 
 
 
 
   1. server层首先调用存储引擎的接口进行读数据(read data)==>定位到满足条件的第一条二级索引记录(Read index) 
 
 
 
   2. 根据B+树索引快速定位到这条二级索引记录后, 根据二级索引记录的主键值进行回表操作(get records),将完整的用户记录返回给存储引擎(Load data), 将完整记录返回给server层 
 
 
 
   3. server层再根据using where 判断其他搜索条件是否成立, 如果成立则将其发送给其他客户端; 否则向存储引擎要下一条数据 
 
 
 
   4. 由于每条记录都有next_record 属性, 根据该属性定位下一条符合条件的二级索引记录  
 
 
  
 
   下图即Using prefix index to get records过程 
 
 
  
 
  
   使用 
   ICP 
   扫描的过程:  
  
 
   
   storage 
   层:  
  
 
   
   首先将 
   index key 
   条件满足的索引记录区间确定,然后在索引上使用 
   index filter对每条记录 
   进行过滤。将满足的 
   index filter条件的索引记录才去回表取出整行记录返回 
   server 
   层。不满足 
   index filter 
   条件的索引记录丢弃,不回表、也不会返回server 
   层, 之后判断下一条数据。  
  
 
   
   server  
   层:  
  
 
   
   对返回的数据,使用 
   table filter 
   条件做最后的过滤。 
  
 
   
 
  
     server层在生成执行计划后, 按如下步骤执行查询: 
   
 
   
     1. server层首先调用存储引擎的接口进行读数据(read data)==>定位到满足条件的第一条二级索引记录(Read index) 
   
 
   
     2. 根据B+树索引快速定位到这条二级索引记录后, 先不进行回表操作(get records),而是 
    先判断一下所有关于索引中包含的列的条件( 
    就是假如使用的是联合索引, 而其他条件所在列恰好也在联合索引内)是否成立(Using index condition), 如果不成立, 直接跳过不再回表, 如果成立, 正常回表并将完整的用户记录返回给存储引擎(Load data), 将完整记录返回给server层 
   
 
   
     3. server层再判断其他搜索条件( 
    不在联合索引内,如果有这样的条件还要加上using where)是否成立, 如果成立则将其发送给其他客户端; 否则向存储引擎要下一条数据 
   
 
   
     4. 由于每条记录都有next_record 属性, 根据该属性定位下一条符合条件的二级索引记录, 并继续上述操作 
   
 
  
    下图即 Using index condition 操作 
  
 
  
 
 
 使用前后的成本差别  
 
 
 使用前,存储层多返回了需要被 
 index filter 
 过滤掉的整行记录  
 
 
 使用 
 ICP 
 后,直接就去掉了不满足 
 index filter 
 条件的记录,省去了他们回表和传递到 
 server 
 层的成本。  
 
 
 ICP 
 的  
 加速效果  
 取决于在存储引擎内通过  
 ICP 
 筛选  
 掉的数据的比例。  
 
10.2 ICP的使用条件
 
  ICP 
  的使用条件:  
 
 
  
  ① 只能用于二级索引 
  (secondary index)  
   毕竟一级索引也不需要回表 
 
 
  
  ② 
  explain 
  显示的执行计划中 
  type 
  值( 
  join  
  类型)为  
  range  
  、  
  ref  
  、  
  eq_ref  
  或者  
  ref_or_null  
  。  
 
 
  
  ③ 并非全部 
  where 
  条件都可以用 
  ICP 
  筛选,如果 
  where 
  条件的字段不在索引列中,还是要读取整表的记录到server 
  端做 
  where 
  过滤。  
 
 
  
  ④  
  ICP 
  可以用于 
  MyISAM 
  和 
  InnnoDB 
  存储引擎  
 
 
  
  ⑤  
  MySQL 5.6 
  版本的不支持分区表的 
  ICP 
  功能, 
  5.7 
  版本的开始支持。  
 
 
  
  ⑥ 当 
  SQL 
  使用覆盖索引时,不支持 
  ICP 
  优化方法。 
 
 
 10.3 ICP使用案例
 
 
 12. 其它查询优化策略
12.1 EXISTS 和 IN 的区分
 
 问题:  
 
 
 不太理解哪种情况下应该使用 EXISTS,哪种情况应该用 IN。选择的标准是看能否使用表的索引吗? 
 
  这两条语句有一些区别 : 上面的是不相关子查询, 需要从内部查出数据给外边用 
 
                                       : 下面的是相关子查询, 需要从外部传入数据给内部用 
 
 
 
12.2 COUNT(*)与COUNT(具体字段)效率
面试经常问
 
 问:在  
 MySQL  
 中统计数据表的行数,可以使用三种方式:  
 SELECT COUNT(*)  
 、  
 SELECT COUNT(1)  
 和  
 SELECT COUNT(具体字段 
 )  
 ,使用这三者之间的查询效率是怎样的?  
 

12.3 关于SELECT(*)
 
 在表查询中,建议明确字段,不要使用  
 *  
 作为查询的字段列表,推荐使用 
 SELECT < 
 字段列表 
 >  
 查询。原因:  
 
 
 ①  
 MySQL  
 在解析的过程中,会通过  
 查询数据字典  
 将 
 "*" 
 按序转换成所有列名,这会大大的耗费资源和时  
 
 
 间。  
 
 
 ② 无法使用  
 覆盖索引  
 
12.5 多使用COMMIT
 
  只要有可能,在程序中尽量多使用  
  COMMIT 
  ,这样程序的性能得到提高,需求也会因为  
  COMMIT  
  所释放的资源而减少。  
 
 
  
  COMMIT  
  所释放的资源:  
 
 
  
          回滚段上用于恢复数据的信息  
 
 
  
          被程序语句获得的锁  
 
 
  
          redo / undo log buffer 中的空间  
 
 
  
          管理上述 3  
  种资源中的内部花费 
 
 
 3 join语句原理
我碰见题时候再来补充
4. 排序优化
同上



















