MySQL百万数据分页查询优化

创建表

创建表并初始化百万条数据至表中

CREATE TABLE `orm_user` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
  `name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '加密后的密码',
  `salt` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '加密使用的盐',
  `email` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '邮箱',
  `phone_number` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '手机号码',
  `status` int NOT NULL DEFAULT '1' COMMENT '状态,-1:逻辑删除,0:禁用,1:启用',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `last_login_time` datetime DEFAULT NULL COMMENT '上次登录时间',
  `last_update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '上次更新时间',
  PRIMARY KEY (`id`),
  KEY `create_time` (`create_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='示例表';

使用limit查询尝试

SQL_NO_CACHE
这个关键词是为了不让SQL查询走缓存。
SELECT SQL_NO_CACHE * from orm_user where create_time BETWEEN '2023-08-01 00:00:00' and  '2023-08-30 23:59:59' LIMIT 1, 10

查询前10条基本不消耗时间
查询前10条数据基本不消耗时间

SELECT SQL_NO_CACHE * from orm_user where create_time BETWEEN '2023-08-01 00:00:00' and  '2023-08-30 23:59:59' LIMIT 1600000, 10

将偏移量至百万,查询耗时1s左右
在这里插入图片描述

优化方案

SELECT SQL_NO_CACHE * from
(SELECT SQL_NO_CACHE id from orm_user orm_user where create_time BETWEEN '2023-08-01 00:00:00' and  '2023-08-30 23:59:59' LIMIT 1600000, 10) as temp INNER JOIN orm_user ou on ou.id = temp.id

耗时0.7s左右
在这里插入图片描述

原因分析

我们一般对于查询频率比较高的字段会建立索引。索引会提高我们的查询效率。我们上面的语句使用了SELECT * FROM orm_user,但是我们并不是所有的字段都建立了索引。当从索引文件中查询到符合条件的数据后,还需要从数据文件中查询到没有建立索引的字段。那么这个过程称之为回表。

覆盖索引

如果查询的字段正好创建了索引了,比如 SELECT create_time FROM orm_user,我们查询的字段是我们创建的索引,那么这个时候就不需要再去数据文件里面查询,也就不需要回表。这种情况我们称之为覆盖索引

IO

回表操作通常是IO操作,因为需要根据索引查找到数据行后,再根据数据行的主键或唯一索引去聚簇索引中查找具体的数据行。聚簇索引一般是存储在磁盘上的数据文件,因此在执行回表操作时需要从磁盘读取数据,而磁盘IO是相对较慢的操作。
LIMTI 1600000,10 ?
你有木有想过LIMIT 1600000,10会不会扫描1-1600000行,你之前有没有跟我一样,觉得数据是直接从1600000行开始取的,前面的根本没扫描或者不回表。其实这样的写法,一个完整的流程是查询数据,如果不能覆盖索引,那么也是要回表查询数据的。
现在你知道为什么越到后面查询越慢了吧!

问题总结

我们现在知道了LIMIT 遇到后面查询的性能越差,性能差的原因是因为要回表,既然已经找到了问题那么我们只需要减少回表的次数就可以提升查询性能了。

解决方案

既然覆盖索引可以防止数据回表,那么我们可以先查出来主键id(主键索引),然后将查出来的数据作为临时表然后 JOIN 原表就可以了,这样只需要对查询出来的10条结果进行数据回表,大幅减少了IO操作。

文章参考来源

https://juejin.cn/post/7230979300828151865#heading-6

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL百万级数据查询优化是提高数据库性能的重要步骤。下面是一些建议: 1. 索引优化:通过合理的索引设计,能够加快查询速度。对于经常作为查询条件的列,添加索引能够提高查询效率。 2. 分页查询优化:对于大数据量的查询结果,可以使用分页查询来避免一次性加载所有数据。通过设置合理的分页大小,可以加快查询速度。 3. 使用合适的存储引擎:MySQL支持多种存储引擎,如InnoDB、MyISAM等。根据实际应用需求选择合适的存储引擎可以提高查询性能。 4. 查询语句优化:通过合理的查询语句设计,能够减少不必要的数据查询和计算,加快查询速度。例如,避免使用SELECT *查询所有列,只查询需要的列。 5. 分区表:对于大数据量的表,可以考虑使用分区表来提高查询性能。通过将表按照某个列进行分区,可以将数据分散存储在多个物理文件中,提高查询效率。 6. 调整内存和缓存配置:根据实际硬件情况和数据库负载,合理配置MySQL的内存和缓存参数,如缓存大小、连接池大小等,以提高数据库性能。 7. 查询计划优化:通过对查询执行计划进行分析,可以找出查询中存在的性能瓶颈,并对其进行优化。例如,添加合适的索引、调整查询语句等。 8. 数据库分片:对于超大规模的数据量,可以考虑将数据库分片存储在多个服务器上,通过分片查询来提高查询性能。 总之,针对百万级数据查询优化,需要综合考虑索引设计、分页查询、存储引擎选择、查询语句优化、分区表、内存和缓存配置、查询计划优化以及数据库分片等多个方面。不同的应用场景可能有不同的优化策略,需要结合实际情况进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值