如何查看并开启查询缓存
查看是否开启查询缓存:
mysql> 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 | 16777216 |
| query_cache_type | OFF |
| query_cache_wlock_invalidate | OFF |
+------------------------------+----------+
6 rows in set (0.00 sec)
query_cache_type
:是否开启查询缓存,0 表示不开启查询缓存,1 表示始终开启查询缓存 (不要缓 存使用 sql_no_cache), 2 表示按需开启查询缓存 (需要缓存使 用 sql_cache)
query_cache_size
:给缓存分配的最大内存空间
FLUSH QUERY CACHE
: 清理查询缓存内存碎片 (不会清理查询缓存)
RESET QUERY CACHE
: 从查询缓存中移出所有查询
FLUSH TABLES
: 关闭所有打开的表,同时该操作将会清空查询缓存中的内容
开启查询缓存:需要修改配置文件,linux my.cnf
[root@localhost www]# find / -name my.cnf
/etc/my.cnf
[root@localhost www]# vim /etc/my.cnf
添加query_cache_type=1
[root@localhost www]# systemctl restart mysqld
查询结果:
SELECT * from purchase_order WHERE order_sn like "ry2bhxtAu4%"
> OK
> 时间: 2.674s
SELECT * from purchase_order WHERE order_sn like "ry2bhxtAu4%"
> OK
> 时间: 0.002s
以上是查看和开启查询缓存的demo,下面记录一下查询缓存的概念、优缺点及应用注意点:
了解什么是查询缓存,需要先了解MySQL的执行流程,这里文字描述
1.客户端向MySQL服务器发送一条查询请求
2.服务器先查询查询缓存,如果命中缓存,则立刻返回存储在缓存中的结果,否则进入下一阶段
3.服务器进行SQL解析,预处理、再由优化器生成对应的执行计划
4.MySQL根据执行计划,调用存储引擎的API来执行查询
5.将结果返回给客户端,同时缓存查询结果
可以了解到 查询缓存
相当于一个hash结构,哈希值索引,这个哈希值通过查询本身、当前要查询的 数据库、客户端协议版本号等一些可能影响结果的信息计算得来。所以两个查询在任何字符上的不同 (例如 : 空格、注释),都会导致缓存不会命中。
简单理解为:开启查询缓存后,在满足缓存条件下,可以快速返回结果集。比如demo中从2s到0.01s的查询返回。
那么具备命中缓存的条件是什么呢,哪些不会缓存呢?
-
查询中包含任何用户自定义函数、存储函数、用户变量、临时表、MySQL库中的系统表,其查询结果 都不会被缓存。比如函数 NOW() 或者 CURRENT_DATE() 会因为不同的查询时间,返回不同的查询结果,再 比如包含 CURRENT_USER 或者 CONNECION_ID() 的查询语句会因为不同的用户而返回不同的结果,将这样 的查询结果缓存起来没有任何的意义
-
MySQL 查询缓存系统会跟踪查询中涉及的每个表,如果这些表 (数据或结构) 发生变化,那么和这张表相关 的所有缓存数据都将失效。正因为如此,在任何的写操作时,MySQL必须将对应表的所有缓存都设置为失 效。如果查询缓存非常大或者碎片很多,这个操作就可能带来很大的系统消耗,甚至导致系统僵死一会儿
查询缓存对系统的额外消耗不仅仅在写,读也会有消耗:
- 任何的查询语句在开始之前都必须经过检查,即使这条 SQL语句 永远不会命中缓存
- 如果查询结果可以被缓存,那么执行完成后,会将结果存入缓存,也会带来额外的系统消耗
基于此,并不是什么情况下查询缓存都会提高系统性能,缓存和失效
都会带来额外消耗,特别是写密集型应用,只有当缓存带来的资源节约大于其本身消耗的资源时,才会给系统带来性能提升。可以尝试打开查 询缓存,并在数据库设计上做一些优化 :
- 用多个小表代替一个大表,注意不要过度设计
- 批量插入代替循环单条插入
- 合理控制缓存空间大小,一般来说其大小设置为几十兆比较合适
- 可以通过 SQL_CACHE 和 SQL_NO_CACHE 来控制某个查询语句是否需要进行缓存
注 : SQL_NO_CACHE 是禁止缓存查询结果,是从设置后开始的,如果之前有缓存的话,满足命中条件还是可以作为缓存结果返回的。
补充:
mysql服务端分层:
连接层:主要是线程管理,对程序连接的管理
sql层:解析sql,优化sql
存储引擎层:innodb,myisam存储引擎
连接层:1.连接后的用户密码的校验。2.校验后的连接进行线程分配管理。3.对用户校验后的数据库表的操作权限的校验
mysql最大连接数:show variables like "%max_connections%";
当前用户的连接:show processlist;
sql层:sql语句是由连接层传递过来的
如:select * from user where id > 10 and (age >11 or sex = 0 );
-
先判断sql语句的类型
(query(select)),dml(insert, update, delete), ddl(alter), status(show status)等 -
假设query
mysql8之前是先判断查询缓存是否开启,如果开启查询缓存,看是否命中,如果命中,那么直接返回结果,反之继续执行。
mysql8.0之后,执行流程是解析器,sql解析器,语法解析器。
sql解析器:根据查询的sql语句将sql划分为小token
将上面的sql语句分成了select
,*
,from
,where
,id
,>
,10
。。。
得到前面分解的token,根据token去进行排列组合(关键字and or)成解析树
是根据where条件中的关键词进行组合。
优化器做了什么?
优化器:根据解析树,选择合适的执行计划(这个计划不一定最优)
1.获取表结构信息(字段信息,字段类型,存储位置,索引信息)获取的信息是查询的表的信息。如果是join那么就是获取两张表的信息。
2. 根据解析树进行条件过滤,主要是一些没有意义的查询 1=1
3.索引信息 来确定、判断执行计划
4.执行这个计划,在索引以及条件等来过滤