0.MySQL基本架构
MySQL有客户端,也有服务端,服务端主要分为Server层和存储引擎层,Server层包括五个部分,分别为连接器、查询缓存、分析器、优化器和执行器。基本架构图如下:
MySQL基本架构.png1.查询缓存作用
-
查询过程
当执行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 开始彻底没有这个功能了。
网友评论