关注微信公众号程序媛小水,与您一起进步
应该有很多朋友都用过或者听说过数据库mysql,那么你清楚mysql对查询是怎么运作的嘛? 这篇文章水水就来分享一下mysql是如何执行查询语句。
安装mysql
首先我们需要安装mysql服务器,我是在ubuntu 16.04环境下进行安装。
1. 打开终端,更新软件包列表
$ sudo apt update
2. 安装mysql
$ sudo apt-get install mysql-server mysql-client

3. mysql脚本进行初始化
$ sudo mysql_secure_installation
执行这条命令时会出现几次mysql的询问:修改root账号的密码、移除匿名用户、允许远程登录、删除test数据库。
4. 登录
mysql -u root -p
5. 创建MySQL数据库和用户
$ create database datatest; # 创建一个名为datatest的数据库
mysql> create user`moly`@`*` identified by'123456'; #创建molly用户
ps:在创建用户时 需要注意(我就是踩坑里了弄了半天):
user`moly`@`*` 需要用 反引号 `
但是水水还是遇到了问题

# flush privileges 命令的作用是mysql用户数据和权限有修改后,不重启MySQL服务直接生效。
mysql> flush privileges
之后就可以开心的添加用户啦~

可以查看一下我们创建好的数据库~
mysql> show databases;
查看连接的数据库
mysql> show processlist;
如果不需要可以进行删除~
mysql> drop databases datatest;
做完了这些准备工作,就要到今天的重点-mysql到底是怎么实现语句查询的呢?
mysql 的基本架构
MySQL 可以分为 Server 层和存储引擎层两部分。
这里我画了一个图,不太好看大家先凑合看哈~

Server 层
包括连接器、查询缓存、分析器、优化器、执行器等,涵盖 MySQL 的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。 而存储引擎层负责数据的存储和提取。
连接器
mysql服务器与客户端进行连接。
本地连接 mysql -u 用户名 -p 密码
远程连接 mysql -h 远程ip或域名 -p 端口 -u 用户名 -p 密码
mysql -u root -p
虽然密码也可以直接跟在 -p 后面写在命令行中,但可能会导致你的密码泄露。
连接器做了几个工作?
-
将客户端连接到服务端
-
获取到权限等信息
从权限表里边查询用户权限并保存在一个变量里边以供查询缓存。
分析器,执行器在检查权限的时候使用。
-
在连接的有效时长内对sql进行处理。
interactive_timeout
wait_timeout
其中 wait_timeout是非交互式连接的空闲超时,interactive_timeout是交互式连接的空闲超时。
长链接的危害
在连接时最好使用长链接,但是MySQL 在执行过程中临时使用的内存在连接的对象里,并且这些资源会在连接断开的时候才释放。 所以会占用很多内存,达到一定值后有可能被系统强制杀死。
怎么解决?
有两个方法:
-
定期断开长连接。
使用一段时间,或者执行过一个占用内存的查询操作后,断开连接。
-
可以使用这个API来重新初始化连接资源,将连接恢复到刚刚创建完时的状态。
mysql_reset_connection
查询缓存
拿到语句,先到缓存以(key-value的形式查询),如果内存中有,则把value返回。大家可能觉得缓存这个东西不错嗷,可以减少mysql的工作量。如果之前查询过直接把值拿过来就可以了。但是水水却觉得缓存尽量别用~大家先别急,往下看。
为什么不用缓存?
查询缓存的失效非常频繁,只要有一个表的更新,那么这个表上所有的查询缓存都会被清空。这就会引发一个很大的问题,对于更新频繁的数据库来说,查询缓存的命中率会非常低。而且查询缓存是要从内存中去查询,命中率低会影响数据库服务器的性能。因此水水建议如果数据库表经常更新,最好不要使用缓存。
如何查看缓存?
mysql> show variables like '%query_cache%';
如何设置不使用缓存?
- 将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。
- 也可以用 SQL_NO_CACHE 指定
mysql> select SQL_NO_CACHE count(host) from user;
分析器
分析器主要负责将命令拆分成词来进行词法和语法分析。
词法分析:识别关键字,表名,列名等等(查看表,列是否存在)从information schema里面获得表的信息的。
语法分析:是否满足sql语法
mysql是如何进行语法分析的呢?
答案是通过解析器和预处理器~
-
mysql通过 关键词 将sql命令语句解析成一棵 “解析树”
-
解析器处理语法和解析查询,主要有验证关键词的拼写和顺序是否正确。
如果语法不正确会出现 "You have an error in your SQL syntax"
-
预处理器进一步检查解析树是否合法。主要有 检查表和列是否存在,别名是否被占用等等。
-
预处理器验证用户是否有查询权限。
如果通过则生成新的解析树,再提交给优化器。
优化器
决定使用哪个索引(表中有多个索引) 或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。最后生成执行计划进入执行器。
执行器
- 判断是否有这个表的查询权限
res= select_precheck(thd, lex, all_tables, first_table);
-
根据指令,通过API调用底层存储引擎执行。
mysql实现了一个抽象接口层 handler(sql/handler.h)
有了分析器的权限的检查为什么还需要执行器的权限检查??
如果使用触发器,得在执行器阶段才能确定。 所以分析器工作结束后的precheck是不能对这种运行时涉及到的表进行权限校验的,所以需要在执行器阶段进行权限检查。 另外正是因为有precheck这个步骤,才会在报错时报的是用户无权限,而不是 k字段不存在,以免暴露表结构。