首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL Query Cache 深度解析:原理、配置、監控與避坑指南

     編輯:MySQL 資料庫相關知識

Query Cache(QC)工作原理

Query Cache 是 MySQL 基於 SQL 文本精確匹配 的結果集緩存機制。僅針對 SELECT 語句生效,其他(SHOW, USE 等)不緩存。

關鍵特性:極度字面匹配

  • SQL 文本作為 Key,**不做任何正規化處理**
  • 大小寫不同、多一個空格、註釋差異 → 完全不同的 Cache 入口
  • 客戶端可能預處理:官方命令行客戶端會移除註釋、首尾空白;PHP mysqlnd 驅動則不處理註釋
-- 這三條語句在 QC 中佔用三個獨立槽位
select * FROM people where name='surfchen';
select * FROM people where /*hey~*/name='surfchen';
SELECT * FROM people where name='surfchen';

失效機制:表級粒度,更新即全清

任一涉及表發生 UPDATE/DELETE/INSERT/TRUNCATE/ALTER 等寫操作,**該表相關的所有 QC 條目全部失效**。頻繁寫入的表開啟 QC 反而會增加開銷(內存分配/釋放、鎖競爭、失效掃描)。

內存存儲結構:塊管理

  • 查詢結果**分塊存儲**,非一次性分配
  • 單塊大小由 query_cache_min_res_unit 控制(默認 4KB)
  • 最後一塊未用完的內存會釋放回池
  • 每個緩存條目佔用:1 個 SQL 文本塊 + N 個結果塊 + 1 個表信息塊(多線程共享)
  • 總塊數 ≈ 查詢數 × 2 + 涉及表數

核心配置參數

參數說明建議
query_cache_type0=關閉, 1=開啟(可用 SQL_NO_CACHE 禁用), 2=按需(需 SQL_CACHE 啟用)生產環境建議 2,精確控制
query_cache_sizeQC 總內存,0 即禁用。需 ≥40KB 結構開銷,單位 1024 字節對齊視命中率調整,典型 64M-256M
query_cache_limit單個查詢結果超過此值不緩存1M-4M,防止大結果集佔滿池
query_cache_min_res_unit每次分配塊大小見下文調優策略

狀態變量監控與調優

SHOW STATUS LIKE 'Qcache%';
變量含義異常信號
Qcache_hits命中次數過低說明 QC 無效
Qcache_inserts新增緩存次數—
Qcache_lowmem_prunes因內存不足被剔除的條目數快速增長 → 增加 query_cache_size
Qcache_free_memory剩餘可用內存過小 → 擴容
Qcache_free_blocks空閒塊數(碎片指標)過大 → 碎片嚴重,執行 FLUSH QUERY CACHE
Qcache_total_blocks總塊數配合 Qcache_queries_in_cache 看平均塊數
Qcache_queries_in_cache當前緩存查詢數—
Qcache_not_cached未緩存的只讀查詢數含不可緩存類型、SQL_NO_CACHE、超大結果等

調優決策樹

  1. Qcache_lowmem_prunes 快速增長 → 增加 query_cache_size
  2. Qcache_total_blocks / Qcache_queries_in_cache ≫ 2 → 平均每查詢佔用塊過多,增大 query_cache_min_res_unit(如 16K-32K)減少分配次數
  3. Qcache_queries_in_cache × query_cache_min_res_unit 遠大於 實際已用內存 → 塊過大造成浪費,嘗試減小 query_cache_min_res_unit
  4. Qcache_free_blocks 過大 → 執行 FLUSH QUERY CACHE 整理碎片(不清空條目)

實戰避坑指南

❌ 不適合 QC 的場景

  • 高頻寫入表(用戶表、日志表、統計計數表)
  • 高基數、低重複查詢(如 SELECT pwd FROM user WHERE name='xxx',每用戶 SQL 文本不同)
  • 包含不確定函數:NOW(), RAND(), UUID(), CONNECTION_ID() 等
  • 查詢系統表、臨時表、用戶變量

✅ 最佳實踐模式

-- 默認關閉 QC,關鍵只讀業務顯式啟用
SET SESSION query_cache_type = 2;

-- 熱點配置查詢、字典表查詢、報表聚合查詢
SELECT SQL_CACHE * FROM config WHERE type='payment';
SELECT SQL_CACHE id, name FROM dict_category WHERE parent_id=0;

-- 寫操作、高頻變更、個性化查詢顯式禁用
SELECT SQL_NO_CACHE * FROM user_log WHERE uid=123 ORDER BY time DESC LIMIT 20;

MySQL 8.0 重要變更:Query Cache 已移除

MySQL 8.0 完全移除了 Query Cache。官方理由:

  • 全局鎖瓶頸嚴重,多核擴展性極差
  • 失效掃描開銷大,寫入密集型負載性能倒退
  • 應用層緩存更靈活、可控、可擴展

替代方案:應用層引入 Redis/Memcached,按業務語義緩存對象/列表/聚合結果,配合 TTL、主動失效、標籤組失效等策略,遠優於 SQL 文本級的被動緩存。

總結

Query Cache 曾是 MySQL 5.x 時代簡單場景下的「免費加速器」,但其**粗粒度失效、字面匹配、全局鎖**三大硬傷決定了它無法適應高併發寫入場景。現代架構應將緩存策略前置至應用層,MySQL 專注於存儲與索引優化。若維護 5.7 及以下舊系統,請嚴格遵循「默認關、按需開、監控調、定期清」原則。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved