初探查詢緩存

0.MySQL基本架構(gòu)

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

MySQL基本架構(gòu).png

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  OFF   
    

    MySQL5.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 開始徹底沒有這個功能了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容