你了解mysql是如何执行查询语句的嘛?

1,014 阅读5分钟

关注微信公众号程序媛小水,与您一起进步

应该有很多朋友都用过或者听说过数据库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 后面写在命令行中,但可能会导致你的密码泄露。

连接器做了几个工作?

  1. 将客户端连接到服务端

  2. 获取到权限等信息

    从权限表里边查询用户权限并保存在一个变量里边以供查询缓存。

    分析器,执行器在检查权限的时候使用。

  3. 在连接的有效时长内对sql进行处理。

interactive_timeout
wait_timeout

其中 wait_timeout是非交互式连接的空闲超时,interactive_timeout是交互式连接的空闲超时。

长链接的危害

在连接时最好使用长链接,但是MySQL 在执行过程中临时使用的内存在连接的对象里,并且这些资源会在连接断开的时候才释放。 所以会占用很多内存,达到一定值后有可能被系统强制杀死。

怎么解决?

有两个方法:

  1. 定期断开长连接。

    使用一段时间,或者执行过一个占用内存的查询操作后,断开连接。

  2. 可以使用这个API来重新初始化连接资源,将连接恢复到刚刚创建完时的状态。

    mysql_reset_connection
    

查询缓存

拿到语句,先到缓存以(key-value的形式查询),如果内存中有,则把value返回。大家可能觉得缓存这个东西不错嗷,可以减少mysql的工作量。如果之前查询过直接把值拿过来就可以了。但是水水却觉得缓存尽量别用~大家先别急,往下看。

为什么不用缓存?

查询缓存的失效非常频繁,只要有一个表的更新,那么这个表上所有的查询缓存都会被清空。这就会引发一个很大的问题,对于更新频繁的数据库来说,查询缓存的命中率会非常低。而且查询缓存是要从内存中去查询,命中率低会影响数据库服务器的性能。因此水水建议如果数据库表经常更新,最好不要使用缓存。

如何查看缓存?

mysql> show variables like '%query_cache%';

如何设置不使用缓存?

  1. 将参数 query_cache_type 设置成 DEMAND,这样对于默认的 SQL 语句都不使用查询缓存。
  2. 也可以用 SQL_NO_CACHE 指定
mysql> select SQL_NO_CACHE count(host) from user;

分析器

分析器主要负责将命令拆分成词来进行词法和语法分析。

词法分析:识别关键字,表名,列名等等(查看表,列是否存在)从information schema里面获得表的信息的。

语法分析:是否满足sql语法

mysql是如何进行语法分析的呢?

答案是通过解析器和预处理器~

  1. mysql通过 关键词 将sql命令语句解析成一棵 “解析树”

  2. 解析器处理语法和解析查询,主要有验证关键词的拼写和顺序是否正确。

    如果语法不正确会出现 "You have an error in your SQL syntax"

  3. 预处理器进一步检查解析树是否合法。主要有 检查表和列是否存在,别名是否被占用等等。

  4. 预处理器验证用户是否有查询权限。

    如果通过则生成新的解析树,再提交给优化器。

优化器

决定使用哪个索引(表中有多个索引) 或者在一个语句有多表关联(join)的时候,决定各个表的连接顺序。最后生成执行计划进入执行器。

执行器

  1. 判断是否有这个表的查询权限
 res= select_precheck(thd, lex, all_tables, first_table);
  1. 根据指令,通过API调用底层存储引擎执行。

    mysql实现了一个抽象接口层 handler(sql/handler.h)

有了分析器的权限的检查为什么还需要执行器的权限检查??

如果使用触发器,得在执行器阶段才能确定。 所以分析器工作结束后的precheck是不能对这种运行时涉及到的表进行权限校验的,所以需要在执行器阶段进行权限检查。 另外正是因为有precheck这个步骤,才会在报错时报的是用户无权限,而不是 k字段不存在,以免暴露表结构。