本文给大家分享的是作者在使用mysql进行千万级数据量分页查询的时候进行性能优化的方法,对我们学习mysql性能优化非常有帮助
mysql数据量大时使用limit分页,随着页码的增大,查询效率越低下。
实验
1.准备1000w数据,直接使用limit start, count分页语句:
select * from user_operation_log limit start, count
当起始页较小时,查询没有性能问题,我们分别看下从100, 1000, 10000,100000,1000000, 9000000开始分页的执行时间(每页取100条), 如下:
SELECT * FROM `user_operation_log` LIMIT 100, 100 运行时间:0.014s
SELECT * FROM `user_operation_log` LIMIT 1000, 100 运行时间:0.015s
SELECT * FROM `user_operation_log` LIMIT 10000, 100 运行时间:0.021s
SELECT * FROM `user_operation_log` LIMIT 100000, 100 运行时间:0.332s
SELECT * FROM `user_operation_log` LIMIT 1000000, 100 运行时间:1.637s
SELECT * FROM `user_operation_log` LIMIT 9000000, 100 运行时间:12.591s
最后一条sql取出的时间将近13s,
显然这种时间是无法忍受的。
从中我们也能总结出两件事情:
1)limit语句的查询时间与起始记录的位置成正比
2)mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。
2.对limit分页问题的性能优化方法
利用表的覆盖索引来加速分页查询
我们都知道,利用了索引查询的语句中如果只包含了那个索引列(覆盖索引),那么这种情况会查询很快。
因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。
在我们的例子中,我们知道id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何:
这次我们之间查询最后一页的数据(利用覆盖索引,只包含id列),如下:
SELECT id FROM `user_operation_log` LIMIT 9000000, 100 运行时间:3.378s
我们更换上面的写法,使用join的方式
SELECT * FROM `user_operation_log` a join (SELECT id FROM `user_operation_log` LIMIT 9000000, 100)b where a.id=b.id 运行时间:3.485s
缩短了将近10s
还有一种写法,但是只针对于自增主键
SELECT * FROM `user_operation_log` where id >= (SELECT id FROM `user_operation_log` LIMIT 9000000, 1) limit 100 运行时间:3.372s
3.总结
1)分页查询每页的数据量越大查询效果越差,所以分页的时候应该控制每页的数据量。
2)查询的时候建议使用覆盖索引,非必要字段不返回同样有利于查询速度提升,在写SQL的时候要合理利用索引去优化。