上一篇
2025年8月最新动态:MySQL 9.0社区预览版发布后,查询优化器对范围查询的索引使用策略进行了微调,但">="操作符在某些场景下仍可能出现索引失效问题,这已成为开发者社区近期热议话题。
上周排查一个生产环境慢查询时,我遇到了一个特别诡异的情况:
-- 这个查询用了0.8秒(表数据量200万) SELECT * FROM orders WHERE create_time >= '2025-07-01';
但当我稍微调整查询条件:
-- 这个查询只用了0.02秒! SELECT * FROM orders WHERE create_time > '2025-06-30 23:59:59';
两个查询逻辑上是等价的,但性能差距达到40倍!更离谱的是,create_time
字段明明有BTREE索引啊!
MySQL索引就像书本目录,B+树结构让它可以快速定位数据,对于范围查询:
>
、<
操作符:优化器可以明确使用索引定位边界值>=
、<=
操作符:情况开始变得复杂...MySQL内部有个"成本计算器",它会估算:
当使用>=
时:
假设你的create_time
字段数据分布如下:
2025-01-01:10条
2025-07-01:150万条
2025-08-01:50万条
当查询>= '2025-07-01'
时,MySQL发现要扫描75%的数据,自然放弃索引。
-- 原始问题查询 SELECT * FROM orders WHERE create_time >= '2025-07-01'; -- 优化方案1:转为> + 精确时间 SELECT * FROM orders WHERE create_time > '2025-06-30 23:59:59'; -- 优化方案2:使用BETWEEN SELECT * FROM orders WHERE create_time BETWEEN '2025-07-01' AND '2025-12-31';
SELECT * FROM orders FORCE INDEX(create_time_idx) WHERE create_time >= '2025-07-01';
注意:这可能导致更差性能,需先EXPLAIN验证
复合索引有时能解决问题:
ALTER TABLE orders ADD INDEX (status, create_time);
然后查询:
SELECT * FROM orders WHERE status = 'active' AND create_time >= '2025-07-01';
-- 需要开启优化器开关 SET optimizer_switch = 'skip_scan=on';
EXPLAIN SELECT * FROM orders WHERE create_time >= '2025-07-01';
关键看:
type
列:range表示用了范围索引,ALL表示全表扫描key
列:显示实际使用的索引SET optimizer_trace="enabled=on"; SELECT * FROM orders WHERE create_time >= '2025-07-01'; SELECT * FROM information_schema.optimizer_trace;
WHERE col >= NULL
会导致索引失效WHERE DATE(create_time) >= '2025-07-01'
绝对不走索引ANALYZE TABLE
更新统计信息handler_read_key
和handler_read_next
状态变量最后提醒:每个MySQL版本对范围查询的优化策略都有调整,本文基于2025年8月的MySQL 9.0预览版测试结果,生产环境请务必自行验证。
思考题:如果你发现WHERE price >= 100
走了索引,但WHERE price >= 99.99
却没走索引,可能是什么原因?(提示:考虑数据类型和精度问题)
本文由 扈代巧 于2025-08-05发表在【云服务器提供商】,文中图片由(扈代巧)上传,本平台仅提供信息存储服务;作者观点、意见不代表本站立场,如有侵权,请联系我们删除;若有图片侵权,请您准备原始证明材料和公证书后联系我方删除!
本文链接:https://vps.7tqx.com/wenda/543466.html
发表评论