摘要:输入一条语句,返回一个结果,却不晓得这条语句在 MySQL 内部的执行过程。
本文分享自华为云社区《一条查找SQL是怎样执行的-云社区-华为云》,作者: 共饮一杯无 。
执行如下SQL,咱们看到的只是输入一条语句,返回一个结果,却不晓得这条语句在 MySQL 内部的执行过程。
select * from where id =1;
上图给出的是 MySQL 的基本架构示意图,从中你能够清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。大体来讲,MySQL 能够分为 Server 层和存储引擎层两部分。
Server 层包含连接器、查找缓存、分析器、优化器、执行器等,涵盖 MySQL 的大都数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,例如存储过程、触发器、视图等。
而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持 InnoDB、MyISAM、Memory 等多个存储引擎。此刻最常用的存储引擎是 InnoDB,它从 MySQL 5.5.5 版本起始作为了默认存储引擎。亦能够经过指定存储引擎的类型来选取别的引擎,例如在 create table 语句中运用 engine=memory, 来指定运用内存引擎创建表。
一条SQL查找的完整执行流程如上图所示。
Server服务层
连接器
连接数据库最起始肯定是连接器。连接器负责跟客户端创立连接、获取权限、维持和管理连接。连接命令通常是这么写的:
mysql -h$ip -P$port -u$user -p输完命令之后,你就必须在交互对话里面输入秘码。虽然秘码亦能够直接跟在 -p 后面写在命令行中,但这般可能会引起你的秘码泄密。倘若你连的是生产服务器,剧烈意见你不要这么做。
连接命令中的 mysql 是客户端工具,用来跟服务端创立连接。在完成经典的 TCP 握手后,连接器就要起始认证你的身份,这个时候用的便是你输入的用户名和秘码。 倘若用户名或秘码不对,你就会收到一个"Access denied for user"的错误,而后客户端程序结束执行。倘若用户名秘码认证经过,连接器会到权限表里面查出你持有的权限。之后,这个连接里面的权限判断规律,都将依赖于此时读到的权限。
这就寓意着,一个用户成功创立连接后,即使你用管理员账号对这个用户的权限做了修改,亦不会影响已然存在连接的权限。修改完成后,仅有再新建的连接才会运用新的权限设置。
连接完成后,倘若你无后续的动作,这个连接就处在空闲状态,你能够在 show processlist 命令中看到它。文本中这个图是 show processlist 的结果,其中的 Command 列表示为“Sleep”的这一行,就暗示此刻系统里面有一个空闲连接。
客户端倘若太长期没动静,连接器就会自动将它断开。这个时间是由于参数 wait_timeout 掌控的,默认值是 8 小时。
倘若在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。此时候倘若你要继续,就必须重连,而后再执行请求了。
数据库里面,长连接指的是连接成功后,倘若客户端连续有请求,则始终运用同一个连接。短连接则指的是每次执行完很少的几次查找就断开连接,下次查找再重新创立一个。
创立连接的过程一般是比较繁杂的,因此我意见你在运用中要尽可能减少创立连接的动作,亦便是尽可能运用长连接。
然则所有运用长连接后,你可能会发掘,有些时候 MySQL 占用内存涨得尤其快,这是由于 MySQL 在执行过程中临时运用的内存是管理在连接对象里面的。这些资源会在连接断开的时候才释放。因此倘若长连接累积下来,可能引起内存占用太大,被系统强行杀掉(OOM),从现象看便是 MySQL 反常重启了。
怎么处理这个问题呢?你能够思虑以下两种方法。 定时断开长连接。运用一段时间,或程序里面判断执行过一个占用内存的大查询后,断开连接,之后要查找再重连。倘若你用的是 MySQL 5.7 或更新版本,能够在每次执行一个比很强的操作后,经过执行 mysql_reset_connection 来重新初始化连接资源。这个过程不必须重连和重新做权限验证,然则会将连接恢复到刚才创建完时的状态。
查找缓存
连接创立完成后,你就能够执行 select 语句了。执行规律就会来到第二步:查找缓存。
MySQL 拿到一个查找请求后,会先到查找缓存瞧瞧,之前是不是执行过这条语句。之前执行过的语句及其结果可能会以 key-value 对的形式,被直接缓存在内存中。key 是查找的语句,value 是查找的结果。倘若你的查找能够直接在这个缓存中找到 key,那样这个 value 就会被直接返回给客户端。
倘若语句不在查找缓存中,就会继续后面的执行周期。执行完成后,执行结果会被存入查找缓存中。你能够看到,倘若查找命中缓存,MySQL 不必须执行后面的繁杂操作,就能够直接返回结果,这个效率会很高。
然则大都数状况下我会意见你不要运用查找缓存,为什么呢?由于查找缓存常常坏处大于利。
查找缓存的失效非常频繁,只要有对一个表的更新,这个表上所有的查找缓存都会被清空。因此呢很可能你费劲地把结果存起来,还没运用呢,就被一个更新全清空了。针对更新压力大的数据库来讲,查找缓存的命中率会非常低。除非你的业务便是有一张静态表,很长期才会更新一次。例如,一个系统配置表,那这张表上的查找才适合运用查找缓存。
好在 MySQL 亦供给了这种“按需运用”的方式。你能够将参数 query_cache_type 设置成 DEMAND,这般针对默认的 SQL 语句都不运用查找缓存。而针对你确定要运用查找缓存的语句,能够用 SQL_CACHE 显式指定,像下面这个语句同样:
mysql> select SQL_CACHE * from T where ID=10;必须重视的是,MySQL 8.0 版本直接将查找缓存的整块功能删掉了,亦便是说 8.0 起始彻底无这个功能了。
分析器
倘若无命中查找缓存,就要起始真正执行语句了。首要,MySQL 必须晓得你要做什么,因此呢必须对 SQL 语句做解析。
分析器先会做“词法分析”。你输入的是由于多个字符串和空格构成的一条 SQL 语句,MySQL 必须识别出里面的字符串分别是什么,表率什么。
MySQL 从你输入的"select"这个关键字识别出来,这是一个查找语句。它亦要把字符串“T”识别成“表名 T”,把字符串“ID”识别成“列 ID”。
做完了这些识别以后,就要做“语法分析”。按照词法分析的结果,语法分析器会按照语法规则,判断你输入的这个 SQL 语句是不是满足 MySQL 语法。
倘若你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,例如下面这个语句 select 少打了开头的字母“s”。
mysql> elect * from t where ID=1;
ERROR 1064 (42000): You have an error inyour SQL syntax; check the manual that corresponds to your MySQL server versionfor the right syntax to use near elect * from t where ID=1 at line 1
通常语法错误会提示第1个显现错误的位置,因此你要关注的是紧接“use near”的内容。
优化器
经过了分析器,MySQL 就晓得你要做什么了。在起始执行之前,还要先经过优化器的处理。
优化器是在表里面有多个索引的时候,决定运用哪个索引;或在一个语句有多表相关(join)的时候,决定各个表的连接次序。一般两种执行办法的规律结果是同样的,然则执行的效率会有区别,而优化器的功效便是决定选取运用哪一个方法。优化器周期完成后,这个语句的执行方法就确定下来了,而后进入执行器周期。
执行SQL查找的时候优化器重点执行如下任务: 选取最合适的索引;选取表扫还是走索引;选取表相关次序;优化 where 子句;排除管理中无用表;决定 order by 和 group by 是不是走索引;尝试运用 inner join 替换 outer join;简化子查找,决定结果缓存;
MySQL 查找优化器有几个目的,然则其中最重点的目的是尽可能地运用索引,并且运用最严格的索引来消除尽可能多的数据行。
优化器试图排除数据行的原由在于它排除数据行的速度越快,那样找到与要求匹配的数据行亦就越快。倘若能够首要进行最严格的测试,查找就能够执行地更快。
执行器
MySQL 经过分析器晓得了你要做什么,经过优化器晓得了该怎么做,于是就进入了执行器周期,起始执行语句。
起始执行的时候,要先判断一下你对这个表 T 有无执行查找的权限,倘若无,就会返回无权限的错误,如下所示 (在工程实现上,倘若命中查找缓存,会在查找缓存返回结果的时候,做权限验证。查找亦会在优化器之前调用 precheck 验证权限)。
mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user b@localhost for table T
倘若有权限,就打开表继续执行。打开表的时候,执行器就会按照表的引擎定义,去运用这个引擎供给的接口。
例如咱们这个例子中的表 T 中,ID 字段无索引,那样执行器的执行流程是这般的: 调用 InnoDB 引擎接口取这个表的第1行,判断 ID 值是不是 10,倘若不是则跳过,倘若是则将这行存在结果集中;调用引擎接口取“下一行”,重复相同的判断规律,直到取到这个表的最后一行。执行器将以上遍历过程中所有满足要求的行构成的记录集做为结果集返回给客户端。
至此,这个语句就执行完成为了。
针对有索引的表,执行的规律亦差不多。第1次调用的是“取满足要求的第1行”这个接口,之后循环取“满足要求的下一行”这个接口,这些接口都是引擎中已然定义好的。
你会在数据库的慢查找日志中看到一个 rows_examined 的字段,暗示这个语句执行过程中扫描了多少行。这个值便是在执行器每次调用引擎获取数据行的时候累加的。
在有些场景下,执行器调用一次,在引擎内部则扫描了多行,因此呢引擎扫描行数跟 rows_examined 并不是完全相同的。
存储引擎
经过 show engines;查看引擎类型,能够看出来要用到事务只能用InnoDB引擎类型
InnoDB存储引擎
InnoDB是MySQL的默认事务型引擎,亦是最重要、运用最广泛的存储引擎,并且有行级锁定和外键约束。
它被设计用来处理海量的短期(short-lived)事务,短期事务大部分状况是正常提交,很少会被回滚。InnoDB的性能和自动崩溃恢复特性,使得它在非事务型存储的需求中亦很流行。除非有非常尤其的原由必须运用其他的存储引擎,否则应该优先思虑InnoDB引擎。
InnoDB的适用场景/特性,有以下几种: 经常更新的表,适合处理多重并发的更新请求。支持事务。能够从劫难中恢复(经过bin-log日志等)。外键约束。仅有他支持外键。支持自动增多列属性auto_increment。
MyISAM存储引擎
MyISAM供给了海量的特性,包含全文检索、压缩等,但不支持事务和行级锁,支持表级锁。 针对只读的数据,或表较小、能够忍受修复操作的场景,依然能够运用MyISAM。
MyISAM的适用场景/特性,有以下几种: 不支持事务的设计,然则并不表率着有事务操作的项目不可用MyISAM存储引擎,完全能够在程序层进行按照自己的业务需求进行相应的掌控。不支持外键的表设计。查找速度火速,倘若数据库insert和update的操作比较多的话比较适用。整天 对表进行加锁的场景。MyISAM极度强调快速读取操作。MyIASM中存储了表的行数,于是SELECT COUNT(*) FROM TABLE时只必须直接读取已然保留好的值而不必须进行全表扫描。倘若表的读操作远远多于写操作且不必须数据库事务的支持,那样MyIASM亦是很好的选取。
MySQL内建的其他存储引擎
MySQL还有有些特殊用途的存储引擎,在有些特殊场景下用起来会很爽的。在MySQL新版本中,有些可能由于有些原由已然再也不支持了,还有有些会继续支持,然则必须知道地启用后才可运用。
Archive存储引擎
Archive引擎只支持insert和select操作,并且在MySQL 5.1之前连索引都不支持。
Archive引擎会缓存所有的写并利用zlib对插进的行进行压缩,因此比MyISAM引擎的磁盘I/O更少。然则每次select查找都必须进行全表扫描,因此Archive更适合日志和数据采集类应用,况且这类应用在做数据分析时常常必须全表扫描。
Archive引擎支持行级锁和专用的缓冲区,因此能够实现高并发的插进。在一个查找起始直到返回表中存在的所有行之前,Archive引擎会阻止其他的select执行,以实现一致性读。另一,这亦实现了批量插进在完成之前对读操作是不看见的。
Blackhole存储引擎
Blackhole引擎无实现任何的存储机制,它会丢失所有插进的数据,不做任何保留。怪哉,岂不是一无用处?
然则服务器会记录Blackhole的日志,因此能够用于复制数据到备库,或只是简单地记录到日志。这种特殊的存储引擎能够在一些特殊的复制架构和日志审核时发挥功效。
但这种存储引擎的存在,迄今还是有些难以理解。
CSV存储引擎
CSV引擎能够将普通的CSV文件做为MySQL的表来处理,但这种表不支持索引。
CSV引擎能够在数据库运行时拷入或拷出文件,能够将Excel等电子表格软件中的数据存储为CSV文件,而后复制到MySQL数据目录下,就能在MySQL中打开运用。一样,倘若将数据写入到一个CSV引擎表中,其他的外边程序亦能立即从表的数据文件中读取CSV格式的数据。
因此呢,CSV引擎能够做为一种数据交换的机制,是非常有用的。
Memory存储引擎
倘若必须快速地拜访数据,并且这些数据不会被修改,重启以后丢失亦无关系,那样运用Memory引擎是非常有用的。Memory引擎最少比MyISAM引擎要快一个数量级,由于所有的数据都保留在内存中,不必须进行磁盘I/O。Memory引擎的表结构在重启以后还会保存,但数据会丢失。
Memory引擎在非常多场景下能够发挥很好的功效: 用于查询或映射表,例如将邮箱和州名映射的表。用于缓存周期性聚合数据的结果。用于保留数据分析中产生的中间数据。
Memory引擎支持Hash索引,因此呢查询非常快。虽然Memory的速度非常快,但还是没法取代传统的基于磁盘的表。Memory引擎是表级锁,因此呢并发吸入的性能较低。
倘若MySQL在执行查找的过程中,必须运用临时表来保留中间结果,内部运用的临时表便是Memory引擎。倘若中间结果太大超出了Memory的限制,或含有BLOB或TEXT字段,则临时表会转换成MyISAM的引擎。
看了上面的说明,大众就会经常混淆Memory和临时表了。临时表指的是运用CREATE TEMPORARY TABLE语句创建的表,它能够运用任何存储引擎,因此呢和Memory不是一回事。临时表仅在单个连接中可见,当连接断开时,临时表亦将不复存在。
关于临时表和Memory引擎的哪些事,可参考MySQL · 引擎特性 · 临时表哪些事儿。
MySQL的存储引擎及第三方存储引擎,还有非常多,这里就不一一介绍了,后续如有必须,再进一步来谈谈。
怎样选取合适的存储引擎呢
这么多存储引擎,真是眼花缭乱,咱们该怎样选取呢?
大部分状况下,都会选取默认的存储引擎——InnoDB,并且这亦是最正确的选取,因此Oracle在MySQL 5.5版本时最终将InnoDB做为默认的存储引擎了。
针对怎样选取合适的存储引擎,能够简单地归纳为一句话:”除非必须用到某些InnoDB不具备的特性,并且无其他能够替代,否则都应该优先选取InnoDB引擎”。
例如,倘若要用到全文检索,意见优先思虑InnoDB加上Sphinx的组合,而不是运用支持全文检索的MyISAM。当然,倘若不必须用到InnoDB的特性,同期其他引擎的特性能够更好地满足需求,就能够思虑一下其他存储引擎。
除非万不得已,意见不要混合运用多种存储引擎,否则可能带来一系列繁杂的问题,以及有些潜在的bug和边界问题。
倘若必须运用区别的存储引擎,意见思虑从以下几个原因进行衡量思虑。 事务备份恢复特有的特性
其他查询引擎SQL
经过下面的命令查看默认的存储引擎。
mysql> show variables like %storage_engine%;
--查看表的存储引擎
show table status like "table_name" ;若有收获,就点赞关注一下吧
点击下方,第1时间认识华为云鲜嫩技术~
华为云博客_大数据博客_AI博客_云计算博客_研发者中心-华为云
|