Query Cache (QC) 將 完整 SELECT 語句文本 (大小寫敏感、空格敏感) 作為 Key,結果集 作為 Value 緩存。命中時直接返回結果,**跳過解析、優化、執行、存儲引擎交互** 全鏈路。
適用場景: 讀多寫少、數據變更頻率低、重複查询比例高 (如配置表、字典表、報表查詢)。
不適用場景: 高頻寫入表、大結果集、非確定性函數 (NOW(), RAND())、分區表、InnoDB 事務隔離級別影響。
| 參數 | 默認值 | 建議值 | 說明 |
|---|---|---|---|
| query_cache_type | OFF (0) | 1 (ON) / 2 (DEMAND) | 0=禁用,1=緩存所有 SELECT (除 SQL_NO_CACHE),2=僅緩存 SQL_CACHE 指定查詢 |
| query_cache_size | 0 | 64M-256M (視內存) | 緩存總內存,0 即禁用。不可動態調大,需重啟 |
| query_cache_limit | 1M | 1M-4M | 單個結果集最大緩存體積,超過不緩存 |
| query_cache_min_res_unit | 4K | 1K-2K | 緩存分配最小塊,過大碎片化,過小管理開銷大 |
| query_cache_wlock_invalidate | OFF | ON | 寫鎖時是否失效緩存,防止髒讀 |
[mysqld]
query_cache_type = 1
query_cache_size = 268435456 # 256MB
query_cache_limit = 1048576 # 1MB
query_cache_min_res_unit = 2048 # 2KB
query_cache_wlock_invalidate = 1
生效: 修改後 systemctl restart mysqld。query_cache_size 從 0 變非 0 或反向必須重啟;同類型間動態調整需 FLUSH QUERY CACHE 整理碎片。
-- 強制不緩存 (query_cache_type=1 時)
SELECT SQL_NO_CACHE * FROM huge_table WHERE ...;
-- 強制緩存 (query_cache_type=2 時)
SELECT SQL_CACHE * FROM config_table WHERE ...;
SHOW STATUS LIKE 'Qcache%';
SHOW STATUS LIKE 'Com_select';
| 變量 | 含義 | 健康判斷 |
|---|---|---|
| Qcache_hits | 命中次數 | 核心指標,持續增長 |
| Qcache_inserts | 新增緩存次數 | 與 Hits 比例反映重複查詢率 |
| Qcache_not_cached | 未緩存查詢數 | 不可緩存類型 (函數/大結果/自定義) |
| Qcache_lowmem_prunes | 內存不足淘汰次數 | 持續增長 = 緩存太小或碎片嚴重 |
| Qcache_free_memory | 剩餘可用內存 | 趨近 0 需擴容或整理 |
| Qcache_free_blocks | 空閒塊數 | 過多 = 碎片化嚴重 |
| Qcache_total_blocks | 總塊數 | 配合 free_blocks 計算碎片率 |
| Com_select | 總 SELECT 執行次數 | 分母 |
命中率 = Qcache_hits / (Qcache_hits + Qcache_inserts + Qcache_not_cached) * 100%
-- 或簡化:Qcache_hits / Com_select * 100% (含不可緩存查詢)
經驗值: 命中率 > 80% 為優秀,50-80% 良好,< 50% 需優化或關閉。
-- 即時整理碎片 (不清空緩存)
FLUSH QUERY CACHE;
-- 完全重置 (清空所有緩存)
RESET QUERY CACHE;
-- 或
FLUSH TABLES; -- 會隱式 RESET QUERY CACHE
定時任務建議: 每天低峰期執行 FLUSH QUERY CACHE,防止碎片積累導致分配失敗。
診斷: query_cache_size=64M 過小,頻繁淘汰。
方案: 擴容至 256M,調整 query_cache_min_res_unit=2K 減少碎片,啟用 query_cache_wlock_invalidate=1 保證一致性。
根因: MySQL 5.7+ Query Cache 全局互斥鎖 (LOCK_query_cache) 成為熱點,高併發下嚴重退化性能。
方案: 關閉 Query Cache (query_cache_type=0, query_cache_size=0),改用應用層緩存。
| 版本 | 狀態 | 建議 |
|---|---|---|
| MySQL 5.6/5.7 | 默認關閉,可用 | 僅低併發、高重複查詢場景謹慎啟用 |
| MySQL 8.0 | 完全移除 | 不可用,必須遷移至應用層緩存 (Redis/Memcached) 或 ProxySQL Query Cache |
| MariaDB 10.2+ | 保留但默認關閉 | 同 5.7 策略 |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| 應用層 Redis/Memcached | 分布式、高性能、數據結構豐富、TTL 靈活 | 代碼侵入、緩存一致性需自管 | 通用、高併發、微服務 |
| ProxySQL Query Cache | 透明代理、無代碼改動、多後端聚合、規則動態 | 引入中間件、單點風險 (需集群) | legacy 應用快速接入、讀寫分離整合 |
| MySQL 8.0 CTE/衍生表物化 | 優化器原生、無額外組件 | 僅優化單查詢、不跨會話共享 | 復雜報表查詢優化 |
| 物化視圖 / 總結表 | 查詢極快、數據預聚合 | 維護成本高、實時性弱 | 固定維度報表、大屏展示 |
query_cache_limitNOW(), RAND(), UUID(), CONNECTION_ID() 導致不緩存Query Cache 是「雙刃劍」:低併發、高重複、低寫入場景下能帶來數量級性能提升;高併發寫入下全局鎖成為系統瓶頸。MySQL 8.0 果斷移除,倒逼架構向應用層緩存 (Redis)、中間件緩存 (ProxySQL)、計算下推 (ClickHouse/StarRocks) 進化。存量 5.6/5.7 系統:監控命中率與 Lowmem Prunes,命中率 > 80% 且無鎖爭用可保留;否則立即關閉,規劃遷移路徑。緩存的本質是「用空間換時間、用最終一致性換高可用」,層級越高 (應用 > 中間件 > 數據庫),控制力越強、擴展性越好。