首页 > 数据库 >MySQL执行过程及执行顺序

MySQL执行过程及执行顺序

时间:2022-11-28 14:36:14浏览次数:44  
标签:缓存 MySQL 查询 权限 顺序 SQL 执行

一、MySQL执行过程

image

简单概括:

1、我们在客户端发起一个SQL的查询;
2、连接器判断用户登录以及用户权限;
3、缓存命中,走缓存,直接返回查询结果;
3、缓存没命中,到达分析器,对SQL语句进行分析,包括预处理与解析过程;
4、优化器,对SQL语句进行优化;
5、执行器,调用存储引擎,执行具体的SQL操作;
6、将操作记录在undo log中,并存储回滚段指针和事务ID。
7、通过索引查找数据
8、写入redo log
9、写binlog
10、提交事务

连接器(主要职责)

1、负责与客户端的通信

是半双工模式,这就意味着某一固定时刻只能由客户端向服务器请求或者服务器向客户端发送数据,而不能同时进行,其中MySQL在与客户端连接TC/IP的。

2、验证请求用户的账户和密码是否正确

如果账户和密码错误,会报错:Access denied for user 'root'@'localhost' (using password: YES)

3、查询当前用户的权限

如果用户的账户和密码验证通过,会在MySQL自带的权限表中查询当前用户的权限。

MySQL中存在4个控制权限的表:

user表:存放用户账户信息以及全局级别(所有数据库)权限,决定了来自哪些主机的哪些用户可以访问数据库实例
db表:存放数据库级别的权限,决定了来自哪些主机的哪些用户可以访问此数据库
tables_priv表:存放表级别的权限,决定了来自哪些主机的哪些用户可以访问数据库的这个表
columns_priv表:存放列级别的权限,决定了来自哪些主机的哪些用户可以访问数据库表的这个字段

MySQL权限表的验证过程

1、 先从user表中的Host,User,Password这3个字段中判断连接的IP、用户名、密码是否存在,存在则通过验证。

2、通过身份认证后,进行权限分配,按照user,db,tables_priv,columns_priv的顺序进行验证。即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db,tables_priv,columns_priv;如果为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限;如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推。

3、如果在任何一个过程中权限验证不通过,都会报错。

缓存

MySQL的缓存主要的作用是为了提升查询的效率,缓存以key和value的哈希表形式存储,key是具体的SQL语句,value是结果的集合。

如果无法命中缓存,就继续走到分析器的这一步,如果命中缓存就直接返回给客户端。

不过需要注意的是在MySQL的8.0版本以后,缓存被官方删除掉了。 之所以删除掉,是因为查询缓存的失效非常频繁,如果在一个写多读少的环境中,缓存会频繁的新增和失效。对于某些更新压力大的数据库来说,查询缓存的命中率会非常低,MySQL为了维护缓存可能会出现一定的伸缩性的问题,目前在5.6的版本中已经默认关闭了,

比较推荐的一种做法是将缓存放在客户端,性能大概会提升5倍左右。

分析器

分析器的主要作用是将客户端发过来的SQL语句进行分析,这将包括预处理与解析过程,在这个阶段会解析SQL语句的语义,并进行关键词和非关键词进行提取、解析,并组成一个解析树。

具体的关键词包括不限定于以下:select/update/delete/or/in/where/group by/having/count/limit等。

如果分析到语法错误,会直接给客户端抛出异常:“ERROR:You have an error in your SQL syntax.”。

比如:select * from user where userId =1234;

在分析器中就通过语义规则器将select from where这些关键词提取和匹配出来,MySQL会自动判断关键词和非关键词,将用户的匹配字段和自定义语句识别出来。

这个阶段也会做一些校验:比如校验当前数据库是否存在user表,同时假如user表中不存在userId这个字段同样会报错:

“unknown column in field list.”。

优化器

能够进入到优化器阶段,表示SQL是符合MySQL的标准语义规则的并且可以执行的,

此阶段主要是进行SQL语句的优化,会根据执行计划进行最优的选择,匹配合适的索引,选择最佳的执行方案。

比如一个典型的例子是这样的:
表T,对A、B、C列建立联合索引,在进行查询的时候,当SQL查询到的结果是:select xx where B=x and A=x and C=x,很多人会以为是用不到索引的,但其实会用到,虽然索引必须符合最左原则才能使用,但是本质上,优化器会自动将这条SQL优化为:where A=x and B=x and C=X,这种优化会为了底层能够匹配到索引,同时在这个阶段是自动按照执行计划进行预处理,MySQL会计算各个执行方法的最佳时间,最终确定一条执行的SQL交给最后的执行器。

执行器

在执行器的阶段,此时会调用存储引擎的API,API会调用存储引擎,主要有一下存储的引擎,不过常用的还是myisam和innodb;
image
引擎以前的名字叫做:表处理器(其实这个名字我觉得更能表达它存在的意义)负责对具体的数据文件进行操作,对SQL的语义比如select或者update进行分析,执行具体的操作。

在执行完以后会将具体的操作记录到binlog中,需要注意的一点是:select不会记录到binlog中,只有update/delete/insert才会记录到binlog中。而update会采用两阶段提交的方式,记录都redolog中。

二、执行的状态

可以通过命令:show full processlist,展示所有的处理进程,主要包含了以下的状态,表示服务器处理客户端的状态,

状态包含了从客户端发起请求到后台服务器处理的过程,包括加锁的过程、统计存储引擎的信息,排序数据、搜索中间表、发送数据等。囊括了所有的MySQL的所有状态,其中具体的含义如下图:
image

三、SQL的执行顺序

事实上,SQL并不是按照我们的书写顺序来从前往后、左往右依次执行的,它是按照固定的顺序解析的,主要的作用就是从上一个阶段的执行返回结果来提供给下一阶段使用,SQL在执行的过程中会有不同的临时中间表。
image
image

例子:
select distinct s.id from T t join S s on t.id=s.id where t.name="Yrion" group by t.mobile having count(*)>2 order by s.create_time limit 5;

这里有几个需要注意的地方:

1、SQL语句是从FROM开始执行的,而不是SELECT。MySQL在执行SQL查询语句的时,首先是将数据从硬盘加载到数据缓冲区中,以便对这些数据进行操作。

2、SELECT是在FROM和GROUP BY 之后执行的。这就导致了无法在WHERE中使用SELECT中设置字段的别名作为查询条件。

3、UNION是排在ORDER BY之前的。虽然数据库允许SQL语句对UNION段中的子查询或者派生表进行排序,但是这并不能说明在 UNION 操作过后仍保持排序后的顺序。

4、在MySQL中SQL的逻辑查询是根据上述进行查询,但MySQL可能并不完全会按照逻辑查询处理方式进行查询。MySQL有2个组件:1),分析SQL语句的Parser;2)、优化器Optimizer;MySQL在执行查询之前,都会选择一条自认为最优的查询方案去执行,获取查询结果。一般情况下都能计算出最优的查询方案,但在某些情况下,MySQL给出的查询方案并不是很好的查询方案。

5、存在索引时,优化器优先使用索引的插叙条件,当索引为多个时,优化器会直接选择效率最高的索引去执行。

四、SQL语句where后条件执行先后顺序

结论

  • 针对MySQL,其条件执行顺序是 从左往右,自上而下。

  • 针对Orcale,其条件执行顺序是从右往左,自下而上。

MySQL

MySQL where执行顺序是从左往右执行的,在数据量小的时候不用考虑,但数据量多的时候要考虑条件的先后顺序,此时应遵守一个原则:排除越多的条件放在第一个。

在用MySQL查询数据库的时候,连接了很多个过滤条件,发现非常慢。例如:

select… where p.languages_id=1 and t.type=1 and p.products_id in(472,474);

这样查询需要20多秒,虽然在各个字段上都建立了索引。用分析Explain SQL一分析,发现在第一次分析过程中就返回了几万条数据:where d p.languages_id=1 ,然后再依次根据条件缩小范围。

然后稍微改变一下where字段的位置之后,速度就有了明显地提高:

where p.products_id in(472,474) and p.languages_id=1 and t.type=1;

这样第一次的过滤条件是p.products_id in(472,474),它返回的结果只有不到10条,接下来还要根据其它的条件来过滤,自然在速度上有了较大的提升。

标签:缓存,MySQL,查询,权限,顺序,SQL,执行
From: https://www.cnblogs.com/zhaojinhui/p/16932090.html

相关文章

  • Net6 CodeFirst注入MySQL数据库上下文
    十年河东,十年河西,莫欺少年穷学无止境,精益求精 2022太难了,好多公司倒闭,互联网不景气,工作难找,苏州的C#/Net程序员的招聘更是少之又少,java,C,等其他语言也是供大于求,总之,难上......
  • mysql,在win10上绿色安装5.7版本
    1.下载地址,选择5.7的zip包https://downloads.mysql.com/archives/community/2.解压到自定义路径下我这里选择的路径D:\mysql手动创建了文件my.inimy.ini内容点击查......
  • 企业级自定义表单引擎解决方案(十七)--Job配置执行
    .netcore研发的低代码自定义表单引擎,采用强大的规则引擎将所有的业务串联起来的,和其他低代码平台是有本质的区别的,目标是完全解放繁琐的CRUD工作。常规的业务,在需求以及......
  • 顺序栈的实现及应用
    实现packagestackimport"log"typeArrayStackstruct{ items[]string//存储栈元素的数组 nint//栈的大小 countint//栈中元素的个数}......
  • Mysql与Redis如何保证数据的一致性?
    问题分析:当MySQL中的数据发生更新时,就面临一个问题,如何确保MySQL与Redis数据的一致性,我们有两个选择:先更新MySQL,后删除(或更新)Redis先删除(或更新)Redis,后更新MySQL......
  • Linux日志轮询设置时间执行【原创】
    自动切割时间默认的logrotate(配置文件里设置的是cron.daily)一般会在每天的3点05分到3点50分之间执行但是由于我们统计日志时间需要从每天0点开始,所以就要利用crontab设置......
  • application、nacos和各个配置文件生效顺序
    平常Java开发中会用到好多配置文件,比如application、bootstrap、nacos文件等下面就来说一下生效顺序nacos>application-dev.yaml>application.yaml>bootstrap.yaml......
  • python3.7安装mysqlclient失败问题
    问题直接使用pipinstall安装mysqlclient最新版本2.1.1失败了,提示“Failedbuildingwheelformysqlclient”解决步骤:换wheel方式安装,去pypi官网准备下载文件,突然发......
  • ThinkPHP6 使用原生mysql表达式
    1if(!empty($param)){2$where[]=['','exp',Db::raw("FIND_IN_SET(".$param.",mysqlfield)")];3}使用这种查询表达式,注意几点:1.数组......
  • JavaWeb-MySql高级
    JavaWeb-MySql高级1,约束1.1概念约束是作用于表中列上的规则,用于限制加入表的数据例如:我们可以给id列加约束,让其值不能重复,不能为null值。约束的存在保证了数据......