职位列表翻到第 10000 页接口超时:深分页优化,从 3 秒到 30ms

发布时间:2026/9/29 4:54:51
职位列表翻到第 10000 页接口超时:深分页优化,从 3 秒到 30ms 导读招聘平台职位列表页用户翻到第几百页后接口开始变慢第 10000 页直接超时。慢查询日志里躺着一条LIMIT 200000, 20的 SQL执行要 3 秒多。这个案例很典型深分页的优化套路也就那么几个今天用一次真实排查把它讲透。职位列表翻到第 10000 页接口超时深分页优化从 3 秒到 30ms先说业务。求职招聘系统的职位搜索页支持按城市、职位类型、薪资范围筛选分页大小 20。用户猛翻页翻到后面比如第 10000 页即 offset200000的时候接口响应从几十毫秒涨到 3 秒再往后直接超时。慢 SQL 长什么样最开始的 SQL 是这么写的SELECTid,title,salary_min,salary_max,city_code,company_name,updated_atFROMjob_positionWHEREcity_code330100ANDstatus1ORDERBYupdated_atDESCLIMIT200000,20;字段看着不复杂city_code和status也有索引。用EXPLAIN看一眼EXPLAINSELECTid,title,salary_min,salary_max,city_code,company_name,updated_atFROMjob_positionWHEREcity_code330100ANDstatus1ORDERBYupdated_atDESCLIMIT200000,20;结果里typerefkeyidx_city_status乍一看索引用上了。但注意Extra列Using index condition; Using filesortUsing filesort出来了。排序字段updated_at不在联合索引里MySQL 只能把 20 万行先捞出来在内存里排完序再丢掉前 20 万行。这就是慢的根源。为什么 offset 越大越慢很多人以为 LIMIT 优化是只取 20 条其实 MySQL 是先扫描 offsetlimit 行再丢弃前 offset 行。offset200000 时即使每条都命中索引也要读 200020 行。更要命的是 SELECT 里查了company_name、salary_max这些不在索引里的字段每行都要回表查一次聚簇索引200020 次回表不慢才怪。优化一延迟关联最通用核心思路先在索引里把 id 定位出来再回表拿完整数据回表次数从 20 万降到 20 次。SELECTp.id,p.title,p.salary_min,p.salary_max,p.city_code,p.company_name,p.updated_atFROMjob_position pINNERJOIN(SELECTidFROMjob_positionWHEREcity_code330100ANDstatus1ORDERBYupdated_atDESCLIMIT200000,20)tONp.idt.idORDERBYp.updated_atDESC;子查询里只查id走覆盖索引如果建了(city_code, status, updated_at)联合索引连 filesort 都省了直接按索引顺序扫。这样子查询扫 20 万行但不回表快了不是一点半点。压测结果同一页数据从 3.2s 降到 31ms100 倍。配合的索引 DDLALTERTABLEjob_positionADDINDEXidx_city_status_time(city_code,status,updated_at);ORDER BY updated_at DESC能直接走这个索引的顺序Using filesort消失Extra变成干净的Using index condition。优化二游标分页翻到底的方案延迟关联能救 10000 页但 offset 到 100 万行的时候子查询本身也要扫 100 万行还是会慢。更彻底的方案是不用 offset改游标记住上一页最后一条的updated_at下一页只查比它小的。SELECTid,title,salary_min,salary_max,city_code,company_name,updated_atFROMjob_positionWHEREcity_code330100ANDstatus1ANDupdated_at2026-09-27 18:30:00-- 上一页最后一条的时间ORDERBYupdated_atDESCLIMIT20;这个方案每页都是 O(索引命中行数)不管翻多深都稳定。代价是不能用页码跳转只能上一页下一页且updated_at要有唯一性保证同秒多条会漏数据一般拼上id做二级条件。AND(updated_at?OR(updated_at?ANDid?))我在项目里是浅页数用延迟关联超过 100 页提示用户用搜索/筛选缩小范围没有做无限翻页的游标——招聘场景用户不会真翻到 1 万页但接口不能因此超时。踩坑记录加了索引反而更慢说个翻车经历。我先给表加了(city_code, status, updated_at)联合索引以为万事大吉结果 EXPLAIN 一看优化器还是走了老索引idx_city_statusfilesort 还在。排查过程SHOW INDEX FROM job_position确认索引建上了再 EXPLAIN发现key还是旧的。查了 MySQL 版本和统计信息ANALYZE TABLE job_position更新统计信息后优化器才切到新索引。这个坑的教训加了索引不代表优化器会用MySQL 的优化器基于统计信息做选择表数据量变化后要ANALYZE TABLE刷新统计信息实在不听话可以用FORCE INDEX (idx_city_status_time)先顶上但根因要查清楚。可直接复用的要点慢查询日志开着long_query_time1定期扫一眼。深分页三板斧联合索引覆盖排序字段 → 延迟关联减少回表 → 游标分页根治翻页。EXPLAIN看Extra出现Using filesort就是排序没走索引。加了索引不生效先ANALYZE TABLE刷新统计信息。业务层限制最大翻页深度超深提示用户加筛选条件比无限优化 SQL 更实在。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询