MYSQL 执行过程

Mysql 整体执行过程如下图所示

image.png

1.1:连接器
主要职责:

  • 负责与客户端的通信, 是半双工模式, 这就意味着某一固定时刻只能由客户端向服务器请求或者服务器向客户端发送数据, 而不能同时进行
  • 验证请求用户的账户和密码是否正确, 如账户和密码错误, 会报错: Access denied for user 'root'@'localhost' (using password: YES)
  • 如果用户的账户和密码验证通过, 会在mysql自带的权限表中查询当前用户的权限

mysql中存在4个控制权限的表
分别为user表,db表,tables_priv表,columns_priv

  • User表: 存放用户账户信息以及全局级别(所有数据库) 权限,决定了来自哪些主机的哪些用户可以访问数据库实例
  • Db表: 存放数据库级别的权限,决定了来自哪些主机的哪些用户可以访问此数据库
  • Tables_priv表:存放表级别的权限,决定了来自哪些主机的哪些用户可以访问数据库的这个表
  • Columns_priv表:存放列级别的权限,决定了来自哪些主机的哪些用户可以访问数据库表的这个字段
  • Procs_priv表: 存放存储过程和函数 级别的权限

mysql权限表的验证过程为:

  • 先从user表中的Host,User,Password这3个字段中判断连接的ip、用户名、密码是否存在,存在则通过验证
  • 通过身份认证后,进行权限分配,按照user,db,tables_priv,columns_priv的顺序进行验证。即先检查全局权限表user,如果user中对应的权限为Y,则此用户对所有数据库的权限都为Y,将不再检查db, tables_priv,columns_priv;如果为N,则到db表中检查此用户对应的具体数据库,并得到db中为Y的权限;如果db中为N,则检查tables_priv中此数据库对应的具体表,取得表中的权限Y,以此类推
  • 如果在任何一个过程中权限验证不通过,都会报错

1.2:缓存
mysql的缓存主要的作用是为了提升查询的效率, 缓存以key和value的哈希表形式存储, key是具体的sql语句, value是结果的集合
如果无法命中缓存, 就继续走到分析器的的一步, 如果命中缓存就直接返回给客户端
不过需要注意的是在mysql的8.0版本以后缓存被官方删除掉了, 之所以删除掉, 是因为查询缓存的失效非常频繁 ,如果在一个写多读少的环境中 ,缓存会频繁的新增和失效
对于某些更新压力大的数据库来说, 查询缓存的命中率会非常低, mysql为了维护缓存可能会出现一定的伸缩性的问题, 目前在5.6的版本中已经默认关闭了
比较推荐的一种做法是将缓存放在客户端,性能大概会提升5倍左右

1.3:分析器
分析器的主要作用是将客户端发过来的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.

1.4:优化器
能够进入到优化器阶段表示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交给最后的执行器

1.5:执行器
在执行器的阶段, 此时会调用存储引擎的API, API会调用存储引擎
主要有一下存储的引擎,不过常用的还是myisaminnodb:

image

引擎以前的名字叫做: 表处理器, 负责对具体的数据文件进行操作, 对sql的语义如select或者update进行分析, 执行具体的操作
在执行完以后会将具体的操作记录到binlog中, 需要注意的一点是: select不会记录到binlog中, 只有update/delete/insert才会记录到binlog中. 而update会采用两阶段提交的方式,记录都redolog中

二:执行的状态
可以通过命令: show full processlist 展示所有的处理进程
主要包含了以下的状态, 表示服务器处理客户端的状态, 状态包含了从客户端发起请求到后台服务器处理的过程, 包括加锁的过程、统计存储引擎的信息, 排序数据、搜索中间表、发送数据等
囊括了所有的mysql的所有状态,其中具体的含义如下图:

image

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

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;

3.1:from
第一步就是选择出from关键词后面跟的表, 这也是sql执行的第一步: 表示要从数据库中执行哪张表。
实例说明: 在这个例子中就是首先从数据库中找到表T

3.2: join on
join是表示要关联的表, on是连接的条件. 通过from和join on选择出需要执行的数据库表T和S, 产生笛卡尔积, 生成T和S合并的临时中间表Temp1
on: 确定表的绑定关系, 通过on产生临时中间表Temp2
实例说明:找到表S, 生成临时中间表Temp1, 然后找到表T的id和S的id相同的部分组成成表Temp2, Temp2里面包含着T和Sid相等的所有数据

3.3: where
where表示筛选, 根据where后面的条件进行过滤, 按照指定的字段的值(如果有and连接符会进行联合筛选)从临时中间表Temp2中筛选需要的数据, 注意如果在此阶段找不到数据, 会直接返回客户端, 不会往下进行. 这个过程会生成一个临时中间表Temp3
注意在where中不可以使用聚合函数,聚合函数主要是(min\max\count\sum等函数)
实例说明: 在temp2临时表集合中找到T表的name="Yrion"的数据, 找到数据后会成临时中间表Temp3,temp3里包含name列为"Yrion"的所有表数据

3.4: group by
group by是进行分组, 对where条件过滤后的临时表Temp3按照固定的字段进行分组, 产生临时中间表Temp4, 这个过程只是数据的顺序发生改变, 而数据总量不会变化, 表中的数据以组的形式存在
实例说明: 在temp3表数据中对mobile进行分组, 查找出mobile一样的数据,然后放到一起, 产生temp4临时表

3.5: having
对临时中间表Temp4进行聚合, 这里可以为count等计数, 然后产生中间表Temp5, 在此阶段可以使用select中的别名
实例说明: 在temp4临时表中找出条数大于2的数据, 如果小于2直接被舍弃掉, 然后生成临时中间表temp5

3.6: select
对分组聚合完的表挑选出需要查询的数据, 如果为*会解析为所有数据, 此时会产生中间表Temp6
实例说明:在此阶段就是对temp5临时聚合表中S表中的id进行筛选产生Temp6, 此时temp6就只包含有s表的id列数据, 并且name="Yrion", 通过mobile分组数量大于2的数据

3.7: distinct
distinct对所有的数据进行去重, 此时如果有minmax函数会执行字段函数计算, 然后产生临时表Temp7
实例说明: 此阶段对temp5中的数据进行去重, 引擎API会调用去重函数进行数据的过滤, 最终只保留id第一次出现的那条数据, 然后产生临时中间表temp7

3.8: order by
会根据Temp7进行顺序排列或者逆序排列, 然后插入临时中间表Temp8, 这个过程比较耗费资源
实例说明: 这段会将所有temp7临时表中的数据按照创建时间(create_time)进行排序, 这个过程也不会有列或者行损失

3.9: limit
limit对中间表Temp8进行分页, 产生临时中间表Temp9, 返回给客户端
实例说明: 在temp7中排好序的数据, 然后取前五条插入到Temp9这个临时表中, 最终返回给客户端

ps: 实际上这个过程也并不是绝对这样的,中间mysql会有部分的优化以达到最佳的优化效果,比如在select筛选出找到的数据集

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352