
查詢的執行路徑
- SQL語句
- 查詢緩存
- 解析器
- 解析樹
- 預處理
- 查找最好的查詢路徑
- 查詢優化SQL語句
- 執行計划
- API調用存儲引擎
- 調用數據,返回結果
緩存SELECT操作或預處理查詢的結果集和SQL語句,當有新的SELECT語句或預處理查詢語句請求,先去查詢緩存,判斷是否存在可用的記錄集,判斷標准:與緩存的SQL語句,是否完全一樣,區分大小寫。
不需要對SQL語句做任何解析和執行,當然語法解析必須通過在先,直接從Query Cache中獲得查詢結果,提高查詢性能
查詢緩存的判斷規則,不夠智能,也即提高了查詢緩存的使用門檻,降低其效率;查詢緩存的使用,會增加檢查和清理Query Cache中記錄集的開銷
查詢緩存
查詢緩存,及將查詢結果的緩存下載;如果查詢語句完全相同,則直接返回緩存中的結果;
我們可以使用如下語句,查看當前服務是否開啟了查詢緩存功能:
MariaDB [(none)]> SHOW VARIABLES LIKE '%query_cache%'; +------------------------------+----------+ | Variable_name | Value | +------------------------------+----------+ | have_query_cache | YES | | query_cache_limit | 1048576 | | query_cache_min_res_unit | 4096 | | query_cache_size | 33554432 | | query_cache_strip_comments | OFF | | query_cache_type | ON | | query_cache_wlock_invalidate | OFF | +------------------------------+----------+ 7 rows in set (0.10 sec)
可以看到,query_cache_type的值為ON,也就是目前已經開啟了查詢緩存功能;
query_cache_type的值可以設置為:ON、OFF、DEMAND,分別為已啟動、已禁用和按需緩存,在文件my.cnf中設置即可;
vim /etc/my.cnf [mysqld]中添加: query_cache_type = ON
have_query_cache表示當前數據庫是否支持緩存功能;值為YES
query_cache_limit表示單條查詢緩存的最大值,如果查詢結果超過此大小,即使指定緩存當前結果,結果也不會被緩存;默認為1M
query_cache_min_res_unit表示緩存存儲於內存的最小單元,默認為4K,如果查詢結果小於4K,也會占用4k內存,所以設置過大會存內存空間的浪費,設置過小,則會頻繁分配內存待遇按或頻發的回收
query_cache_size表示查詢緩存的總大小
query_cache_wlock_invalidate表示所查詢的表如果被寫鎖鎖定,是否使用緩存返回結構
只有查詢語句完全相同時,緩存才能夠被命中;查詢SQL語句相同,大小寫不同即算不同;
MariaDB [(none)]> select * from stu; MariaDB [(none)]> SELECT * FROM stu;
MySQL在收到查詢請求時,會對查詢語句進行hash計算,計算出對應的hash,通過這個hash值查找是否存在對應的緩存,所以,即使查詢語句的大小寫不同,也會被認為是不同的查詢語句;當前hash碼沒有命中對應的緩存,mysql則會將對應的hash值放在對應的hash表中,同時將查詢結果存放在對應的緩存中,如果查詢語句的hash值命中了對應緩存項,則之間從緩存中返回響應結果,如果緩存對應的表中的數據發生了變化,那么查詢緩存中,所有與變化的數據表有關的緩存都將失效;
那么,我們該如何靈活使用緩存呢;可用如下方法;
在開啟緩存時(query_cache_type=ON),指定對應的查詢語句不使用緩存
MariaDB [(none)]> select sql_no_cache name from stu;
也可在按需使用緩存時(query_cache_type=DEMAND),,之地==指定對應的查詢語句使用緩存
MariaDB [(none)]> select sql_cache name from stu;
查看緩存使用情況
MariaDB [(none)]> SHOW status LIKE 'qcache%'; +-------------------------+----------+ | Variable_name | Value | +-------------------------+----------+ | Qcache_free_blocks | 1 | | Qcache_free_memory | 33536824 | | Qcache_hits | 0 | | Qcache_inserts | 0 | | Qcache_lowmem_prunes | 0 | | Qcache_not_cached | 27 | | Qcache_queries_in_cache | 0 | | Qcache_total_blocks | 1 | +-------------------------+----------+ 8 rows in set (0.33 sec)
其中各個參數的意義如下:
Qcache_free_blocks:緩存中相鄰內存塊的個數。數目大說明可能有碎片。FLUSH QUERY CACHE會對緩存中的碎片進行整理,從而得到一個空閑塊。
Qcache_free_memory:緩存中的空閑內存。
Qcache_hits:每次查詢在緩存中命中時就增大
Qcache_inserts:每次插入一個查詢時就增大。命中次數除以插入次數就是不中比率。
Qcache_lowmem_prunes:緩存出現內存不足並且必須要進行清理以便為更多查詢提供空間的次數。這個數字最好長時間來看;如果這個 數字在不斷增長,就表示可能碎片非常嚴重,或者內存很少。(上面的 free_blocks和free_memory可以告訴您屬於哪種情況)
Qcache_not_cached:不適合進行緩存的查詢的數量,通常是由於這些查詢不是 SELECT 語句或者用了now()之類的函數。
Qcache_queries_in_cache:當前緩存的查詢(和響應)的數量。
Qcache_total_blocks:緩存中塊的數量。
通過上述統計信息的數值,以及緩存設置相關值,計算出查詢緩存的相關指標,從而判斷查詢緩存是否對我們有一定幫助;一切以實際生產為准
查詢緩存的碎片率 = ( Qcache_free_blocks / Qcache_total_blocks ) * 100%
查詢緩存利用率 = ( query_cache_size - Qcache_free_memory ) / query_cache_size * 100%
由上述兩個公式可以推斷出;如果Qcache_free_memory緩存中塊的數量越大,則碎片率越高,可以嘗試適當調小query_cache_min_res_unit值,或及時清理緩存碎片。
清理緩存碎片:
MariaDB [(none)]> FLUSH QUERY CACHE
如果想要清除查詢緩存中已經存在的緩存,可用使用
從查詢緩存中移除所有查詢結果的緩存
MariaDB [(none)]> RESET QUERY CACHE;
如果查詢緩存利用率太低,則表示query_cache_size設置過大,可適當調小,如果緩存利用率非常
高,同時Qcache_lowmem_prunes的值較大,則表示query_cache_size設置略小。
如果在調整query_cache_min_res_unit值時不確定調整為多大;可以參考如下公式
( query_cache_size - Qcache_free_memory ) / Qcache_queries_in_cache
查詢緩存命中率 = ( Qcache_hits / Com_select ) * 100%
其中Com_select表示查詢語句的執行次數(此描述並不准確;應是Qcache_hits + Qcache_inserts),可用如下語句獲得查詢語句執行次數
show status like "Com_select%";
優化查詢緩存


