为何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
相关产品推荐
相关产品推荐

