mysql索引和缓存如何配合_mysql性能提升策略

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

索引没生效时,缓存反而放大性能问题

MySQL 查询走不上索引,

SELECT
却被应用层或代理(如 Redis、ProxySQL)缓存了结果,会导致「缓存永远返回旧的慢查询结果」。典型表现是:数据明明已更新,但接口响应时间依然高,且
EXPLAIN
显示
type=ALL
key=NULL

实操建议:

上线前必查
EXPLAIN
,尤其关注
key
rows
Extra
字段;
rows
接近表总行数基本等于没走索引
缓存 key 设计要包含能触发索引的条件字段,例如缓存
user:profile:{user_id}
user:all_profiles
更安全
对未加索引的
WHERE
字段做缓存,等同于把全表扫描结果固化——别这么做

innodb_buffer_pool_size 设置不当,索引和缓存都在抢内存

InnoDB 缓冲池(

innodb_buffer_pool_size
)本质就是 MySQL 的「主内存缓存」,它负责缓存数据页和索引页。如果设得太小,索引节点频繁换入换出;设得太大,又会挤压 OS 文件缓存和应用层缓存(如 PHP-FPM 内存、Redis 内存),反而引发 swap 或 OOM。

实操建议:

生产环境建议设为物理内存的 50%–75%,但上限不超过 80%;可通过
SHOW ENGINE INNODB STATUS
查看
Buffer pool hit rate
,持续低于 99% 就该调大
避免与 Redis 共用同一台机器且都吃满内存;若必须共存,给 Redis 配
maxmemory
+
maxmemory_policy=volatile-lru
,防止其无节制膨胀
innodb_buffer_pool_instances
建议按 CPU 核数设置(如 8 核设为 8),减少内部锁争用

覆盖索引 + SELECT 字段精简,让查询不碰磁盘也不进应用层缓存

当索引包含查询所需全部字段(即覆盖索引),MySQL 可直接从 B+ 树叶子节点返回结果,连主键回表都省了。此时若再在应用层加一层缓存,属于冗余存储+额外序列化开销。

实操建议:

EXPLAIN
确认
Extra
字段含
Using index
,而非
Using where; Using index
(后者仍需回表)
写 SQL 时显式列出字段,别用
SELECT *
;否则即使有索引,也可能因新增列导致覆盖失效
对高频、低更新的维度表(如
region
status_code
),可建联合覆盖索引:
CREATE INDEX idx_status_name ON status (code, name);

Query Cache 已被弃用,别再依赖它协调索引与缓存

MySQL 5.7 默认关闭、8.0 直接移除了

query_cache_type
和相关参数。它的机制是「SQL 文本完全匹配 + 表无变更才复用」,在高并发更新场景下失效频繁,且锁粒度粗(全局锁),反而成瓶颈。

实操建议:

确认
SELECT @@have_query_cache;
返回
NO
,或
SHOW VARIABLES LIKE 'query_cache%';
全为空值——别白费力气调参
替代方案:用客户端缓存(HTTP Cache-Control)、代理层缓存(Varnish)、或业务层缓存(Redis + 主键/条件组合 key) 注意:这些外部缓存无法感知 MySQL 索引变化,所以更新操作后必须主动
DEL
SET
对应 key,不能只依赖过期时间
索引和缓存不是叠加使用就一定快,关键在数据访问路径是否真正收敛到内存层级。最容易被忽略的是:你以为缓存保护了慢查询,其实只是把问题延迟暴露了。

相关推荐