mysql范围查询如何优化_mysql查询性能提升方法

来源:这里教程网 时间:2026-02-28 20:46:39 作者:

为什么
WHERE col BETWEEN a AND b
有时比
WHERE col >= a AND col  慢?

二者语义等价,但 MySQL 优化器对

BETWEEN
的常量推导更保守,尤其当涉及函数或隐式类型转换时。例如
created_at BETWEEN '2024-01-01' AND NOW()
NOW()
是非确定性函数,可能导致索引失效;而显式写成
created_at >= '2024-01-01' AND created_at  反而更容易被提前物化。

优先用
>=
 替代 <code>BETWEEN
,尤其右侧边界含函数、子查询或变量
确保两端值类型一致:比如
id BETWEEN '1' AND '100'
会触发字符串比较,若
id
INT
,应写成
id BETWEEN 1 AND 100
避免在字段上套函数:
DATE(created_at) BETWEEN ...
必然无法走索引,改用
created_at >= '2024-01-01' AND created_at 

复合索引中范围条件必须放最后吗?

是的,且这是最容易踩的坑。MySQL 的 B+ 树索引只能高效支持「最左前缀 + 等值匹配 + 最多一个范围匹配」的组合。一旦出现范围(

>
、<code>BETWEEN
LIKE 'abc%'
),其右侧所有字段都无法用于索引查找。

对于查询
WHERE status = 1 AND created_at > '2024-01-01' AND user_id = 123
,索引
(status, created_at, user_id)
只能用到前两个字段,
user_id
不参与索引查找
如果业务中
user_id
过滤性更强,应调整为
(status, user_id, created_at)
,把范围字段放在最后
IN
列表不算严格意义上的“范围”,但 MySQL 8.0+ 对
IN
后多个常量会做等值展开,仍可继续使用后续字段 —— 但别依赖这个行为,
IN
超过几百项时性能会断崖下跌

如何判断范围查询是否真的走了索引?

光看

EXPLAIN
type
range
不够,得结合
key_len
rows
和实际执行时间验证。常见假象是:索引存在、
type
显示
range
,但
key_len
远小于预期,说明只用了索引前缀。

执行
EXPLAIN FORMAT=TREE
(MySQL 8.0+)看索引扫描路径,比传统
EXPLAIN
更直观
检查
key_len
:比如索引是
(a INT, b VARCHAR(50))
,若
a
NULL
,单列
INT
占 5 字节(4+1),
b
若为 utf8mb4 字符集且定义长度 50,则最多占 200 字节(50×4),加起来 205;若实际
key_len=5
,说明
b
完全没用上
SELECT * FROM t WHERE ... INTO DUMPFILE '/tmp/test'
配合慢日志中的
Rows_examined
对比,确认是否真按索引行数扫描

时间范围查询分页深翻怎么不崩?

LIMIT offset, size
做深分页时,即使有索引,MySQL 仍要扫描
offset + size
行才能跳过前面的数据 —— offset 越大越慢。时间范围本身不能解决这个问题,但可以换思路。

放弃
OFFSET
,改用游标分页:记录上一页最后一条的
created_at
id
,下一页查
WHERE created_at >= ? AND id > ? ORDER BY created_at, id LIMIT 20
如果必须用时间范围分页,先用覆盖索引查出 ID 列表(如
SELECT id FROM t WHERE time BETWEEN ... ORDER BY time LIMIT 20000, 20
),再用
IN
回表,比直接
LIMIT 20000,20
快得多
对实时性要求不高的场景,考虑预生成时间分区表(如按天/月分表),查某天数据时直接路由到对应表,避免大范围扫描

索引设计不是一锤子买卖,范围条件的位置、数据分布倾斜度、查询并发模式都会影响最终效果。上线前务必用生产级数据量压测,而不是只看

EXPLAIN
的理想路径。

相关推荐