在使用一些常规的 SQL 时,如果我们通过一些方法和技巧来优化这些 SQL 的实现,在性能上就会比使用常规通用的实现方式更
- 优化分页查询
通常我们是使用 <LIMIT M,N> + 合适的 order by 来实现分页查询,这种实现方式在没有任何索引条件支持的情况下,需要做大量的文件排序操作(file sort),性能将会非常得糟糕。如果有对应的索引,通常刚开始的分页查询效率会比较理想,但越往后,分页查询的性能就越差。
这是因为我们在使用 LIMIT 的时候,偏移量 M 在分页越靠后的时候,值就越大,数据库检索的数据也就越多。例如 LIMIT 10000,10 这样的查询,数据库需要查询 10010 条记录,后返回 10 条记录。也就是说将会有 10000 条记录被查询出来没有被使用到。
我们模拟一张 10 万数量级的 order 表,进行以下分页查询:
通过 EXPLAIN 分析可知:该查询使用到了索引,扫描行数为 10020 行,但所用查询时间为 0.018s,相对来说时间偏长了。
利用子查询优化分页查询
以上分页查询的问题在于,我们查询获取的 10020 行数据结果都返回给我们了,我们能否先查询出所需要的 20 行数据中的 小 ID 值,然后通过偏移量返回所需要的 20 行数据给我们呢?我们可以通过索引覆盖扫描,使用子查询的方式来实现分页查询:
通过 EXPLAIN 分析可知:子查询遍历索引的范围跟上一个查询差不多,而主查询扫描了更
多的行数,但执行时间却减少了,只有 0.004s。这就是因为返回行数只有 20 行了,执行效率得到了明显的提升。
在开发中,我们要尽量写出高性能的 SQL 语句,但也无法避免一些慢 SQL 语句的出现,或因为疏漏,或因为实际生产环境与开发环境有所区别,这些都是诱因。面对这种情况,我们可以打开慢 SQL 配置项,记录下都有哪些 SQL 超过了预期的 大执行时间。首先,我们可以通过以下命令行查询是否开启了记录慢 SQL 的功能,以及 执行时间是多少:
- Show variables like 'slow_query%';
- Show variables like 'long_query_time';
如果没有开启,我们可以通过以下设置来开启:
复制代码
- set global slow_query_log='ON'; // 开启慢 SQL 日志
- set global slow_query_log_file='/var/lib/mysql/test-slow.log';// 记录日志地址
- set global long_query_time=1;// 最大执行时间