网站LOGO
逐暗者的麦田
页面加载中
4月25日
网站LOGO 逐暗者的麦田
一个java软件攻城狮
菜单
  • 逐暗者的麦田
    一个java软件攻城狮
    用户的头像
    首次访问
    上次留言
    累计留言
    我的等级
    我的角色
    打赏二维码
    打赏博主
    知识点整理(五)——mysql分页问题
    点击复制本页信息
    微信扫一扫
    文章二维码
    文章图片 文章标题
    创建时间
  • 一 言
    确认删除此评论么? 确认
  • 本弹窗介绍内容来自,本网站不对其中内容负责。
    按住ctrl可打开默认菜单

    知识点整理(五)——mysql分页问题

    shellingford · 原创 ·
    程序人生 · java知识点整理mysql
    共 2723 字 · 约 2 分钟 · 269
    本文最后更新于2023年08月05日,已经过了264天没有更新,若内容或图片失效,请留言反馈

    前言

    mysql在大数据量的情况下使用limit分页,会随着页码增大而查询效率低下。该怎么优化呢?

    先看是不是,再看为什么,最后看怎么办

    准备

    mysql

    本次操作使用mysql8

    为了验证大数据量,我们先准备一张5000万条记录的表。

    mysql 代码:
    CREATE TABLE `demo_5000` (
      `id` bigint NOT NULL AUTO_INCREMENT,
      `a` int NOT NULL,
      `b` int NOT NULL,
      `c` int NOT NULL,
      `d` varchar(45) NOT NULL,
      `f` varchar(45) NOT NULL,
      `g` varchar(45) NOT NULL,
      PRIMARY KEY (`id`),
      KEY `idx_combo` (`a`,`b`,`c`)
    ) ENGINE=InnoDB AUTO_INCREMENT=50010007 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

    一张简单的表,主键自增,3个int字段和3个varchar字段,并建立一个联合索引。

    sql语句

    mysql 代码:
    set profiling = 1;

    临时开启性能分析。

    mysql 代码:
    show profile CPU,SWAPS,BLOCK IO,MEMORY,SOURCE for query [querID]

    查看性能。

    explain (查看执行计划) 和 SQL_NO_CACHE (跳过缓存)

    limit offset,size 分页

    根据a字段降序,进行分页查询
    • 查询1万左右的
    mysql 代码:
    select SQL_NO_CACHE * from demo_5000  order by id desc  limit 10000,100;

    使用 show profile 查看性能。

    • 查询10万左右的
    mysql 代码:
    select SQL_NO_CACHE * from demo_5000  order by id desc  limit 100000,100;
    • 查询100万左右的
    mysql 代码:
    select SQL_NO_CACHE * from demo_5000  order by id desc  limit 1000000,100;

    到这里我们其实就可以看出结果了,随着页码变大,效率会急剧下降。虽然每一次查询只取100条数据,但查询前1万和前10万左右的记录时间是差不多的,但到100万时性能就相差非常大。(当然这和表结构有关)

    为什么?

    那为什么会这样呢?我们可以使用执行计划来看一下。

    mysql 代码:
    explain select * from demo_5000  order by a desc  limit 10000,100;
    explain select * from demo_5000  order by a desc  limit 100000,100;
    explain select * from demo_5000  order by a desc  limit 1000000,100;


    可以看到实际上mysql会扫描offset数量,然后再取100条。尤其是第三条语句,mysql甚至认为预计需要扫描4000w条以至于直接放弃使用索引了。

    这就是为什么页码越大,性能越差的原因。

    怎么优化

    先查询id,然后通过id来查询其余的数据。
    mysql 代码:
    select SQL_NO_CACHE id from demo_5000  order by a desc  limit 1000000,100;

    再看看执行计划

    可以看到,如果只是查询主键id,那么mysql不会回表查询,而且会使用到索引,这样效率会非常高。即使查询id的时候依然会扫描100万条索引,但扫描索引比扫描数据要高效的多。

    利用上一页的查询结果

    在有些场景下,既然查询到第1万页了,那也应该查询过第9999页。我们可以利用上一页的最大id,或者排序字段来作为where条件,这样就能避免offset太大了。

    mysql 代码:
    select SQL_NO_CACHE id from demo_5000  where a<=4900450   order by a desc  limit 0,100;

    这样查询效率是最高的,并且扫描行数也是最少的。

    声明:本文由 shellingford(博主)原创,依据 CC-BY-NC-SA 4.0 许可协议 授权,转载请注明出处。

    还没有人喜爱这篇文章呢

    发一条! 发一条!
    博客logo 逐暗者的麦田 一个java软件攻城狮
    MOEICP 萌ICP备20237379号 ICP 沪ICP备13037081号-2,沪ICP备13037081号-1,沪ICP备13037081号-3 又拍云 本站由又拍云提供CDN加速/云存储服务

    🕛

    本站已运行 2 年 243 天 10 小时 23 分

    🌳

    自豪地使用 Typecho 建站,并搭配 MyLife 主题
    逐暗者的麦田. © 2021 ~ 2024.
    网站logo

    逐暗者的麦田 一个java软件攻城狮
     
     
     
     
    壁纸