MySQL为何未使用oc_sd_filter表已创建的索引?如何解决?
解决oc_sd_filter表未使用已创建索引的问题
常见原因排查
1. 索引列被函数/运算修饰
如果查询的WHERE子句中,索引列被函数(如DATE()、LOWER())或算术运算包裹,数据库无法直接利用索引进行查找,必然导致索引失效。比如:
-- 错误用法,索引失效 WHERE DATE(sd.create_time) = '2024-05-20' -- 正确用法,直接使用列匹配 WHERE sd.create_time BETWEEN '2024-05-20 00:00:00' AND '2024-05-20 23:59:59'
2. 索引选择性过低
如果索引列的重复值过多(比如状态列只有0/1两种值,且90%都是0),数据库优化器会判断全表扫描比走索引更高效。可以通过以下语句计算索引选择性:
SELECT COUNT(DISTINCT 你的索引列)/COUNT(*) AS selectivity FROM oc_sd_filter;
如果结果小于0.1(即重复率90%以上),建议更换索引列或创建组合索引。
3. 表统计信息过时
数据库依赖表的统计信息来判断执行计划,如果统计信息很久没更新,优化器可能做出错误判断。执行以下语句更新统计信息:
ANALYZE TABLE oc_sd_filter;
4. 隐式类型转换
当查询条件中传入的参数类型与索引列类型不匹配时,会触发隐式转换,导致索引失效。比如索引列是INT类型,但查询用字符串匹配:
-- 错误用法,隐式转换导致索引失效 WHERE sd.id = '1001' -- 正确用法,类型匹配 WHERE sd.id = 1001
5. 索引未覆盖所需字段
如果查询需要返回的字段不在索引中,数据库走索引后还要回表查询数据,当数据量较大时,优化器可能选择直接全表扫描。这种情况可以创建覆盖索引,将所需查询字段包含到索引中。
解决办法
- 修正
WHERE子句写法:确保索引列未被函数或运算修饰,参数类型与列类型一致。 - 更新统计信息:执行
ANALYZE TABLE oc_sd_filter;让优化器获取最新数据分布。 - 调整索引策略:对于选择性低的索引,更换索引列或创建组合索引;如果需要回表,创建覆盖索引。
- 强制测试索引:如果以上步骤无效,可以尝试强制使用索引验证是否可行:
SELECT sd.* FROM oc_sd_filter sd FORCE INDEX(你的索引名) WHERE ...;
如果强制后索引生效,说明优化器成本计算存在偏差,可以调整数据库优化器参数(如optimizer_switch),但这属于进阶操作,需谨慎调整。
内容的提问来源于stack exchange,提问作者bobi
相关产品推荐
相关产品推荐

