You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何MySQL查询同时使用OR条件与c_desc字段时会挂起?

问题分析与解决:MySQL OR条件结合longtext字段导致查询挂起

核心原因

从EXPLAIN结果能明确看到,查询3没有使用你创建的licenses复合索引,反而选择了idx_timestamp单字段索引——这是优化器的索引选择失误,直接引发了性能灾难:

  • 当使用idx_timestamp时,MySQL会按c_timestamp降序遍历索引条目,但每找到一条记录,都需要回表读取c_desc(longtext类型,IO开销极大),再校验c_license_sign是否匹配目标值。
  • 你的表有150万+数据,可能前大量按时间排序的记录都不符合license001或license002的条件,导致MySQL持续遍历索引、回表校验,看起来就像“永久挂起”。
  • 而查询4去掉c_desc后,idx_timestamp是覆盖索引,无需回表就能完成校验,所以快速返回;查询1、2单独用单个license值时,优化器能正确选择licenses复合索引,直接定位到对应license的最新记录,自然正常。

解决方法

1. 强制指定使用licenses复合索引

通过FORCE INDEX引导优化器走正确的索引,避免错误选择:

SELECT c_desc, c_timestamp 
FROM t_usage FORCE INDEX(licenses)
WHERE c_license_sign='license001' OR c_license_sign='license002' 
ORDER BY c_timestamp DESC limit 1;

2. 用UNION ALL替代OR

OR条件容易干扰优化器判断,拆成两个独立查询再合并,优化器会分别使用licenses索引,效率大幅提升:

(SELECT c_desc, c_timestamp FROM t_usage WHERE c_license_sign='license001' ORDER BY c_timestamp DESC limit 1)
UNION ALL
(SELECT c_desc, c_timestamp FROM t_usage WHERE c_license_sign='license002' ORDER BY c_timestamp DESC limit 1)
ORDER BY c_timestamp DESC limit 1;

3. 创建覆盖索引

如果这类查询属于高频场景,直接建一个包含所有查询字段的覆盖索引,彻底消除回表开销:

CREATE INDEX idx_license_timestamp_desc ON t_usage(c_license_sign, c_timestamp DESC, c_desc);

这个索引包含了查询需要的所有字段,MySQL可直接从索引中获取数据,无需回表,无论用OR还是其他条件,性能都会达到最优。

额外建议

你的表没有主键,InnoDB会自动生成隐藏的6字节主键,这会增加回表开销与存储空间。建议添加自增主键(如id INT AUTO_INCREMENT PRIMARY KEY),对整体性能有明显帮助。

内容的提问来源于stack exchange,提问作者elfan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 09:03:47