当前位置: 首页 > news >正文

MySQL Limit数量不满足时导致查询变慢

问题背景

mysql 查询语句中,common_id ,effective_date ,status 分别是单独的索引,id为主键

select id, serial_no from account where 1=1
and id > 3706705 and effective_date >= '2016-01-01' and effective_date <= '2019-05-16'
and common_id in ( '1006' ) and status in ( 1 , 2 )
order by id asc limit 600 ;

这条sql执行时间是2分钟多,实际的查询结果只有33条

这条sql是分页查询的最后一条查询语句,前面查询都很快。

select id, serial_no from account where 1=1
and id > 3706705
and common_id in ( '1006' ) and status in ( 1 , 2 )
order by id asc limit 600 ;

这条sql执行时间是秒级别。

执行计划

字段
typerange
possible_keysPRIMARY, index common_id, idx effectdate, idx status
keyPRIMARY
rows12,754,809
filtered0.58
ExtraUsing where

🧠 关键分析点

key = PRIMARY ➜ 只用了 id 索引

虽然你写了多个条件(common_id, status, effective_date),但 MySQL 最终选择只使用了 PRIMARY KEY (id) 索引。

这说明:

MySQL 试图通过 id > 3706705 开始顺序扫描表的主键,但其余过滤条件(common_id, status, effective_date)都变成了 “额外过滤”,不能用索引加速。


rows = 12754809 ➜ 扫描了约 1275 万行!

这是致命性能瓶颈。

  • 这表示 MySQL 扫描了整个主键范围中1275 万行来寻找满足 effective_date 和其他条件的数据。
  • 实际只返回了 33 条
  • 效率极低,扫描和返回比为 386,511:1

因为最后一次查询没有满足limit 600,所以一直查询直到最后没有满足600条的数据才返回,大坑!!!

filtered = 0.58 ➜ 只有 0.58% 的行满足条件

这个值也说明:

  • MySQL 预估大部分行都不会满足 where 条件;
  • 但又因为索引选择不佳,无法提前排除这些行,只能暴力遍历。

📌 为什么不用其他索引(如 common_ididx_effectdate)?

因为用了以下复杂组合:

  • id > 3706705
  • common_id IN (...)
  • status IN (...)
  • effective_date BETWEEN ...
  • 再加 ORDER BY id

MySQL 必须选择一个 单一索引路径。如果这些字段不是同一个联合索引的一部分,它无法优化所有条件。

而:

  • idx_effectdate 无法帮助排序(ORDER BY id);
  • idx_common_ididx_status 也是单列索引,不能联合使用;
  • 最终 MySQL 只能选择 PRIMARY 来满足 id > ... ORDER BY id,牺牲过滤效率。

✅ 解决方案建议

✅ 方案一:加复合索引(强烈推荐)

ALTER TABLE account 
ADD INDEX idx_csid_effective_id (common_id, status, effective_date, id);

这个索引可以覆盖所有过滤条件 + 排序,MySQL 就能:

  • 快速定位满足条件的数据;
  • id 顺序返回;
  • 避免扫描千万行。

⚠️ 顺序不能乱:common_id, status, effective_date, id 是根据你查询的筛选 + 排序优先级排列的。


✅ 方案二:尝试使用 FORCE INDEX

如果你无法修改表结构,可以尝试如下变通方法:

SELECT id, serial_no 
FROM account FORCE INDEX(idx_effectdate) 
WHERE id > 3706705AND effective_date >= '2016-01-01'AND effective_date <= '2019-05-16'AND common_id IN ('1006')AND status IN (1, 2)
ORDER BY id ASC 
LIMIT 600;

但效果可能有限,因为 ORDER BY ididx_effectdate 无关联,MySQL 仍可能需要做 filesort,所以只是尝试,不如建复合索引效果好。


✅ 方案三:按时间切片分批查(业务层分页)

如果无法加索引,你可以写一段逻辑:

  1. common_id, status 等过滤后的记录;
  2. 进一步按 effective_date 做范围过滤;
  3. 或者在业务侧分页时跳过没有数据的时间段(你已知哪些段是“稀疏”的);

✅ 总结

问题项原因
查询很慢查询用了 PRIMARY KEY 单一索引,只能遍历大量无效数据行
索引没用上没有合适的联合索引满足所有筛选条件和排序要求
行数多结果少MySQL 扫描了 1275 万行,只返回 33 条,效率极低
优化建议建联合索引:(common_id, status, effective_date, id)

你说得完全对,LIMIT 600 导致 MySQL 必须扫描海量数据才能“找够”符合条件的记录,但由于数据分布稀疏、索引不理想,最终只能找到 33 条,且必须扫描上千万行才能确认没有更多了。


经过分析,是因为limit 600的原因导致一直在扫描数据,直到全部扫描完成发现只有33条满足条件的数据,才返回。

http://www.lryc.cn/news/575924.html

相关文章:

  • 深圳中青宝互动网络股份有限公司游戏运维工程师面试题(笔
  • 使用OpenCV进行3D重建:详细指南
  • OpenCV图像添加水印
  • word中如何保存高清图片,并保存为高质量的pdf文件(图像不失真)
  • 51c~嵌入式~PLC~西门子~合集1
  • GO 语言学习 之 语句块
  • 汉中农业服务——激活田野的希望,共绘乡村振兴图
  • Guava Cache 本地项目缓存
  • 昇腾910(NPU)安装paddlepaddle【自用版】
  • LinuxBridge的作用与发展历程:从基础桥接到云原生网络基石
  • 【Linux指南】压缩、网络传输与系统工具
  • 用 pnpm + TurboRepo,构建多项目高效开发体系
  • 人工智能-基础篇-4-人工智能AI、机器学习ML和深度学习DL之间的关系
  • 几种基于Doherty结构的GAN氮化镓功放设计方法介绍
  • Ehcache、Caffeine、Spring Cache、Redis、J2Cache、Memcached 和 Guava Cache 的主要区别
  • 算法-堆排序
  • 飞算科技依托 JavaAI 核心技术,打造企业级智能开发全场景方案
  • AIOps与人工智能的融合:从智能运维到自适应IT生态的革命
  • 【网络】Linux 内核优化实战 - net.ipv4.tcp_rmem 和 net.core.rmem_default 关系
  • MySQL(1)——count()聚合函数
  • V-by-One V1.4协议介绍
  • QT基础知识3——文件操作:QFile类
  • windows11 源码本地部署大模型anythingllm
  • web布局26
  • sqlite如何存储日期
  • 【数据交易】全国数据交易所的发展现状
  • 开源 java android app 开发(十三)绘图定义控件、摇杆控件的制作
  • OpenLayers 拖动旋转和缩放
  • Python打卡训练营-Day44-预训练模型
  • 生成式人工智能实战 | WGAN(Wasserstein Generative Adversarial Network, GAN)