美文网首页
初探查询缓存

初探查询缓存

作者: Tod_2021 | 来源:发表于2022-07-28 23:03 被阅读0次

    0.MySQL基本架构

    MySQL有客户端,也有服务端,服务端主要分为Server层和存储引擎层,Server层包括五个部分,分别为连接器、查询缓存、分析器、优化器和执行器。基本架构图如下:

    MySQL基本架构.png

    1.查询缓存作用

    • 查询过程

      当执行SQL查询时,MySQL会先到查询缓存中查看之前执行过该SQL语句,在查询缓存中之前执行过的语句及其结果会以key-value形式存放,key对应于查询语句value对应于查询结果。如果在查询缓存中存在该key,则直接返回value,不需要执行后面操作;如果不存在该key,则进行分析器、优化器、执行器以及调用存储引擎操作,最后将对应结果以key-value形式写入查询缓存,返回value。

    • 存在弊端

      虽然命中查询缓存的语句效率非常高,但是查询缓存的失效非常频繁,只要有对一个表的更新,这个表所有的查询缓存就回被清空对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存

    • 解决方案

      好在 MySQL 也提供了这种“按需使用”的方式。你可以将参数 query_cache_type (ini配置文件)设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存

      对于你确定要使用查询缓存的语句,可以用 SQL_CACHE 显式指定,像下面这个语句一样:

      mysql> select SQL_CACHE * from table_name where ID=10;
      

      需要注意的是,MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

      同时以上查询缓存语句对于数据库系统表(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默认关闭(OFF)

      MySQL8.0不存在该变量

    • my.ini文件设置查询缓存模式

      # 查询缓存模式:
      # 0 : OFF 关闭 
      # 1 : ON 缓存所有结果,除非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请求如果在缓存中未找到,不得不执行查询处理,执行查询处理后把结果insert到查询缓存中。 
    Qcache_lowmem_prunes     0         
    Qcache_not_cached        11         # 表示因为query_cache_type的设置而没有被缓存的查询数量。 
    Qcache_queries_in_cache  1          # 当前缓存中缓存的查询数量。 
    Qcache_total_blocks      4        # 当前缓存的block数量。
    

    3.验证查询缓存

    以下试验以MySQL5.5版本为基础

    3.1查询缓存模式为ON

    • 查看数据库版本

      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        
      
    • 执行三次计数查询语句以及两次查询命中情况

      ①
      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请求如果在缓存中未找到,不得不执行查询处理,执行查询处理后把结果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       
      
    • 执行两次次基数查询并查询命中情况

      ①
      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         
      

      分析:如果存在对该表插入,其查询缓存立即失效

    • 更新其他表数据

      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   
      
    • 执行一次基数查询并查询命中情况

      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   
      

      分析:其他表的更新对于原查询不会有影响

    结论

    • 查询缓存的失效只针对当前表的更新操作
    • 如果当前表涉及更新操作,再此查询会执行缓存插入操作

    3.2查询缓存模式为DEMAND

    • 在my.ini文件中添加

      # 查询缓存模式:
      # 0 : OFF 关闭 
      # 1 : ON 缓存所有结果,除非select语句使用SQL_NO_CACHE禁用查询缓存 
      # 2 : DEMAND 只缓存select语句中通过SQL_CACHE指定需要缓存的查询
      query_cache_type=2
      
    • 重启数据库服务

      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    
      
    • 执行两次计数查询语句以及两次查询命中情况

      ①
      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         
      
    • 执行两次显示指定执行查询缓存模式,执行一次普通计数查询

      ①
      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,即使是同一查询语句也不走查询缓存模式

    结论

    • 显式使用SQL_CACHE能够有效控制查询语句是否走查询缓存模式,能够人为实现控制。
    • 不走查询缓存模式能够减少一次写缓存操作。

    MySQL 8.0 版本直接将查询缓存的整块功能删掉了,也就是说 8.0 开始彻底没有这个功能了。

    相关文章

      网友评论

          本文标题:初探查询缓存

          本文链接:https://www.haomeiwen.com/subject/dpnxwrtx.html