mysql索引优化和缓存有什么关系_mysql性能协作分析

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

索引没建对,缓存再快也白搭

缓存(比如 Redis)只能加速「已经能快速查出来的数据」,如果 SQL 本身走全表扫描、

EXPLAIN
显示
type=ALL
rows
动辄几十万,那哪怕把结果缓存 1 小时,下一次未命中缓存的请求照样拖垮数据库。真实线上案例里,70% 的“缓存无效”问题,根子都在索引没覆盖查询条件或顺序错——比如
WHERE status = ? AND created_at > ? ORDER BY id
,却只给
status
单独建了索引,
created_at
id
完全没进索引,MySQL 只能先扫出所有
status
匹配的行,再内存排序,缓存根本救不了这个 IO+CPU 双爆的场景。

哪些查询值得加缓存?先看索引是否“覆盖”

真正适合缓存的查询,往往满足两个硬条件:高频、稳定、且已由**覆盖索引**支撑。所谓覆盖索引,就是

SELECT
的所有字段 +
WHERE
/
ORDER BY
用到的字段,全部包含在同一个索引里,让 MySQL 连主表数据页都不用读。例如:

SELECT user_id, order_no, amount FROM orders WHERE shop_id = ? AND status = ? ORDER BY created_at DESC;

对应建复合索引:

ALTER TABLE orders ADD INDEX idx_shop_status_time (shop_id, status, created_at DESC, user_id, order_no, amount);

这样查询走索引就能拿到全部结果,
Extra
字段显示
Using index
,IO 极低,才值得扔进 Redis 缓存
如果索引里漏了
amount
,MySQL 就得回表查聚簇索引,延迟波动大,缓存命中的收益被抵消
缓存 key 设计也要对齐索引字段,比如
orders:shop_123:status_1
,避免缓存粒度太粗(全量缓存)或太碎(单行缓存)

缓存失效和索引更新不是一回事

很多人误以为“我改了数据,缓存自动失效”,其实完全无关——InnoDB 更新数据时会维护 B+ 树索引,但不会通知 Redis。必须由应用层主动清理或设 TTL。更危险的是:如果索引设计导致查询结果逻辑变更(比如新增一个

WHERE is_deleted = 0
条件但没加到索引里),旧缓存可能长期返回错误数据,而 DB 层毫无感知。

写操作后,优先清缓存,而不是等 TTL;尤其涉及金额、状态类字段 避免用「更新即删缓存」的简单策略——如果并发写同一记录,可能因时序问题导致缓存击穿,建议用延迟双删或订阅 binlog 索引重建(
OPTIMIZE TABLE
ALTER TABLE ... ENGINE=InnoDB
)不触发缓存失效,但可能改变查询执行计划,需同步验证缓存 key 是否仍有效

别拿缓存当索引缺陷的遮羞布

见过太多团队在慢查询报警后第一反应是“加个 Redis”,结果缓存掩盖了真实瓶颈:比如一个分页查询

OFFSET 10000 LIMIT 20
,索引虽存在,但深度遍历导致延迟飙升,缓存只能缓解第一页,后面翻页照样超时。这种场景该做的是改用游标分页(
WHERE id > ? ORDER BY id LIMIT 20
)+ 覆盖索引,而不是堆缓存。

缓存适合解决「读多写少 + 查询模式固定」的问题;索引优化解决「任意条件组合下都能快速定位」的问题 监控时要分开看:Redis 的
get_hits / get_misses
比率高 ≠ 数据库健康;MySQL 的
Handler_read_next
持续飙升,说明索引没发挥应有作用
最易被忽略的一点:
JOIN
多表时,每张表的驱动顺序和关联字段索引质量,直接影响最终是否能走覆盖索引——这一步没调好,缓存连入口都摸不到

相关推荐