[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"article-mysqlruhejiejueshendufenyewenti":3},{"id":4,"title":5,"slug":6,"summary":7,"content":8,"contentHtml":9,"wordCount":10,"readingTime":11,"categoryId":12,"tags":13,"coverImage":13,"thumbnail":13,"status":14,"isTop":15,"isRecommended":15,"allowComments":15,"password":13,"viewCount":16,"likeCount":15,"commentCount":15,"seoTitle":5,"seoKeywords":17,"seoDescription":18,"source":13,"sourceUrl":13,"publishTime":19},"2009074534064386049","MySQL如何解决深度分页问题？","mysqlruhejiejueshendufenyewenti","在MySQL开发中，除了计数场景，深度分页（即`LIMIT offset, size`中`offset`值极大的分页查询）也是高频遇到的性能问题。比如“查询第1000页数据，每页10条”（`LIMIT 9990, 10`），常会出现查询缓慢的情况。下面详细讲解深度分页的问题根源及解决方案。 ### 1. 深度分页的问题根源 先明确常规分页的实现方式：使用`LIMIT offset, size`，其中`offset`表示跳过前N条数据，`size`表示取N条数据。 问题核心：当`offset`极大时（如9990），MySQL需要先扫描并跳过前9990条数据，再取10条数据。即使查询条件有索引，也需要遍历索引到第9990条位置，才能定位到目标数据，导致IO开销大、查询效率低。 示例（低效查询）： ```sql -- 查询第1000页数据，每页10条，offset=9990 SELECT id,...","在MySQL开发中，除了计数场景，深度分页（即`LIMIT offset, size`中`offset`值极大的分页查询）也是高频遇到的性能问题。比如“查询第1000页数据，每页10条”（`LIMIT 9990, 10`），常会出现查询缓慢的情况。下面详细讲解深度分页的问题根源及解决方案。\n\n### 1. 深度分页的问题根源\n\n先明确常规分页的实现方式：使用`LIMIT offset, size`，其中`offset`表示跳过前N条数据，`size`表示取N条数据。\n\n问题核心：当`offset`极大时（如9990），MySQL需要先扫描并跳过前9990条数据，再取10条数据。即使查询条件有索引，也需要遍历索引到第9990条位置，才能定位到目标数据，导致IO开销大、查询效率低。\n\n示例（低效查询）：\n\n```sql\n\n-- 查询第1000页数据，每页10条，offset=9990\nSELECT id, name FROM test_table LIMIT 9990, 10;\n-- 问题：MySQL需扫描前9990条数据并跳过，仅返回最后10条，资源浪费严重\n```\n\n### 2. 解决方案（按适用场景排序）\n\n#### 方案1：基于主键\u002F索引排序+条件过滤（推荐，适用大部分场景）\n\n核心思路：利用主键或有序索引的连续性，通过`WHERE`条件直接定位到“上一页最后一条数据”，替代`offset`跳过数据。要求查询结果必须按主键或有序索引字段排序。\n\n实现步骤：\n\n1. 分页查询时，记录上一页最后一条数据的主键\u002F索引字段值（如最后一条数据的`id=9990`）；\n\n2. 下一页查询时，通过`WHERE 主键 > 上一页最后主键`直接过滤前9990条数据，再用`LIMIT size`取数。\n\n示例（优化后查询）：\n\n```sql\n\n-- 第1页查询（无offset，直接取前10条）\nSELECT id, name FROM test_table ORDER BY id ASC LIMIT 10;\n-- 记录第1页最后一条数据的id=10\n\n-- 第2页查询（通过id>10过滤前10条，无需offset）\nSELECT id, name FROM test_table WHERE id > 10 ORDER BY id ASC LIMIT 10;\n-- 记录第2页最后一条id=20\n\n-- 第1000页查询（直接过滤前9990条，效率极高）\nSELECT id, name FROM test_table WHERE id > 9990 ORDER BY id ASC LIMIT 10;\n```\n\n优点：利用索引快速定位，无需扫描跳过的数据，查询效率稳定且高效；缺点：仅支持“下一页”查询，不支持直接跳转到任意页（如直接跳第1000页，需知道第999页最后一条的id）。\n\n#### 方案2：游标分页（适合滚动加载场景）\n\n核心思路：MySQL的`CURSOR`（游标）本质是一个指向查询结果集的指针，可通过游标逐页读取数据，避免`offset`的低效扫描。适合“滚动加载更多”（如APP下拉加载）的场景，不支持跳页。\n\n实现步骤：\n\n```sql\n\n-- 1. 声明游标（指定查询条件和排序方式）\nDECLARE cur_page CURSOR FOR \nSELECT id, name FROM test_table ORDER BY id ASC;\n\n-- 2. 打开游标\nOPEN cur_page;\n\n-- 3. 读取数据（每次读取10条，即一页）\nFETCH cur_page INTO @id, @name; -- 逐行读取，可循环读取10条作为一页\n\n-- 4. 关闭游标\nCLOSE cur_page;\n```\n\n优点：适合大量数据的滚动加载，效率稳定；缺点：不支持直接跳页，语法较复杂，需在存储过程中使用。\n\n#### 方案3：预计算汇总表（适合静态\u002F低频更新数据）\n\n核心思路：如果数据是静态的（如历史订单、归档数据）或更新频率极低，可提前预计算分页所需的“分页标记”（如每10条数据的最大主键），存储在汇总表中。查询时直接从汇总表获取目标页的标记，再查询主表数据。\n\n实现示例：\n\n```sql\n\n-- 1. 创建汇总表（存储每页最后一条数据的id和页码）\nCREATE TABLE page_summary (\n    page_num INT PRIMARY KEY, -- 页码\n    last_id INT -- 该页最后一条数据的id\n);\n\n-- 2. 预插入数据（可通过定时任务更新）\nINSERT INTO page_summary VALUES \n(1, 10), (2, 20), ..., (1000, 10000);\n\n-- 3. 查询第1000页数据（先查汇总表，再查主表）\nSELECT last_id FROM page_summary WHERE page_num = 999; -- 得到第999页最后id=9990\nSELECT id, name FROM test_table WHERE id > 9990 ORDER BY id ASC LIMIT 10;\n```\n\n优点：查询速度极快，适合大数据量静态数据；缺点：不适合动态更新数据，需维护汇总表（增加存储和维护成本）。\n\n#### 方案4：限制分页深度（业务层面优化）\n\n核心思路：从业务角度限制用户的分页深度，避免用户查询过深的页码。比如“最多支持查询前100页数据”，超过则提示“数据过多，请缩小查询范围”。\n\n实现示例：\n\n```sql\n\n-- 限制offset最大值为9990（即最多100页）\nSELECT id, name FROM test_table \nWHERE offset \u003C= 9990 \nLIMIT #{offset}, #{size};\n```\n\n优点：简单易实现，从根源减少深度分页查询；缺点：有业务局限性，不适用于必须支持深分页的场景（如后台数据导出）。\n\n### 3. 方案选择总结\n\n|方案|适用场景|核心优势|局限性|\n|---|---|---|---|\n|主键\u002F索引条件过滤|大部分动态数据分页（如列表查询）|效率高、实现简单、兼容性好|不支持直接跳页|\n|游标分页|APP滚动加载、大量数据逐页读取|效率稳定、适合大数据量|不支持跳页、语法复杂|\n|预计算汇总表|静态\u002F低频更新数据（如归档、报表）|查询速度极快|需维护汇总表、不支持动态数据|\n|限制分页深度|业务允许限制分页范围（如前台列表）|实现简单、无性能开销|业务局限性大|\n补充提示：深度分页优化的核心是“避免扫描跳过无关数据”，无论哪种方案，都需确保查询条件中的排序字段有索引（如主键默认有索引），否则仍会出现全表扫描，优化失效。","\u003Cp data-line=\"0\">在MySQL开发中，除了计数场景，深度分页（即\u003Ccode>LIMIT offset, size\u003C\u002Fcode>中\u003Ccode>offset\u003C\u002Fcode>值极大的分页查询）也是高频遇到的性能问题。比如“查询第1000页数据，每页10条”（\u003Ccode>LIMIT 9990, 10\u003C\u002Fcode>），常会出现查询缓慢的情况。下面详细讲解深度分页的问题根源及解决方案。\u003C\u002Fp>\n\u003Ch3 data-line=\"2\" id=\"1. 深度分页的问题根源\">1. 深度分页的问题根源\u003C\u002Fh3>\n\u003Cp data-line=\"4\">先明确常规分页的实现方式：使用\u003Ccode>LIMIT offset, size\u003C\u002Fcode>，其中\u003Ccode>offset\u003C\u002Fcode>表示跳过前N条数据，\u003Ccode>size\u003C\u002Fcode>表示取N条数据。\u003C\u002Fp>\n\u003Cp data-line=\"6\">问题核心：当\u003Ccode>offset\u003C\u002Fcode>极大时（如9990），MySQL需要先扫描并跳过前9990条数据，再取10条数据。即使查询条件有索引，也需要遍历索引到第9990条位置，才能定位到目标数据，导致IO开销大、查询效率低。\u003C\u002Fp>\n\u003Cp data-line=\"8\">示例（低效查询）：\u003C\u002Fp>\n\n        \u003Cdetails  data-line=\"10\" class=\"md-editor-code\" open=\"\">\n          \u003Csummary class=\"md-editor-code-head\">\n            \u003Cdiv class=\"md-editor-code-flag\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv class=\"md-editor-code-action\">\n              \u003Cspan class=\"md-editor-code-lang\">sql\u003C\u002Fspan>\n              \u003Cspan class=\"md-editor-copy-button\" data-tips=\"复制代码\">复制代码\u003C\u002Fspan>\n              \n              \u003Cspan class=\"md-editor-collapse-tips\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-circle-chevron-left md-editor-icon\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m14 16-4-4 4-4\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n          \u003C\u002Fsummary>\n          \u003Cpre>\u003Ccode class=\"language-sql\" language=sql>\u003Cspan class=\"md-editor-code-block\">\u003Cspan class=\"hljs-comment\">-- 查询第1000页数据，每页10条，offset=9990\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table LIMIT \u003Cspan class=\"hljs-number\">9990\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>;\n\u003Cspan class=\"hljs-comment\">-- 问题：MySQL需扫描前9990条数据并跳过，仅返回最后10条，资源浪费严重\u003C\u002Fspan>\u003C\u002Fspan>\u003Cspan rn-wrapper aria-hidden=\"true\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n        \u003C\u002Fdetails>\n      \u003Ch3 data-line=\"17\" id=\"2. 解决方案（按适用场景排序）\">2. 解决方案（按适用场景排序）\u003C\u002Fh3>\n\u003Ch4 data-line=\"19\" id=\"方案1：基于主键\u002F索引排序+条件过滤（推荐，适用大部分场景）\">方案1：基于主键\u002F索引排序+条件过滤（推荐，适用大部分场景）\u003C\u002Fh4>\n\u003Cp data-line=\"21\">核心思路：利用主键或有序索引的连续性，通过\u003Ccode>WHERE\u003C\u002Fcode>条件直接定位到“上一页最后一条数据”，替代\u003Ccode>offset\u003C\u002Fcode>跳过数据。要求查询结果必须按主键或有序索引字段排序。\u003C\u002Fp>\n\u003Cp data-line=\"23\">实现步骤：\u003C\u002Fp>\n\u003Col data-line=\"25\">\n\u003Cli data-line=\"25\">\n\u003Cp data-line=\"25\">分页查询时，记录上一页最后一条数据的主键\u002F索引字段值（如最后一条数据的\u003Ccode>id=9990\u003C\u002Fcode>）；\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli data-line=\"27\">\n\u003Cp data-line=\"27\">下一页查询时，通过\u003Ccode>WHERE 主键 &gt; 上一页最后主键\u003C\u002Fcode>直接过滤前9990条数据，再用\u003Ccode>LIMIT size\u003C\u002Fcode>取数。\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp data-line=\"29\">示例（优化后查询）：\u003C\u002Fp>\n\n        \u003Cdetails  data-line=\"31\" class=\"md-editor-code\" open=\"\">\n          \u003Csummary class=\"md-editor-code-head\">\n            \u003Cdiv class=\"md-editor-code-flag\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv class=\"md-editor-code-action\">\n              \u003Cspan class=\"md-editor-code-lang\">sql\u003C\u002Fspan>\n              \u003Cspan class=\"md-editor-copy-button\" data-tips=\"复制代码\">复制代码\u003C\u002Fspan>\n              \n              \u003Cspan class=\"md-editor-collapse-tips\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-circle-chevron-left md-editor-icon\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m14 16-4-4 4-4\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n          \u003C\u002Fsummary>\n          \u003Cpre>\u003Ccode class=\"language-sql\" language=sql>\u003Cspan class=\"md-editor-code-block\">\u003Cspan class=\"hljs-comment\">-- 第1页查询（无offset，直接取前10条）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \u003Cspan class=\"hljs-keyword\">ORDER\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">BY\u003C\u002Fspan> id \u003Cspan class=\"hljs-keyword\">ASC\u003C\u002Fspan> LIMIT \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>;\n\u003Cspan class=\"hljs-comment\">-- 记录第1页最后一条数据的id=10\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">-- 第2页查询（通过id&gt;10过滤前10条，无需offset）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \u003Cspan class=\"hljs-keyword\">WHERE\u003C\u002Fspan> id \u003Cspan class=\"hljs-operator\">&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">ORDER\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">BY\u003C\u002Fspan> id \u003Cspan class=\"hljs-keyword\">ASC\u003C\u002Fspan> LIMIT \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>;\n\u003Cspan class=\"hljs-comment\">-- 记录第2页最后一条id=20\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">-- 第1000页查询（直接过滤前9990条，效率极高）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \u003Cspan class=\"hljs-keyword\">WHERE\u003C\u002Fspan> id \u003Cspan class=\"hljs-operator\">&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">9990\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">ORDER\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">BY\u003C\u002Fspan> id \u003Cspan class=\"hljs-keyword\">ASC\u003C\u002Fspan> LIMIT \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>;\u003C\u002Fspan>\u003Cspan rn-wrapper aria-hidden=\"true\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n        \u003C\u002Fdetails>\n      \u003Cp data-line=\"45\">优点：利用索引快速定位，无需扫描跳过的数据，查询效率稳定且高效；缺点：仅支持“下一页”查询，不支持直接跳转到任意页（如直接跳第1000页，需知道第999页最后一条的id）。\u003C\u002Fp>\n\u003Ch4 data-line=\"47\" id=\"方案2：游标分页（适合滚动加载场景）\">方案2：游标分页（适合滚动加载场景）\u003C\u002Fh4>\n\u003Cp data-line=\"49\">核心思路：MySQL的\u003Ccode>CURSOR\u003C\u002Fcode>（游标）本质是一个指向查询结果集的指针，可通过游标逐页读取数据，避免\u003Ccode>offset\u003C\u002Fcode>的低效扫描。适合“滚动加载更多”（如APP下拉加载）的场景，不支持跳页。\u003C\u002Fp>\n\u003Cp data-line=\"51\">实现步骤：\u003C\u002Fp>\n\n        \u003Cdetails  data-line=\"53\" class=\"md-editor-code\" open=\"\">\n          \u003Csummary class=\"md-editor-code-head\">\n            \u003Cdiv class=\"md-editor-code-flag\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv class=\"md-editor-code-action\">\n              \u003Cspan class=\"md-editor-code-lang\">sql\u003C\u002Fspan>\n              \u003Cspan class=\"md-editor-copy-button\" data-tips=\"复制代码\">复制代码\u003C\u002Fspan>\n              \n              \u003Cspan class=\"md-editor-collapse-tips\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-circle-chevron-left md-editor-icon\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m14 16-4-4 4-4\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n          \u003C\u002Fsummary>\n          \u003Cpre>\u003Ccode class=\"language-sql\" language=sql>\u003Cspan class=\"md-editor-code-block\">\u003Cspan class=\"hljs-comment\">-- 1. 声明游标（指定查询条件和排序方式）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">DECLARE\u003C\u002Fspan> cur_page \u003Cspan class=\"hljs-keyword\">CURSOR\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">FOR\u003C\u002Fspan> \n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \u003Cspan class=\"hljs-keyword\">ORDER\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">BY\u003C\u002Fspan> id \u003Cspan class=\"hljs-keyword\">ASC\u003C\u002Fspan>;\n\n\u003Cspan class=\"hljs-comment\">-- 2. 打开游标\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">OPEN\u003C\u002Fspan> cur_page;\n\n\u003Cspan class=\"hljs-comment\">-- 3. 读取数据（每次读取10条，即一页）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">FETCH\u003C\u002Fspan> cur_page \u003Cspan class=\"hljs-keyword\">INTO\u003C\u002Fspan> \u003Cspan class=\"hljs-variable\">@id\u003C\u002Fspan>, \u003Cspan class=\"hljs-variable\">@name\u003C\u002Fspan>; \u003Cspan class=\"hljs-comment\">-- 逐行读取，可循环读取10条作为一页\u003C\u002Fspan>\n\n\u003Cspan class=\"hljs-comment\">-- 4. 关闭游标\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">CLOSE\u003C\u002Fspan> cur_page;\u003C\u002Fspan>\u003Cspan rn-wrapper aria-hidden=\"true\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n        \u003C\u002Fdetails>\n      \u003Cp data-line=\"69\">优点：适合大量数据的滚动加载，效率稳定；缺点：不支持直接跳页，语法较复杂，需在存储过程中使用。\u003C\u002Fp>\n\u003Ch4 data-line=\"71\" id=\"方案3：预计算汇总表（适合静态\u002F低频更新数据）\">方案3：预计算汇总表（适合静态\u002F低频更新数据）\u003C\u002Fh4>\n\u003Cp data-line=\"73\">核心思路：如果数据是静态的（如历史订单、归档数据）或更新频率极低，可提前预计算分页所需的“分页标记”（如每10条数据的最大主键），存储在汇总表中。查询时直接从汇总表获取目标页的标记，再查询主表数据。\u003C\u002Fp>\n\u003Cp data-line=\"75\">实现示例：\u003C\u002Fp>\n\n        \u003Cdetails  data-line=\"77\" class=\"md-editor-code\" open=\"\">\n          \u003Csummary class=\"md-editor-code-head\">\n            \u003Cdiv class=\"md-editor-code-flag\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv class=\"md-editor-code-action\">\n              \u003Cspan class=\"md-editor-code-lang\">sql\u003C\u002Fspan>\n              \u003Cspan class=\"md-editor-copy-button\" data-tips=\"复制代码\">复制代码\u003C\u002Fspan>\n              \n              \u003Cspan class=\"md-editor-collapse-tips\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-circle-chevron-left md-editor-icon\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m14 16-4-4 4-4\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n          \u003C\u002Fsummary>\n          \u003Cpre>\u003Ccode class=\"language-sql\" language=sql>\u003Cspan class=\"md-editor-code-block\">\u003Cspan class=\"hljs-comment\">-- 1. 创建汇总表（存储每页最后一条数据的id和页码）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">CREATE\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">TABLE\u003C\u002Fspan> page_summary (\n    page_num \u003Cspan class=\"hljs-type\">INT\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">PRIMARY\u003C\u002Fspan> KEY, \u003Cspan class=\"hljs-comment\">-- 页码\u003C\u002Fspan>\n    last_id \u003Cspan class=\"hljs-type\">INT\u003C\u002Fspan> \u003Cspan class=\"hljs-comment\">-- 该页最后一条数据的id\u003C\u002Fspan>\n);\n\n\u003Cspan class=\"hljs-comment\">-- 2. 预插入数据（可通过定时任务更新）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">INSERT\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">INTO\u003C\u002Fspan> page_summary \u003Cspan class=\"hljs-keyword\">VALUES\u003C\u002Fspan> \n(\u003Cspan class=\"hljs-number\">1\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>), (\u003Cspan class=\"hljs-number\">2\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">20\u003C\u002Fspan>), ..., (\u003Cspan class=\"hljs-number\">1000\u003C\u002Fspan>, \u003Cspan class=\"hljs-number\">10000\u003C\u002Fspan>);\n\n\u003Cspan class=\"hljs-comment\">-- 3. 查询第1000页数据（先查汇总表，再查主表）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> last_id \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> page_summary \u003Cspan class=\"hljs-keyword\">WHERE\u003C\u002Fspan> page_num \u003Cspan class=\"hljs-operator\">=\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">999\u003C\u002Fspan>; \u003Cspan class=\"hljs-comment\">-- 得到第999页最后id=9990\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \u003Cspan class=\"hljs-keyword\">WHERE\u003C\u002Fspan> id \u003Cspan class=\"hljs-operator\">&gt;\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">9990\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">ORDER\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">BY\u003C\u002Fspan> id \u003Cspan class=\"hljs-keyword\">ASC\u003C\u002Fspan> LIMIT \u003Cspan class=\"hljs-number\">10\u003C\u002Fspan>;\u003C\u002Fspan>\u003Cspan rn-wrapper aria-hidden=\"true\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n        \u003C\u002Fdetails>\n      \u003Cp data-line=\"94\">优点：查询速度极快，适合大数据量静态数据；缺点：不适合动态更新数据，需维护汇总表（增加存储和维护成本）。\u003C\u002Fp>\n\u003Ch4 data-line=\"96\" id=\"方案4：限制分页深度（业务层面优化）\">方案4：限制分页深度（业务层面优化）\u003C\u002Fh4>\n\u003Cp data-line=\"98\">核心思路：从业务角度限制用户的分页深度，避免用户查询过深的页码。比如“最多支持查询前100页数据”，超过则提示“数据过多，请缩小查询范围”。\u003C\u002Fp>\n\u003Cp data-line=\"100\">实现示例：\u003C\u002Fp>\n\n        \u003Cdetails  data-line=\"102\" class=\"md-editor-code\" open=\"\">\n          \u003Csummary class=\"md-editor-code-head\">\n            \u003Cdiv class=\"md-editor-code-flag\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fdiv>\n            \u003Cdiv class=\"md-editor-code-action\">\n              \u003Cspan class=\"md-editor-code-lang\">sql\u003C\u002Fspan>\n              \u003Cspan class=\"md-editor-copy-button\" data-tips=\"复制代码\">复制代码\u003C\u002Fspan>\n              \n              \u003Cspan class=\"md-editor-collapse-tips\">\u003Csvg xmlns=\"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"lucide lucide-circle-chevron-left md-editor-icon\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003Cpath d=\"m14 16-4-4 4-4\"\u002F>\u003C\u002Fsvg>\u003C\u002Fspan>\n            \u003C\u002Fdiv>\n          \u003C\u002Fsummary>\n          \u003Cpre>\u003Ccode class=\"language-sql\" language=sql>\u003Cspan class=\"md-editor-code-block\">\u003Cspan class=\"hljs-comment\">-- 限制offset最大值为9990（即最多100页）\u003C\u002Fspan>\n\u003Cspan class=\"hljs-keyword\">SELECT\u003C\u002Fspan> id, name \u003Cspan class=\"hljs-keyword\">FROM\u003C\u002Fspan> test_table \n\u003Cspan class=\"hljs-keyword\">WHERE\u003C\u002Fspan> \u003Cspan class=\"hljs-keyword\">offset\u003C\u002Fspan> \u003Cspan class=\"hljs-operator\">&lt;=\u003C\u002Fspan> \u003Cspan class=\"hljs-number\">9990\u003C\u002Fspan> \nLIMIT #{\u003Cspan class=\"hljs-keyword\">offset\u003C\u002Fspan>}, #{size};\u003C\u002Fspan>\u003Cspan rn-wrapper aria-hidden=\"true\">\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003Cspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fcode>\u003C\u002Fpre>\n\n        \u003C\u002Fdetails>\n      \u003Cp data-line=\"110\">优点：简单易实现，从根源减少深度分页查询；缺点：有业务局限性，不适用于必须支持深分页的场景（如后台数据导出）。\u003C\u002Fp>\n\u003Ch3 data-line=\"112\" id=\"3. 方案选择总结\">3. 方案选择总结\u003C\u002Fh3>\n\u003Ctable data-line=\"114\">\n\u003Cthead data-line=\"114\">\n\u003Ctr data-line=\"114\">\n\u003Cth>方案\u003C\u002Fth>\n\u003Cth>适用场景\u003C\u002Fth>\n\u003Cth>核心优势\u003C\u002Fth>\n\u003Cth>局限性\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody data-line=\"116\">\n\u003Ctr data-line=\"116\">\n\u003Ctd>主键\u002F索引条件过滤\u003C\u002Ftd>\n\u003Ctd>大部分动态数据分页（如列表查询）\u003C\u002Ftd>\n\u003Ctd>效率高、实现简单、兼容性好\u003C\u002Ftd>\n\u003Ctd>不支持直接跳页\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr data-line=\"117\">\n\u003Ctd>游标分页\u003C\u002Ftd>\n\u003Ctd>APP滚动加载、大量数据逐页读取\u003C\u002Ftd>\n\u003Ctd>效率稳定、适合大数据量\u003C\u002Ftd>\n\u003Ctd>不支持跳页、语法复杂\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr data-line=\"118\">\n\u003Ctd>预计算汇总表\u003C\u002Ftd>\n\u003Ctd>静态\u002F低频更新数据（如归档、报表）\u003C\u002Ftd>\n\u003Ctd>查询速度极快\u003C\u002Ftd>\n\u003Ctd>需维护汇总表、不支持动态数据\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr data-line=\"119\">\n\u003Ctd>限制分页深度\u003C\u002Ftd>\n\u003Ctd>业务允许限制分页范围（如前台列表）\u003C\u002Ftd>\n\u003Ctd>实现简单、无性能开销\u003C\u002Ftd>\n\u003Ctd>业务局限性大\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr data-line=\"120\">\n\u003Ctd>补充提示：深度分页优化的核心是“避免扫描跳过无关数据”，无论哪种方案，都需确保查询条件中的排序字段有索引（如主键默认有索引），否则仍会出现全表扫描，优化失效。\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003Ctd>\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\n\u003C\u002Ftable>\n",2845,9,"0","",2,0,213,"数据,查询,--,id,offset","在MySQL开发中，除了计数场景，深度分页（即LIMIT offset, size中offset值极大的分页查询）也是高频遇到的性能问题。比如“查询第1000页数据，每页10条”（LIMIT 9990, 10），常会出现查询缓慢的情况。下面详细讲解深度分页的问题根源及解决方案。\n1.","2026-01-08 09:27:51"]