展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > MySQL调优之SQL查询深度分页问题怎么解决

MySQL调优之SQL查询深度分页问题怎么解决

SQLPro
SQLPro

SQLPro 是一款macOS平台上数据库管理应用,避免使用非法,享受更全面的支持和更新。它更贴近日常 macOS 使用场景,处理高频操作时整体会更顺手一些。

¥119
macOS 2026-09-24
正版软件 macOS软件 数据库管理工具 macOS
立即下载

一、问题引入例如当前存在一张表test_user,然后往这个表里面插入3百万的数据:CREATETABLE`test_user`(`id`int(11)NOTNULLAUTO_INCREMENTCOMMENT'主键id',`user_id`varchar(36)NOTNULLCOMMENT'用户id',`user_name`varchar(30)NOTNULLCOMMENT'用户名称',`phone`varchar(20)NOTNULLCOMMENT'

本文目录

    一、问题引入

    例如当前存在一张表test_user,然后往这个表里面插入3百万的数据:

    CREATE TABLE `test_user` (
      `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键id',
      `user_id` varchar(36) NOT NULL COMMENT '用户id',
      `user_name` varchar(30) NOT NULL COMMENT '用户名称',
      `phone` varchar(20) NOT NULL COMMENT '手机号码',
      `lan_id` int(9) NOT NULL COMMENT '本地网',
      `region_id` int(9) NOT NULL COMMENT '区域',
      `create_time` datetime NOT NULL COMMENT '创建时间',
      PRIMARY KEY (`id`),
      KEY `idx_user_id` (`user_id`)
    ) ENGINE=InnoDB AUTO_INCREMENT;

    在数据库开发过程中我们经常会使用分页,核心技术是使用用 limit start, count 分页语句进行数据的读取。 

    我们分别看下从0、10000、100000、500000、1000000、1800000开始分页的执行时长(每页取100条)。

    SELECT * FROM test_user LIMIT 0,100;         # 0.031
    SELECT * FROM test_user LIMIT 10000,100;     # 0.047
    SELECT * FROM test_user LIMIT 100000,100;    # 0.109
    SELECT * FROM test_user LIMIT 500000,100;    # 0.219
    SELECT * FROM test_user LIMIT 1000000,100;   # 0.547s
    SELECT * FROM test_user LIMIT 1800000,100;   # 1.625s

    我们已经看出随着起始记录的增加,时间也随着增大。这说明分页语句limit跟起始页码是有很大关系的,那么我们把起始记录改为290w看下:

    SELECT * FROM test_user LIMIT 2900000,100; # 3.062s

    我们惊讶的发现MySQL在数据量大的情况下分页起点越大,查询速度越慢! 

    那么为什么会出现上述这种情况呢?

    答案: 因为 limit 2900000,100 的语法实际上是mysql扫描到前2900100条数据,之后丢弃前面的3000000行,这个步骤其实是浪费掉的。

    从中我们也能总结出以下两件事情:

    limit语句的查询时间与起始记录的位置成正比。

    mysql的limit语句是很方便,但是对记录很多的表并不适合直接使用。

    二、MySQL中的limit用法

    limit子句可以被用于强制select语句返回指定的记录数,其语法格式如下:

    SELECT * FROM 表名 limit m,n;
    SELECT * FROM table LIMIT [offset,] rows;

    limit接受一个或两个数字参数,参数必须是一个整数常量,如果给定两个参数:

    第一个参数指定第一个返回记录行的偏移量
    第二个参数指定返回记录行的最大数目

    2.1 m代表从m+1条记录行开始检索,n代表取出n条数据。(m可设为0) 

    SELECT * FROM 表名 limit 6,5;

    上述SQL表示从第7条记录行开始算,取出5条数据 

    2.2 值得注意的是,n可以被设置为-1,当n为-1时,表示从m+1行开始检索,直到取出最后一条数据

    SELECT * FROM 表名 limit 6,-1;

    上述SQL表示取出第6条记录行以后的所有数据

    2.3 若只给出m,则表示从第1条记录行开始算一共取出m条

    SELECT * FROM 表名 limit 6;

    2.4 以年龄倒序后取出前3行

    select * from student order by age desc limit 3;

    2.5 跳过前3行后再2取行

    select * from student order by age desc limit 3,2;

    三、深度分页优化策略

    方法一:用主键id或者唯一索引优化

    即先找到上次分页的最大id,然后利用id上的索引来查询:

    SELECT * FROM test_user WHERE id>1000000 LIMIT 100; # 0.047秒

    使用此优化SQL相比于前面的查询速度已经快了11倍。除了主键ID,也可以利用唯一索引快速定位部分数据,避免全表扫描。例如读取第1000到1019行数据(pk是唯一键),则相对应的优化SQL如下:

    SELECT * FROM 表名称 WHERE pk>=1000 ORDER BY pk ASC LIMIT 0,20

    原因:索引扫描,速度会很快。

    适用场景:如果数据查询出来是按照pk或者id进行排序,并且全部数据没有缺失的话则可以这样优化,否则分页操作会漏数据。

    方法二:利用索引覆盖优化

    我们都知道,利用了索引查询的语句中如果只包含了那个索引列(也就是索引覆盖),那么这种情况会查询很快。

    为什么索引覆盖查询会很快呢?

    答案:因为利用索引查找有优化算法,且数据就在查询索引上面,不用再去找相关的数据地址了,这样节省了很多时间。另外Mysql中也有相关的索引缓存,在并发高的时候利用缓存就效果更好了。

    在我们的测试表test_user中,id字段是主键,自然就包含了默认的主键索引。现在让我们看看利用覆盖索引的查询效果如何。

    这次我们查询第1000001到1000100行的数据(利用覆盖索引,只包含id列):

    SELECT id FROM test_user LIMIT 1000000,100; # 0.843秒

    从这个结果中发现查询速度比全表扫描速度还要慢(当然在重复执行这条SQL,多次查询之后速度还是变快了很多,几乎省了一半时间,这是由于缓存的原因), 接着使用explain命令来查看该SQL的执行计划,发现该SQL执行采用的普通索引 idx_user_id:

    EXPLAIN SELECT id FROM test_user LIMIT 1000000,100;

    MySQL调优之SQL查询深度分页问题怎么解决

    如果我们把普通索引给删除的话,就会发现执行上述SQL其采用的会是主键索引。那如果不删除普通索引的话,针对这种情况,我们要让上述SQL走主键索引的话,则可以使用order by语句:

    SELECT id FROM test_user ORDER BY id ASC LIMIT 1000000,100; # 0.250秒

    那么如果我们也要查询所有列,有两种方法,一种是id>=的形式,另一种就是利用join。

    第一种写法: 

    SELECT * FROM test_user WHERE ID >= (SELECT id FROM test_user ORDER BY id ASC LIMIT 1000000,1) LIMIT 100;

    上述SQL查询时间为0.281秒

    第二种写法:

    SELECT * FROM (SELECT id FROM test_user ORDER BY id ASC LIMIT 1000000,100) a LEFT JOIN test_user b ON a.id = b.id;

    上述SQL查询时间为0.252秒 

    方法三:基于索引再排序

    其中pageNum表示页码,其取值从0开始;pageSize表示指的是每页多少条数据。

    SELECT * FROM 表名称 WHERE id_pk > (pageNum*pageSize) ORDER BY id_pk ASC LIMIT pageSize;

    适应场景:

    • 适用于数据量多的情况

    • 最好ORDER BY后的列对象是主键或唯一索引

    • id数据没有缺失,可以作为序号使用

    • 使用ORDER BY操作能利用索引被消除,但结果集是稳定的

    原因:

    • 索引扫描,速度会很快

    • 但MySQL的排序操作,只有ASC没有DESC。MySQL中索引存储的排序方式是ASC的,没有DESC的索引。这就能够理解为啥order by 默认是按照ASC来排序的了吧

    方法四:基于索引使用prepare

    PREPARE预编译一个SQL语句,并为其分配一个名称 stmt_name,以便以后引用该语句,预编译好的语句用EXECUTE执行。 

    PREPARE stmt_name FROM 'SELECT * FROM test_user WHERE id > ? ORDER BY id ASC LIMIT ?';
    SET @a = 1000000;
    SET @b = 100;
    EXECUTE stmt_name USING @a, @b;;

    MySQL调优之SQL查询深度分页问题怎么解决

    上述SQL查询时间为0.047秒。 

    对于定义好的PREPARE预编译语句,我们可以使用下述命令来释放该预编译语句:

    DEALLOCATE PREPARE stmt_name;

    原因:

    • 索引扫描,速度会很快.

    • prepare语句又比一般的查询语句快一点。

    方法五:利用"子查询+索引"快速定位数据 

    其中page表示页码,其取值从0开始;pagesize表示指的是每页多少条数据。 

    SELECT * FROM your_table WHERE id <= (SELECT id FROM your_table ORDER BY id DESC LIMIT ($page-1)*$pagesize ORDER BY id DESC LIMIT $pagesize);

    方法六:利用复合索引进行优化

    假设数据表 collect ( id, title ,info ,vtype) 就这4个字段,其中id是主键自增,title用定长,info用text, vtype是tinyint,vtype是一个普通索引。

    现在往里面填充数据,填充10万条记录,数据库表占用硬1.6G。

    select id,title from collect limit 1000,10;

    执行上述SQL速度很快,基本上0.01秒就OK。

    select id,title from collect limit 90000,10;

    然后再执行上述SQL,就发现非常慢,基本上平均8~9秒完成。

    这个时候如果我们执行下述,我们会发现速度又变的很快,0.04秒就OK。

    select id from collect order by id limit 90000,10;

    那么这个现象的原因是什么?

    答案:因为用了id主键做索引,  这里实现了索引覆盖,当然快。

    所以如果想一起查询其它列的话,可以按照索引覆盖进行优化,具体如下:

    select id,title from collect where id >= (select id from collect order by id limit 90000,1) limit 10;

    再看下面的语句,带上where 条件:

    select id from collect where vtype=1 order by id limit 90000,10;

    可以发现这个速度上也是很慢的,用了8~9秒!

    这里有一个疑惑:vtype 做了索引了啊?怎么会慢呢?

    vtype做了索引是不错,如果直接对vtype进行过滤:

    select id from collect where vtype=1 limit 1000,10;

    可以看到速度还是很快的,基本上0.05秒,如果从9万开始,那就是0.05*90=4.5秒的速度了。

    其实加了 order by id 就不走索引,这样做还是全表扫描,解决的办法是:复合索引!

    因此针对下述SQL深度分页优化时可以加一个search_index(vtype,id)复合索引:

    select id from collect where vtype=1 order by id limit 90000,10;

    综上: 

    • 在进行SQL查询深度分页优化时,如果对于有where条件,又想走索引用limit的,必须设计一个索引,将where放第一位,limit用到的主键放第二位,而且只能select 主键。

    • 最后根据查询出的主键走一级索引找到对应的数据。

    • 按这样的逻辑,百万级的limit 在0.0x秒就可以分完,完美解决了分页问题。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 MySQL SQL
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    Aperty macOS版
    Aperty macOS版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw macOS版
    AionClaw macOS版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy macOS版
    Loomy macOS版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirBuddy 3 macOS版
    AirBuddy 3 macOS版

    AirBuddy 3 是面向 macOS 的蓝牙外设增强工具,可集中查看 AirPods、Beats 与苹果设备电量,提供快速连接、播放控制、电量提醒、桌面小组件和多台 Mac 外设接力等功能。

    AirServer macOS版
    AirServer macOS版

    AirServer macOS版可把 Mac 转换为无线投屏接收端,通过 AirPlay 或 Google Cast 接收手机、平板和电脑画面,并支持多设备同时连接、高清镜像及会话录制,适合家庭娱乐、课堂教学、会议演示和应用展示。

    AnyDesk macOS版
    AnyDesk macOS版

    AnyDesk macOS版是一款适用于远程办公、设备维护和客户支持的远程桌面工具,可连接并操作异地计算机,支持文件传输、无人值守访问、会话权限控制及跨平台协作。

    WINDOWS 更多
    讯飞绘文 网页版
    讯飞绘文 网页版

    讯飞绘文网页版是科大讯飞推出的AI图文创作与内容运营工具,覆盖热点选题、文章生成、稿件校对、智能配图、排版发布和数据复盘等环节,适合自媒体创作者及内容团队在线使用。

    Maya(Autodesk Maya) Windows版
    Maya(Autodesk Maya) Windows版

    Autodesk Maya 是面向影视、电视、动画和游戏行业的专业三维制作软件,集多边形与 NURBS 建模、角色绑定、关键帧和动作捕捉动画、Bifrost 特效模拟、材质开发及 Arnold 渲染于一体,

    Aperty Windows版
    Aperty Windows版

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    火山引擎 网页版
    火山引擎 网页版

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    立刻MV 网页版
    立刻MV 网页版

    立刻MV 面向音乐人、内容创作者和品牌团队,帮助用户低成本完成歌曲 MV、歌词视频、AI 分镜、图生视频与最终合成。

    蛙蛙写作 网页版
    蛙蛙写作 网页版

    蛙蛙写作 AI 创作工具,覆盖小说、剧本、文案,一键生成文稿,打通文字转视频全流程,高效解决创作难题。

    讯飞智作 网页版
    讯飞智作 网页版

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    超级简历WonderCV 网页版
    超级简历WonderCV 网页版

    超级简历WonderCV是面向应届生和AI小白的智能求职平台,覆盖简历、面试与职业规划。

    音述AI 网页版
    音述AI 网页版

    音述AI,是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区。

    AionClaw Windows版
    AionClaw Windows版

    AionClaw 是可在桌面端运行的任务型 AI 助手,通过数字专家与技能市场组合办公、创作、数据和开发能力。

    Loomy Windows版
    Loomy Windows版

    Loomy 是科大讯飞推出的桌面 AI 助手,可通过对话、任务与工作目录协助处理办公、内容创作和资料整理。

    AirServer Windows版
    AirServer Windows版

    AirServer Windows版可把电脑变成AirPlay、Google Cast和Miracast无线投屏接收端,适合会议演示、课堂教学及家庭大屏分享。发送设备通常无需另装客户端,并可同时接收和智能排列多个镜像会话。

    即将离开本站
    您即将前往第三方网站,请确认是否继续?