




索引未生效时缓存会放大性能问题,因缓存固化了全表扫描结果;需通过EXPLAIN验证索引使用,合理配置innodb_buffer_pool_size,优先用覆盖索引减少磁盘访问,禁用已废弃的Query Cache。
MySQL 查询走不上索引,SELECT 却被应用层或代理(如 Redis、ProxySQL)缓存了结果,会导致「缓存永远返回旧的慢查询结果」。典型表现是:数据明明已更新,但接口响应时间依然高,且 EXPLAIN 显示 type=ALL 或 key=NULL。
实操建议:
EXPLAIN,尤其关注 key、rows、Extra 字段;rows 接近表总行数基本等于没走索引user:profile:{user_id} 比 user:all_profiles 更安全WHERE 字段做缓存,等同于把全表扫描结果固化——别这么做InnoDB 缓冲池(innodb_buffer_pool_size)本质就是 MySQL 的「主内存缓存」,它负责缓存数据页和索引页。如果设得太小,索引节点频繁换入换出;设得太大,又会挤压 OS 文件缓存和应用层缓存(如 PHP-FPM 内存、Redis 内存),反而引发 swap 或 OOM。
实操建议:
SHOW ENGINE INNODB STATUS 查看 Buffer pool hit rate,持续低于 99% 就该调大maxmemory + maxmemory_policy=volatile-lru,防止其无节制膨胀innodb_buffer_pool_instances 建议按 CPU 核数设置(如 8 核设为 8),减少内部锁争用当索引包含查询所需全部字段(即覆盖索引),MySQL 可直接从 B+ 树叶子节点返回结果,连主键回表都省了。此时若再在应用层加一层缓存,属于冗余存储+额外序列化开销。
实操建议:
EXPLAIN 确认 Extra 字段含 Using index,而非 Using where; Using index(后者仍需回表)SELECT *;否则即使有索引,也可能因新增列导致覆盖失效region、status_code),可建联合覆盖索引:CREATE INDEX idx_status_name ON status (code, name);
MySQL 5.7 默认关闭、8.0 直接移除了 query_cache_type 和相关参数。它的机制是「SQL 文本完全匹配 + 表无变更才复用」,在高并发更新场景下失效频繁,且锁粒度粗(全局锁),反而成瓶颈。
实操建议:
SELECT @@have_query_cache; 返回 NO,或 SHOW VARIABLES LIKE 'query_cache%'; 全为空
DEL 或 SET 对应 key,不能只依赖过期时间