0.MySQL基本架構(gòu)
MySQL有客戶端,也有服務(wù)端,服務(wù)端主要分為Server層和存儲引擎層,Server層包括五個部分,分別為連接器、查詢緩存、分析器、優(yōu)化器和執(zhí)行器?;炯軜?gòu)圖如下:

1.查詢緩存作用
-
查詢過程
當執(zhí)行SQL查詢時,MySQL會先到查詢緩存中查看之前執(zhí)行過該SQL語句,在查詢緩存中之前執(zhí)行過的語句及其結(jié)果會以key-value形式存放,key對應(yīng)于查詢語句,value對應(yīng)于查詢結(jié)果。如果在查詢緩存中存在該key,則直接返回value,不需要執(zhí)行后面操作;如果不存在該key,則進行分析器、優(yōu)化器、執(zhí)行器以及調(diào)用存儲引擎操作,最后將對應(yīng)結(jié)果以key-value形式寫入查詢緩存,返回value。
-
存在弊端
雖然命中查詢緩存的語句效率非常高,但是查詢緩存的失效非常頻繁,只要有對一個表的更新,這個表所有的查詢緩存就回被清空。對于更新壓力大的數(shù)據(jù)庫來說,查詢緩存的命中率會非常低。除非你的業(yè)務(wù)就是有一張靜態(tài)表,很長時間才會更新一次。比如,一個系統(tǒng)配置表,那這張表上的查詢才適合使用查詢緩存。
-
解決方案
好在 MySQL 也提供了這種“按需使用”的方式。你可以將參數(shù) query_cache_type (ini配置文件)設(shè)置成 DEMAND,這樣對于默認的 SQL 語句都不使用查詢緩存。
而對于你確定要使用查詢緩存的語句,可以用 SQL_CACHE 顯式指定,像下面這個語句一樣:
mysql> select SQL_CACHE * from table_name where ID=10;需要注意的是,MySQL 8.0 版本直接將查詢緩存的整塊功能刪掉了,也就是說 8.0 開始徹底沒有這個功能了。
同時以上查詢緩存語句對于數(shù)據(jù)庫系統(tǒng)表(information_schema/mysql/performance_schema/sys)無效
2.查詢緩存模式
-
查詢緩存模式
mysql>SHOW VARIABLES LIKE 'query_cache_type'; Variable_name Value ---------------- -------- query_cache_type OFFMySQL5.5默認開啟(ON)
MySQL5.7默認關(guān)閉(OFF)
MySQL8.0不存在該變量
-
my.ini文件設(shè)置查詢緩存模式
# 查詢緩存模式: # 0 : OFF 關(guān)閉 # 1 : ON 緩存所有結(jié)果,除非select語句使用SQL_NO_CACHE禁用查詢緩存 # 2 : DEMAND 只緩存select語句中通過SQL_CACHE指定需要緩存的查詢 query_cache_type=2 查詢是否命中
mysql>SHOW STATUS LIKE '%Qcache%';
Variable_name Value
----------------------- ----------
Qcache_free_blocks 1
Qcache_free_memory 15709672
Qcache_hits 2 # 表示有多少次命中緩存
Qcache_inserts 1 # 表示多少次未命中緩存然后插入,意思是新來的SQL請求如果在緩存中未找到,不得不執(zhí)行查詢處理,執(zhí)行查詢處理后把結(jié)果insert到查詢緩存中。
Qcache_lowmem_prunes 0
Qcache_not_cached 11 # 表示因為query_cache_type的設(shè)置而沒有被緩存的查詢數(shù)量。
Qcache_queries_in_cache 1 # 當前緩存中緩存的查詢數(shù)量。
Qcache_total_blocks 4 # 當前緩存的block數(shù)量。
3.驗證查詢緩存
以下試驗以MySQL5.5版本為基礎(chǔ)
3.1查詢緩存模式為ON
-
查看數(shù)據(jù)庫版本
mysql>SELECT VERSION(); version() ----------- 5.5.40 -
查看默認查詢緩存模式
mysql>SHOW VARIABLES LIKE 'query_cache_type'; Variable_name Value ---------------- -------- query_cache_type ON -
查詢命中情況
mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15711208 Qcache_hits 0 Qcache_inserts 0 Qcache_lowmem_prunes 0 Qcache_not_cached 2 Qcache_queries_in_cache 0 Qcache_total_blocks 1 -
執(zhí)行三次計數(shù)查詢語句以及兩次查詢命中情況
① mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 1 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 0 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 3 Qcache_queries_in_cache 1 Qcache_total_blocks 4 ② mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 1 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 1 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 4 Qcache_queries_in_cache 1 Qcache_total_blocks 4 ③ mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 1 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 2 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 5 Qcache_queries_in_cache 1 Qcache_total_blocks 4分析:第一次查詢Qcache_inserts的值1,表示1次未命中緩存然后插入,意思是新來的SQL請求如果在緩存中未找到,不得不執(zhí)行查詢處理,執(zhí)行查詢處理后把結(jié)果insert到查詢緩存中。
最后一次查詢Qcache_hits為2,表示有2次命中緩存
-
更新當前表
mysql>INSERT INTO shop.`shop_user`(PASSWORD,telephone,username)VALUE('123456', '15552424710','Tod'); 1 queries executed, 1 success, 0 errors, 0 warnings mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15711208 Qcache_hits 2 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 5 Qcache_queries_in_cache 0 Qcache_total_blocks 1 -
執(zhí)行兩次次基數(shù)查詢并查詢命中情況
① mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 2 Qcache_inserts 2 Qcache_lowmem_prunes 0 Qcache_not_cached 6 Qcache_queries_in_cache 1 Qcache_total_blocks 4 ② mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 3 Qcache_inserts 2 Qcache_lowmem_prunes 0 Qcache_not_cached 7 Qcache_queries_in_cache 1 Qcache_total_blocks 4分析:如果存在對該表插入,其查詢緩存立即失效
-
更新其他表數(shù)據(jù)
mysql>INSERT INTO shop.`shop_product`(pname,pprice,stock) VALUE('魅族',4000.0,5000); 1 queries executed, 1 success, 0 errors, 0 warnings mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 3 Qcache_inserts 3 Qcache_lowmem_prunes 0 Qcache_not_cached 7 Qcache_queries_in_cache 1 Qcache_total_blocks 4 -
執(zhí)行一次基數(shù)查詢并查詢命中情況
mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 4 Qcache_inserts 3 Qcache_lowmem_prunes 0 Qcache_not_cached 8 Qcache_queries_in_cache 1 Qcache_total_blocks 4分析:其他表的更新對于原查詢不會有影響
結(jié)論
- 查詢緩存的失效只針對當前表的更新操作
- 如果當前表涉及更新操作,再此查詢會執(zhí)行緩存插入操作
3.2查詢緩存模式為DEMAND
-
在my.ini文件中添加
# 查詢緩存模式: # 0 : OFF 關(guān)閉 # 1 : ON 緩存所有結(jié)果,除非select語句使用SQL_NO_CACHE禁用查詢緩存 # 2 : DEMAND 只緩存select語句中通過SQL_CACHE指定需要緩存的查詢 query_cache_type=2 -
重啟數(shù)據(jù)庫服務(wù)
cmd>net restart mysql -
查看查詢緩存模式
mysql>SHOW VARIABLES LIKE 'query_cache_type'; Variable_name Value ---------------- -------- query_cache_type DEMAND -
查看命中情況
mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15711208 Qcache_hits 0 Qcache_inserts 0 Qcache_lowmem_prunes 0 Qcache_not_cached 0 Qcache_queries_in_cache 0 Qcache_total_blocks 1 -
執(zhí)行兩次計數(shù)查詢語句以及兩次查詢命中情況
① mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15711208 Qcache_hits 0 Qcache_inserts 0 Qcache_lowmem_prunes 0 Qcache_not_cached 2 Qcache_queries_in_cache 0 Qcache_total_blocks 1 ② mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15711208 Qcache_hits 0 Qcache_inserts 0 Qcache_lowmem_prunes 0 Qcache_not_cached 4 Qcache_queries_in_cache 0 Qcache_total_blocks 1 -
執(zhí)行兩次顯示指定執(zhí)行查詢緩存模式,執(zhí)行一次普通計數(shù)查詢
① mysql>SELECT SQL_CACHE COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 0 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 5 Qcache_queries_in_cache 1 Qcache_total_blocks 4 ② mysql>SELECT SQL_CACHE COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 1 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 6 Qcache_queries_in_cache 1 Qcache_total_blocks 4 ③ mysql>SELECT COUNT(*) FROM shop.`shop_user`; count(*) ---------- 2 mysql>SHOW GLOBAL STATUS LIKE '%Qcache%'; Variable_name Value ----------------------- ---------- Qcache_free_blocks 1 Qcache_free_memory 15709672 Qcache_hits 1 Qcache_inserts 1 Qcache_lowmem_prunes 0 Qcache_not_cached 8 Qcache_queries_in_cache 1 Qcache_total_blocks 4分析:如果沒有顯式使用
SQL_CACHE,即使是同一查詢語句也不走查詢緩存模式
結(jié)論
- 顯式使用
SQL_CACHE能夠有效控制查詢語句是否走查詢緩存模式,能夠人為實現(xiàn)控制。 - 不走查詢緩存模式能夠減少一次寫緩存操作。
MySQL 8.0 版本直接將查詢緩存的整塊功能刪掉了,也就是說 8.0 開始徹底沒有這個功能了。