一般来讲,我们拿到一条“不是很优化”、“烂的”、“慢的” 等 SQL 语句(至于怎么拿到这条语句,不在本篇讨论范围),应该按照以下几个步骤来逐步分析:
一、定位该 SQL 语句涉及到的表结构,确认是磁盘表还是视图,如果是磁盘表,那么该考虑以下几点:
这些表是否统一为 InnoDB 引擎(MySQL 5.7 以及以前一些老旧版本可能会有非 InnoDB 引擎表),如果不是,转换表引擎为 InnoDB 。因为 MySQL 从 5.5 版本开始,所有针对存储层的优化都是针对 InnoDB 引擎的。 极个别表为临时表。查看临时表相关参数是否设置合理;或者说能否把临时表替换为磁盘表。 查询每张表的字段类型,看有无不合理的部分。 查询每张表的记录数,检查是否过大需要后续拆分。 查询每张表的统计信息,检查是否及时做了更新。 针对这些表结构做进一步分析,查看索引设计是否合理?大致会有以下几种结果:
(2)都有主键或者唯一索引,但是没有二级索引。
(4)有主键或者唯一索引,也有一些二级索引,但是这些二级索引可选择性很差。
二、如果有些表是视图,需要考虑以下几点:
该视图内部的算法有两种,一种是临时表(TEMPTABLE)、另外一种是合并(MERGE )。可以针对这两种算法来分别测试视图整体性能哪个较优化。 该视图内部如果有很复杂的处理逻辑,想办法把这部分内容简化或者从数据库剥离转交给应用处理,避免数据库将其劣势放大。 该视图如果非必须,可拆解为基表与上层SQL 语句做合并处理,这样效率较之前更优化(比如视图内部多表关联与上层基表再次关联,拆分后,优化器就会有更多更优的表关联顺序)。
三、到了这一步,如果是多张表关联,此处检查表关联键:
表关联键为主键和外键,也即两表用来关联的字段在一张表唯一并且在另一张表被引用,这时需要补充额外的过滤条件来减少扫描记录数。 表关联键为非主键,也即两表用来关联的字段都不唯一, 需要优化为唯一键值关联。 表关联键字段编码不一致,需要人为转换字段编码并改为一致。
四、基于以上几点,表结构分析这块已经大致完毕。接下来从 SQL 语句层面来分析,比如这条 SQL 语句能否修改为更加优化的方式。可以考虑以下两点:
SQL 语句本身很简单,没有必要做修改。 比如这条语句本身是20张表的内联查询,那它不够优化并不是因为写的不好,而是表关联个数实在太多。
SQL 语句本身很复杂,仔细分析后,可以简化这条语句的写法。 复杂 SQL 语句又可以分为很多类别,比如多张子表关联、多张表嵌套子查询、多个子查询合并输出、多个聚合类操作等等。每种都有不同的优化方法,后续我会一一介绍。
五、那么前面几点做完后,进一步分析优化后 SQL 语句的执行计划(如果有条件模拟生产环境压力模型),一般考虑如下几点:
改写后的语句执行计划很优化,走最合适的索引、语句本身也改的很简洁,那么这条语句改写完成。 改写后的语句执行计划没有走合适的索引,可以考虑在表上建立合适的索引。如果建新索引后,这条语句执行效果很好,那么改写完成。 改写后的语句走了合适的索引,执行效果依然不理想,这时可能有以下几种原因:
比如日期字段,过滤条件为昨天的查询记录数为100条,过滤条件为前天的查询记录数则变为1W条。