MySQL—一条查询SQL语句的完整执行流程
MySQL—一条查询SQL语句的完整执行流程
表结构和数据如下:
我们分析的sql语句如下:
select tb_id,tb_name,tb_address from tb_user where tb_id = 66;
大体来说,MySQL可以分为Server层和存储引擎层两部分:
Server层
包括:连接器、查询缓存、分析器、优化器、执行器等
涵盖MySQL的大多数核心服务功能
所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现
- 比如:存储过程、触发器、视图等
存储引擎层:
- 负责数据的存储和提取
- 可插拔式存储引擎:InnoDB、MyISAM、Memory等
- 最常用存储引擎是InhoDB
- 从MySQL 5.5版本开始,默认存储引擎是lnnoDB
第一步:连接到数据库
首先会连接到这个数据库上,这时候接待我们的就是连接器。
mysql -uroot -p
连接完成后,如果没有后续的动作,这个连接就处于空闲状态。客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数wait_timeout
控制的,默认值是8小时。
show processlist;
其中的 Command 列显示为“Sleep”的这一行,就表示现在系统里面有一个空闲连接。
第二步:查缓存
MySQL拿到一个查询请求后,会先到查询缓存看看,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以key-value对的形式,被直接缓存在内存中。key是查询的语句hash之后的值,value是查询的结果。
如果查询语句在缓存中,会被直接返回给客户端。
如果语句不在查询缓存中,就会继续后面的执行阶段。执行完成后,执行结果会被存入查询缓存中。
如果查询命中缓存,MySQL不需要执行后面的复杂操作就可以直接返回结果,效率会很高!但是不建议使用MySQL的内置缓存功能。
查询缓存
查询缓存默认是关闭的状态。
# 查看是否开启缓存
show variables like 'query_cache_type';
# 查看缓存的命中次数:
show status like 'qcache_hits';
开启缓存
在/etc/my.cnf
文件中修改“query_cache_type”参数
值为`0或OFF`会禁止使用缓存。
值为`1或ON`将启用缓存,但以`SELECT SQL_NO_CACHE`开头的语句除外。
值为`2或DEMAND`时,只缓存以`SELECT SQL_CACHE`开头的语句。
清空查询缓存
可以使用下面三个SQL来清理查询缓存:
# 清理查询缓存内存碎片。
FLUSH QUERY CACHE;
# 从查询缓存中移出所有查询。
RESET QUERY CACHE;
# 关闭所有打开的表,同时该操作将会清空查询缓存中的内容。
FLUSH TABLES;
不建议使用MySQL的查询缓存
因为查询缓存往往弊大于利
成本高:查询缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。因此很可能你费劲地把结果存起来,还没使用呢,就被一个更新全清空了。
命中率不高:对于更新压力大的数据库来说,查询缓存的命中率会非常低。除非你的业务就是有一张静态表,很长时间才会更新一次。比如,一个系统配置表,那这张表上的查询才适合使用查询缓存。
功能并不如专业的缓存工具更好:redis、memcache、ehcache...
MySQL提供了按需使用的方式,我们可以将参数query_cache_type设置成DEMAND,这样对于默认的SQL语句都不使用查询缓存。而对于你确定要使用查询缓存的语句,可以用SQL_CACHE显式指定,像下面这个语句一样:select sql_cache * from tb_user where tb_id = 16;
MySQL 8.0 版本直接将查询缓存的整块功能删掉了。
第三步:分析SQL语句
如果查询缓存没有命中,接下来就需要进入正式的查询阶段了。客户端程序发送过来的请求,实际上只是一个字符串而已,所以MySQL服务器程序首先需要对这个字符串做分析,判断请求的语法是否正确,然后从字符串中将要查询的表、列和各种查询条件都提取出来,本质上是对一个SQL语句编译的过程,涉及词法解析、语法分析、预处理器等。
- 词法分析:词法分析就是把一个完整的SQL语句分割成一个个的字符串;
- 语法分析:语法分析器根据词法分析的结果做语法检查,判断你输入的SQL语句是否满足MySQL语法;
- 预处理器:预处理器则会进一步去检查解析树是否合法,比如表名是否存在,语句中表的列是否存在等等,在这一步MySQL会检验用户是否有表的操作权限。
词法分析
比如我们前文所提到的sql语句,分割前为:
select tb_id,tb_name,tb_address from tb_user where tb_id = 66;
分割后为
select,
tb_id,
tb_name,
tb_address,
from,
tb_user,
where,
tb_id,
=,
66
;
MySQL同时需要识别出这个SQL语句的字符串分别是什么,代表什么。
- 把select关键字识别出来,是查询语句;
- 把tb_user识别出来是表名
tb_user
; - ......
语法分析
如果语法正确就会根据MySQL语法规则与SQL语句生成一个数据结构——解析树;
如果我们把from
写成form
;
会报出如下错误:
我们前面的SQL语句,生成解析树如下:
select tb_id,tb_name,tb_address from tb_user where tb_id = 66;
预处理器
预处理器会进一步去检查解析树是否合法,比如表名是否存在,语句中表的列是否存在等等,在这一步MySQL会检验用户是否有表的操作权限。
预处理之后会得到一个新的解析树,然后调用对应执行模块。
第四步:优化SQL语句
优化器顾名思义就是对查询进行优化。作用是根据解析树生成不同的执行计划,然后选择最优的执行计划。
MySQL里面使用的是基于成本模型的优化器,哪种执行计划Explain执行时成本最小就用哪种。而且它是io_cost和cpu_cost的开销总和,它通常也是我们评价一个查询的执行效率的一个常用指标。
show status like 'Last_query_cost';
查看上次查询成本开销,默认值是0
优化器可以做的优化有:
- 当有多个索引可用的时候,决定使用哪个索引;
- 在一个语句有多表关联(join)的时候,决定各个表的连接顺序,以哪个表为基准表。
优化器最多是辅助,作用很有限,我们的SQL语句不能依赖于MySQL的优化器去调优!
第五步:执行SQL语句
判断执行权限
开始执行的时候,要先判断一下对这表tb_user有没有执行查询的权限,如果没有权限,就会返回无权限的错误。
比如:我们新建一个用户hello_user
,只有库sjdwz_test
表tab_test
的查询权限,没有表tb_user
的查询权限。
CREATE USER `hello_user`@`localhost` IDENTIFIED BY '7654321@Hello';
GRANT Select ON TABLE `sjdwz_test`.`tab_test` TO `hello_user`@`localhost`;
使用这个用户hello_user连接mysql,
mysql -uhello_user -p
执行下面的查询语句,就会返回没有权限的错误
select tb_id,tb_name,tb_address from tb_user where tb_id = 66;
调用存储引擎接口查询
如果有权限,就使用指定的存储引擎打开表开始查询。执行器会根据表的引擎定义,去使用这个引擎提供的查询接口提取数据。
- tb_id是主键执行流程:
- 调用InnoDB引擎接口,从主键索引中检索c_id=14的记录。
- 主键索引等值查询只会查询出一条记录,直接将该记录返回客户端。
- 至此,这个语句就执行完成了。
- tb_id不是主键执行流程:全表扫描
- 调用InnoDB引擎接口取这个表的第一行,判断tb_id 值是不是66,如果不是则跳过,如果是则将这行缓存在结果集中;
- 调用引擎接口取”下一行",重复相同的判断逻辑,直到取到这个表的最后一行。
- 执行器将上述遍历过程中所有满足条件的行组成的结果集返回给客户端。
- 至此,这个语句就执行完成了。
MySQL—一条查询SQL语句的完整执行流程的更多相关文章
- 一条update SQL语句是如何执行的
一条更新语句的执行过程和查询语句类似,更新的流程涉及两个日志:redo log(重做日志)和binlog(归档日志).比如我们要将ID(主键)=2这一行的值加(c:字段)1,SQL语句如下: upda ...
- MySQL概述 - 一条查询sql语句的执行过程
Server层 连接器 建立连接.获取权限.维持和管理连接. 连接建立比较复杂,建议使用长连接 定期断开长连接 mysql_reset_connection指令 查询缓存 建议关闭,任何更新操作会此t ...
- MySQL 的分页查询 SQL 语句
MySQL一般使用 LIMIT 实现分页.基本语句为: SELECT ... FROM ... WHERE ... ORDER BY ... LIMIT ... 在中小数据量的情况下,这样的SQL足够 ...
- 多条查询sql语句返回多表数据集
+ + "';SELECT ProductID,ProductTitle,ProductName,SalePrice,ListingPrice,MainPicture,SaledItemCo ...
- MySql 学习之 一条查询sql的执行过程
相信大家都接触过Mysql数据库,而且也肯定都会写sql.我不知道大家有没有这样的感受,反正我是有过这样的想法.就是当我把一条sql语句写完了,并且执行完得到想要的结果.这时我就在想为什么我写这样的一 ...
- 查找Mysql慢查询Sql语句
一.MySQL数据库有几个配置选项可以帮助我们及时捕获低效SQL语句 1,slow_query_log 这个参数设置为ON,可以捕获执行时间超过一定数值的SQL语句. 2,long_query_tim ...
- mysql 中常用的 sql 语句
SQL分类: DDL-----数据定义语言(CREATE--创建,ALTER--修改. DROP--删除表,DECLARE--声明) DML-----数据定义语言(SELECT--查询,DELECT- ...
- 一条查询sql的执行流程和底层原理
1.一条查询SQL执行流程图 2.查询SQL执行流程之发送SQL请求 (1)客户端按照Mysql通信协议将SQL发送到服务端,SQL到达服务端后,服务端会单起一个线程执行SQL. (2)执行时Mysq ...
- 面试官:说说一条查询sql的执行流程和底层原理?
一条查询SQL执行流程图如下 序章 自我介绍 我是一条sql,就是一条长长的字符串,不要问我长什么样,因为我比较傲娇. 额~~不是我不说啊,因为细说起来,我可以细分为DML(Update.Insert ...
- 【转】MySQL用户管理及SQL语句详解
[转]MySQL用户管理及SQL语句详解 1.1 MySQL用户管理 1.1.1 用户的定义 用户名+主机域 mysql> select user,host,password from mysq ...
随机推荐
- Android 关于Dialog在全屏弹出会显示状态栏和导航栏的问题解决
项目的奇葩需求,需要弹出Dialog不要显示状态栏和导航栏,记录一下解决方法 原文地址:Android 关于Dialog在全屏弹出会显示状态栏和导航栏的问题解决 Stars-one的杂货小窝 说明 A ...
- 关于百分百浏览器(cent browser)无法使用QQ快捷登录问题
个人比较喜欢用百分百浏览器,但是QQ似乎不允许此浏览器进行登录,参考了下网上提供的思路,研究解决了QQ无法登录的问题 主要就设置了下证书,详情步骤见下面图片
- day01-2-导入驱动和工具类
满汉楼01-2 4.功能实现01 4.1导入驱动和工具类 4.1.1导入驱动 首先将连接mysql的相关jar包引入项目中,分别右键,点击add as library 4.1.2导入工具类Utilit ...
- C++多态底层原理:虚函数表
虚函数表 C++ 对象模型 在有虚函数的情况下,C++对象的模型可以概括为:虚函数表指针+数据struct.在对象所在的内存里:前8个字节(64位系统)是虚函数表所在地址,后边是对象中的member ...
- 更新|3DCAT实时云渲染 v2.1.2版本全新发布
3DCAT实时渲染云在近期发布了新的v2.1.2的版本,让我们来看下做了哪些更新. 1. 整体UI的变更 目前的UI风格更加美观,区分开了3DCAT 应用控制中心和个人信息管理中心. 3DCAT 应用 ...
- VScode 配置私钥免密登录
VScode 配置私钥免密登录 配置公钥私钥进行免密登录在前文已经提及.在完成上述配置后,我们希望在VScode中配置,毕竟主要的开发环境还是在VScode上且连接到远程服务器会经常遇到网络不稳定需要 ...
- KingbaseES 参数设置优先级别
Oracle的参数可以设置system和session级别,当设置了session级别的参数时,会覆盖值system级别. KingbaseES除了该两个级别外,还有database级别.user/r ...
- Amazon免费CE2基于docker部署nginx,并实现访问
在部署之前,请确保你已经申请好了CE2免费的服务器,网上的相关教程很多,可以自由参考. 一.使用xshell+公钥连接实例 1.打开xshell,导入密钥, 选择"工具" -> ...
- #决策单调性dp,分治#LOJ 6039「雅礼集训 2017 Day5」珠宝
题目传送门 分析 观察到这个0/1背包中单个物品的体积不超过300,考虑分体积考虑. 设 \(dp[i]\) 表示容量大小为 \(i\) 的背包能获得的最大价值, \(dp[i]=\max\{dp[i ...
- #构造#洛谷 6470 [COCI2008-2009#6]CUSKIJA
题目 给定一个长度为 \(n\) 的序列 \(a\),请将其重新排序, 新序列中任意相邻两个数之和都不能被 \(3\) 整除. 分析 分类讨论,如果只有3的倍数多于1个无解 没有 \(3k+1\) 或 ...