引言

本文为社区首发签约文章,14天内制止转载,14天后未获授权制止转载,侵权必究!

MySQL数据库从1995年诞生至今,现已过去了二十多个年初了,到2022.04.26日中止,MySQL8.0.29正式发行了GA版别,在此之前版别也产生了多次迭代,发行了大大小小N多个版别,其间每个版别中都有各自的新特性,悉数版别的特性加起来,用一本书的篇幅也无法彻底论述清楚,因而本章首要会挑要点特性来讲,具体各版别的特性可参阅MySQL官网的开发手册:

  • 《MySQL官网-5.6版手册》
  • 《MySQL官网-5.7版手册》
  • 《MySQL官网-8.0版手册》

这儿首要讲一下5.6、5.7、8.0这三个版别,由于这三个版别归于MySQL里程碑式的发行版,其实除开这三个版别外,5.1版别也是早期最主流的版别,但迄今中止基本上都并不必该版别了,因而不再对其做过多描绘。

一、MySQL5.6支撑的新技能

MySQL5.6Oracle的得意之作,该版别是让MySQL真实走向高功用数据库的里程碑版别,在此之前的MySQL版别中,尽管功用也较为丰富,但功用相较于同期的Oracle数据库而言,其实体现并欠安。直到Oracle公司接手MySQL后,首要就对其进行了雷厉风行的改善,从Oracle中移植了许多特性过来,一起废弃一些原有的鸡肋功用,也优化了许多内部完结,终究打造出了MySQL5.6这个版别。

但这儿关于MySQL5.6中不重要的特性不会罗列,要点解说一些较为重要的新特性。

1.1、支撑只读事务(Read-Only)

在此之前的版别中,MySQL默许会为每个事务都分配事务ID,悉数事务都天公地道,但在5.6版别中开端支撑只读事务,MySQL内部会有两个事务链表,一个是只读事务链表,一个是正常事务链表。

当一个事务中只要读操作时,MySQL并不会为这些事务分配ID,默许悉数为0(可是会分配查询ID),然后将其标记为一个只读事务,并加入只读事务链表中,直到当这个事务中呈现改动数据的操作时,才会正式为其分配事务ID,以及将其挪动到正常事务链表中。

这样做的优点在于:其他事务使用MVCC机制读取数据时,生成的ReadView读视图中的活跃事务链表会小许多许多,因而遍历的速度更快,一起也无需为其分配回滚段,然后进一步进步了MySQL全体的查询功用。

1.2、InnoDB存储引擎增强

首要就说一下InnoDB的核心:BufferPool缓冲池相关的改善项,首要有两点:刷盘战略改善、缓冲池预热。

1.2.1、缓冲池刷盘战略优化

在之前的版别的InnoDB-BufferPool缓冲池中,改动过的数据页会共用MySQL后台的刷盘线程,也便是redo-log、undo-log、bin-log.....一系列内存到磁盘的刷盘作业,都是选用同一批线程来完结。在MySQL5.6版别中,BufferPool引进了独立的刷盘线程,也就意味着缓冲池中改动过的数据页会由专门的线程来负责刷盘,这样能够进步缓冲池的刷盘功率,无需排队等待刷写。

一起BufferPool的刷盘线程,还支撑敞开多线程并发刷盘操作,这样在缓冲池较大的状况下,能够进一步进步刷盘的功率,然后让数据落盘的功率更快,从必定程度上也进步了数据的安全性,究竟内存中的数据随时都有几率丢掉,但落盘后基本上不是硬件损坏,都有或许康复过来。

1.2.2、BufferPool缓冲池预热

缓冲池预热是一种特别好的机制,在之前版别的内存缓冲池中,当MySQL封闭时,本来内存中的热门数据都会被清空,重启后悉数的热门数据又需求经过时刻的沉积,然后才干留在内存中。但MySQL5.6版别中,每次封闭MySQL时都会将内存中的热门数据页保存到磁盘中,当重启时会直接从磁盘中载入之前的热门数据,避免了热门数据的从头“选拔”!

这样做的优点无疑是巨大的,举个比如就能够了解,如下:

现在整个村庄中选拔综合才干最强的男人,本来现已选拔了一批相对来说最优异的人出来,但由于村庄暂时呈现变故需求集体外出,所以本次选拔赛会被搁浅,当处理好变故后再次敞开选拔赛,又从头从头开端选拔,这明显非常影响功率。

而预热的含义是:呈现意外变故时,先将上次选拔赛中最优异的那批人,把对应的姓名保存在一个名单中,处理完变故后,只需求找到这个名单,把名单上的人喊过来持续选拔即可,这样做明显将功率进步了N倍。

1.3、新增Performance_Schema库监控大局资源

假如对MySQL比较熟悉的小伙伴应该清楚,在之前的版别中存在一个名为information_schema的库,其间会记载一些MySQL工作期间需求用到的表,比方视图办理、存储进程与函数的办理、暂时表的办理、会话的办理、触发器的办理、表分区的办理……,这些内容的信息都会被存储到information_schema库中。

而在MySQL5.6中,官方又加入了一个新的自带库:performance_schema,这儿面会记载:数据库全体的监控信息,比方事务监控信息、最近履行的SQL信息、最近衔接的客户端信息、数据库各空间的运用信息……,依据这个库能够在线上构建出一个完善的MySQL监控体系:

  • Statements/execution stagesMySQL计算的一些耗费资源较高的SQL句子。
  • Table and Index I/OMySQL计算的那些表和索引会导致I/O负载过高。
  • Table LocksMySQL计算的表中数据的锁资源竞争信息。
  • Users/Hosts/Accounts:耗费资源最多的客户端、IP机器、用户。
  • Network I/OMySQL计算的一些网络相关的资源状况。
  • .......

1.4、索引下推机制(Index Condition Pushdown)

Index Condition Pushdown索引下推简称ICP,它是MySQL5.6版别以后引进的一种优化机制,以下述用户表为例,这张表上依据姓名、性别、暗码字段树立了一个联合索引,此刻先来看看下面的状况:

select * from `zz_users`;
+---------+-----------+----------+----------+---------------------+
| user_id | user_name | user_sex | password | register_time       |
+---------+-----------+----------+----------+---------------------+
|       1 | 熊猫      || 6666     | 2022-08-14 15:22:01 |
|       2 | 竹子      || 1234     | 2022-09-14 16:17:44 |
|       3 | 子竹      || 4321     | 2022-09-16 07:42:21 |
|       4 | 猫熊      || 8888     | 2022-09-17 23:48:29 |
+---------+-----------+----------+----------+---------------------+
INSERT INTO `zz_users` VALUES(5,"竹竹","女","8888","2022-09-20 22:17:21");
SELECT * FROM `zz_users` WHERE `user_name` LIKE "竹%" AND `user_sex`="男";

首要为了愈加直观的讲清楚索引下推,因而先再向用户表中添加一条数据。然后再来看看后面的查询SQL,这条SQL会运用联合索引吗?答案是会的,但只能部分运用,由于联合索引的每个节点信息大致如下:

{
    ["熊猫","女","6666"] : 1,
    ["竹子","男","1234"] : 2,
    ["子竹","男","4321"] : 3,
    ["猫熊","男","4321"] : 4,
    ["竹竹","女","8888"] : 5
}

由于前面运用的是含糊查询,但%在结尾,因而能够运用这个字作为条件在联合索引中查询,整个查询进程如下:

  • ①使用联合索引中的user_name字段找出「竹子、竹竹」两个索引节点。
  • ②回来索引节点存储的值「2、5」给Server层,然后去逐个做回表扫描。
  • ③在Server层中依据user_sex="男"这个条件逐条判别,终究挑选到「竹子」这条数据。

有人或许会疑问,为什么user_sex="男"这个条件不在联合索引中处理呢?由于前面是含糊查询,所以拼接起来是这样的:竹x男,由于这个x是不知道的,因而无法依据最左前缀准则去匹配数据,终究这儿只能运用联合索引中user_name字段的一部分,后续的user_sex="男"还需求回到Server层处理。

那什么又叫做索引下推呢?也便是将Server层挑选数据的作业,下推到引擎层处理。

以前面的事例来解说,MySQL5.6加入索引下推机制后,其履行进程是什么样子的呢?

  • ①使用联合索引中的user_name字段找出「竹子、竹竹」两个索引节点。
  • ②依据user_sex="男"这个条件在索引节点中逐个判别,然后得到「竹子」这个节点。
  • ③终究将「竹子」这个节点对应的「2」回来给Server层,然后聚簇索引中回表拿数据。

相较于没有索引下推之前,本来需求做「2、5」两次回表查询,但在具有索引下推之后,仅需做「2」一次回表查询。

索引下推在MySQL5.6版别之后是默许敞开的,能够经过指令set optimizer_switch='index_condition_pushdown=off|on';指令来手动办理。

1.5、MRR(Multi-Range Read)机制

Multi-Range Read简称为MRR机制,这也是和索引下推一同在MySQL5.6版别中引进的功用优化办法,那什么叫做MRR优化呢?

一般来说,在实践事务中我们应当尽量经过索引掩盖的特性,削减回表操作以下降IO次数,但在许多时候往往又不得不做回表才干查询到数据,但回表明显会导致产生许多磁盘IO,一起更严峻的一点是:还会产生许多的离散IO,下面举个比如来了解。

SELECT * FROM `zz_student_score` WHERE `score` BETWEEN 0 AND 59;

上述这条SQL所做的作业很简略,便是在学生成果表中查询悉数成果未及格的学生信息,假定成果字段上存在一个一般索引,那考虑一下,这条SQL的履行流程是什么样的呢?

  • ①先在成果字段的索引上找到0分的节点,然后拿着ID去回表得到成果零分的学生信息。
  • ②再次回到成果索引,持续找到悉数1分的节点,持续回表得到1分的学生信息。
  • ③再次回到成果索引,持续找到悉数2分的节点……
  • ④循环往复,不断重复这个进程,直到将0~59分的悉数学生信息悉数拿到中止。

那此刻假定此刻成果0~5分的表数据,位于磁盘空间的page_01页上,而成果为5~10分的数据,位于磁盘空间的page_02页上,成果为10~15分的数据,又位于磁盘空间的page_01页上。此刻回表查询时就会导致在page_01、page_02两页空间上来回切换,但0~5、10~15分的数据彻底能够兼并,然后读一次page_01就能够了,既能削减IO次数,一起还避免了离散IO

MRR机制就首要是处理这个问题的,针关于辅助索引的回表查询,削减离散IO,而且将随机IO转换为次序IO,然后进步查询功率。

MRR机制具体是怎样做的呢?MRR机制中,关于辅助索引中查询出的ID,会将其放到缓冲区的read_rnd_buffer中,然后等悉数的索引检索作业完结后,或许缓冲区中的数据到达read_rnd_buffer_size大小时,此刻MySQL会对缓冲区中的数据排序,然后得到一个有序的ID调集:rest_sort,终究再依据次序IO去聚簇/主键索引中回表查询数据。

SET @@optimizer_switch='mrr=on|off,mrr_cost_based=on|off';

能够经过上述这条指令敞开或封闭MRR机制,MySQL5.6及以后的版别是默许敞开的。

1.6、主从数据同步的仿制改善

随着互联网时代浪潮的兴起,体系中的并发量、数据量日益增长,传统的单库在有些状况下就有些乏力,开端只能经过不断晋级硬件配置的手段来进步功用。可单机的功用无论怎么晋级硬件,总有到达瓶颈的一天,因而散布式的概念开端进入我们眼中,而MySQL5.6中也针关于多节点布置的状况,其数据同步问题做了大幅度优化。

MySQL5.6中,针关于主从数据同步的问题,首要引进了GTID仿制、无损仿制(增强半同步仿制)、延时仿制、并行仿制这四种技能,但由于现在《MySQL专栏》还未开端发布“MySQL高可用”相关的文章,因而这些内容会在后续的《主从仿制篇》论述。

1.7、MySQL5.6中的其他特性

前面介绍的几点,归于比较重要的一些知识,但除此之外,5.6版别中还存在许多特性与优化项,如:

  • 索引增强:全文索引支撑InnoDB与亚洲语种分词、支撑空间索引等。
  • 表分区增强:单表分区数量最大可创立8192个、分区锁功用进步、支撑cloumns分区类型。
  • 增强日期类型:time、datetime、timestamp精度进步到微秒级,datetime容量缩减到5字节。
  • 日志增强:Redo-log文件大小约束由4G→512GUndo-log文件可独立指定方位存储。
  • 支撑在线DDL(Online DDL)、对limit句子做了优化……

(二十)MySQL特性篇:2022年的我们,必须要懂的那些数据库新技术!

除开上述外,还有许多许多与之前不同的改动,官方声称在5.6中修复了1667Bug,因而想要更为全面的了解,可阅读《MySQL官网-5.6版手册》。

二、MySQL5.7引进的新特性

相较于长辈5.6、后辈8.0而言,MySQL5.7版别就显的中规中矩,其间没有产生太多的改动,MySQL5.7更倾向于5.6的稳定版,究竟5.6版别中步子迈的太大,许多方面的技能都需求依据市场反馈做纤细调整,因而成功的为MySQL5.7做好了衬托,一般的项目假如不选用MySQL8.0,基本上都会挑选MySQL5.7而不是5.6

MySQL5.7中也存在几个能令人眼前一亮的优化项,接着就要点聊一聊这些要点~

2.1、引进同享排他锁

MySQL5.7之前的版别中,数据库中仅存在两种类型的锁,即同享锁与排他锁,可是在MySQL5.7.2版别中引进了一种新的锁,被称之为(SX)同享排他锁,这种锁是同享锁与排他锁的杂交类型,至于为何引进这种锁呢?聊它之前需求先了解SMO问题:

SQL履行期间一旦更新操作触发B+Tree叶子节点割裂,那么就会对整棵B+Tree加排它锁,这不但堵塞了后续这张表上的悉数的更新操作,一起也阻挠了悉数试图在B+Tree上的读操作,也便是会导致悉数的读写操作都被堵塞,其影响巨大。因而,这种大粒度的排它锁成为了InnoDB支撑高并发拜访的首要瓶颈,而这也是MySQL 5.7版别中引进SX锁要处理的问题。

那想一下该怎么处理这个问题呢?最简略的方法便是减小SMO问题产生时,确定的B+Tree粒度,当产生SMO问题时,就只确定B+Tree的某个分支,而并不是确定整颗B+树,然后做到不影响其他分支上的读写操作。

MySQL5.7中引进同享排他锁后,究竟是怎么完结的这点呢?先聊聊SX锁的特性,它不会堵塞S锁,可是会堵塞X、SX锁,下面打开来说说。

在聊之前得搞清楚SQL履行时的几个概念:

  • 读取操作:依据B+Tree去读取某条或多条行记载。
  • 达观写入:不会改动B+Tree的索引键,仅会更改索引值,比方主键索引树中不修正主键字段,只修正其他字段的数据,不会引起节点割裂。
  • 失望写入:会改动B+Tree的结构,也便是会造成节点割裂,比方无序刺进、修正索引键的字段值。

MySQL5.6版别中,一旦有操作导致了树结构产生改变,就会对整棵树加上排他锁,堵塞悉数的读写操作,而MySQL5.7版别中,为了处理该问题,关于不同的SQL履行,流程就做了调整。

2.1.1、MySQL5.7中读操作的履行流程

  • ①读取数据之前首要会对B+Tree加一个同享锁。
  • ②在依据树检索数据的进程中,关于悉数走过的叶节点会加一个同享锁。
  • ③找到需求读取的方针叶子节点后,先加一个同享锁,开释进程②上加的悉数同享锁。
  • ④读取终究的方针叶子节点中的数据,读取完结后开释对应叶子节点上的同享锁。

2.1.2、MySQL5.7中达观写入的履行流程

  • ①达观写入之前首要会对B+Tree加一个同享锁。
  • ②在依据树检索修正方位的进程中,关于悉数走过的叶节点会加一个同享锁。
  • ③找到需求写入数据的方针叶子节点后,先加一个排他锁,开释进程②上加的悉数同享锁。
  • ④修正方针叶子节点中的数据后,开释对应叶子节点上的排他锁。

2.1.3、MySQL5.7中失望写入的履行流程

  • ①失望更新之前首要会对B+Tree加一个同享排他锁。
  • ②由于①上现已加了SX锁,因而当时事务履行进程中会堵塞其他测验更改树结构的事务。
  • ③遍历查找需求写入数据的方针叶子节点,找到后对其分支加上排他锁,开释①中加的SX锁。
  • ④履行SMO操作,也便是履行失望写入操作,完结后开释进程③中在分支上加的排他锁。

假如需求修正多个数据时,会在遍历查找的进程中,记载下悉数要修正的方针节点。

2.1.4、MySQL5.7中并发事务抵触剖析

调查上述讲到的三种履行状况,关于读操作、达观写入操作而言,并不会加SX锁,同享排他锁仅针关于失望写入操作会加,由于读操作、达观写入履行前对整颗树加的是S锁,因而失望写入时加的SX锁并不会堵塞达观写入和读操作,但当另一个事务测验履行SMO操作改动树结构时,也需求先对树加上一个SX锁,这时两个失望写入的并发事务就会呈现抵触,新来的事务会被堵塞。

可是要注意:当第一个事务寻找到要修正的节点后,会对其分支加上X锁,紧接着会开释B+Tree上的SX锁,这时别的一个履行SMO操作的事务就能获取SX锁啦!

其实从上述中或许得知一点:MySQL5.7版别引进同享排他锁之后,处理了5.6版别产生SMO操作时堵塞悉数读写操作的问题,这样能够在必定程度上进步了InnoDB表的并发功用。

最后要注意:尽管一个履行失望写入的事务,找到了要更新/刺进数据的节点后会开释SX锁,可是会对其上级的叶节点(叶分支)加上排他锁,因而正在产生SMO操作的叶分支,仍旧是会堵塞悉数的读写行为!

上面这句话啥意思呢?也便是当一个要读取的数据,位于正在履行SMO操作的叶分支中时,仍旧会被堵塞。

2.2、MySQL开端支撑json格局

随着非结构化数据的存储需求持续增长,各类非联系型数据库应运而生,例如大名鼎鼎的MongoDB,各大联系型数据库为了防止市场占用率流失,也开端补偿关于这块的支撑,因而在MySQL5.7.8版别中也支撑了json数据类型,而且为其供给了一系列操作的API

尽管说MySQL也支撑了json格局存储,但明显是亡羊补牢,为时已晚,天然无法抢过MongoDB的市场占用率,从功用和存储容量来说,MySQL也无法竞争过MongoDB,但相较于其他非结构化数据库,MySQL存储json数据有两大优势:①关于json数据的API操作支撑事务。②支撑为一个表字段设置json格局,也就意味着MySQL中能够将结构化数据和非结构化数据共同存储。

2.3、MySQL5.7中的其他特性

除开上述两点值得打开叙说的特性外,其他的基本上是一些纤细改变,因而就不对其进行打开叙述啦,这儿稍微罗列一下MySQL5.7版别中,其他的特性支撑,如下:

  • 暂时表优化,暂时表的写操作不记载redo-log、不为其生成缓冲数据页,减小资源占用。
  • 多接点布置时,数据同步仿制再次优化,支撑多主/源仿制、以及真实意义上的并行仿制等。
  • 引进了虚拟列的完结,类似于Oracle数据库中的函数索引。
  • 移除了默许的test数据库,以及默许不会创立匿名用户,引进暗码过期战略。
  • 触发器增强,表上同一种事件、同一机遇的触发器可创立多个,之前则只能答应创立一个。
  • 推出了新的mysqlpump工具,用于数据的逻辑备份、引进了新的客户端工具mysqlsh等。
  • 支撑经过max_execution_time约束一条SQL的履行超时时刻、支撑innodb_deadlock_detect死锁检测。
  • GIS空间数据类型增强,运用Boost.Geometry代替原有的GIS算法,InnoDB支撑空间索引。
  • .......

除此之外其实也仍旧存在其他许多细节方面的新特性支撑和优化项,具体可参阅《MySQL官网-5.7版手册》。

三、MySQL8.0产生的大改动

MySQL8.0发行前,基本上悉数运用MySQL数据库的企业/个人项目,基本上都归于MySQL5.6/5.7的钉子户,基本上不会再挑选除此之外的发行版,但随着MySQL8.0的发行,打破了这个局面,官方声称经压测后,8.05.7功用足足进步了200%,这无疑关于MySQL的忠诚用户而言,明显是一个非常巨大的诱惑。

由于依照理论来说,只要你将项目中的MySQL,从原有的MySQL5.7版别晋级到MySQL8.0版别,从数据库的功用上来说,无需你手动做任何优化,就能够让功用翻倍。

不过的确在MySQL8.0版别中,再次推出了非常多重要的新特性,也推出了许多关于功用的优化项,因而接下来打开聊聊最新的MySQL8.0系版别。

3.1、移除查询缓存(Query Cache)

Query Cahce查询缓存的规划初衷很好,也便是使用热门勘探技能,关于一些频频履行的查询SQL,直接将成果缓存在内存中,之后再次来查询相同数据时,就无需走磁盘,而是直接从查询缓存中获取数据并回来。

听起来好像还不错呀,如同的确能带来不小的功用进步呢?但实则很鸡肋,为啥?看个比如。

select * from zz_users where user_id=1;
select * from zz_users where user_id = 1;

比方上述这两条SQL句子,在我们看来是不是相同的?的确,都是在查询ID=1的用户数据,但奇葩的工作呈现了,MySQL的查询缓存会把它当做两条不同的SQL,也便是假如上面的第一条SQL,其查询成果被放入到了缓存中,第二条SQL仍旧无法射中这个缓存,会持续走表查询的方法获取数据,Why

由于MySQL查询缓存是以SQL的哈希值来作为Key的,上面两条SQL尽管相同,可是后面的查询条件有纤细差别:user_id=1、user_id = 1,也便是一条SQL有空格,一条没有。

由于这一点点纤细差异,会导致两条SQL计算出的哈希值彻底不同,因而无法射中缓存,是不是很鸡肋?还有多种状况:user_id =1、user_id= 1,空格处于的前后方位不同,也会导致缓存失效。

也正是由于方方面面的原因,所以查询缓存在MySQL8.0中被彻底舍弃了,即移除掉了查询缓存区,各方面原因如下:

  • ①缓存射中率低:简直大部分SQL都无法从查询缓存中取得数据。
  • ②占用内存高:将许多查询成果放入到内存中,会占用至少几百MB的内存。
  • ③添加查询进程:查询表之前会先查一次缓存,查询后会将成果放入缓存,额定多几步开支。
  • ④缓存保护本钱不小,需求LRU算法筛选缓存,一起每次更新、刺进、删除数据时,都要清空缓存中对应的数据。
  • ⑤查询缓存是专门为MyISAM引擎规划的,而InnoDB构建的缓冲区彻底具有查询缓存的效果。

由于上述一系列原因,再加上项目中一般都会运用Redis先做事务缓存,因而能来到MySQL的查询句子,简直都是要从表中读数据的,所以查询缓存的位置就显得愈加突兀,所以在8.0版别中就直接去掉了,究竟弊大于利,带来的收益达不到规划时的预期。

3.2、锁机制优化

MySQL8.0中的锁机制首要呈现了两点优化,一方面临获取同享锁的写法进行了优化,如下:

-- MySQL8.0之前的版别
SELECT ... LOCK IN SHARE MODE;
-- MySQL8.0及后续的版别
SELECT ... FOR SHARE;

第二方面则支撑非堵塞式获取锁机制,能够在获取锁的写法上加上NOWAIT、SKIP LOCKED关键字,这样在未获取到锁时不会堵塞等待,运用SKIP LOCKED未获取到锁时会直接回来空,运用NOWAIT会直接回来并向客户端回来异常。用法如下:

select ... for update nowait;
select ... for update skip locked;

3.3、在线修正的体系参数支撑耐久化

在之前的版别中,经过set、set global的方法修正某个体系变量时,这种方法设置的参数值都是一次性的,也便是修正过的参数并不会被同步到本地,当MySQL重启时,这些调整过的参数又会回归默许值,假如想要让调整过的参数收效,就有必要要手动中止MySQL,然后去修正my.ini/my.conf文件,修正完结后再重启数据库服务,这时才干让参数永久收效。

这种方法无疑是非常痛苦的,尤其是在做数据库线上调优时,修正参数后重启又会失效,有时重启忘记再次调整参数,终究导致数据库服务呈现问题,这种体验令人很糟心。

而在MySQL8.0中则彻底优化了这个问题,推出了在线修正参数后,支撑耐久化到本地文件的机制,也便是经过SET PERSIST指令来完结,如下:

-- 调整事务的阻隔等级(针关于当时衔接有用)
set transaction isolation level read uncommitted;
-- 调整事务的阻隔等级(针关于大局有用,重启后会丢掉)
set global tx_isolation = "read-committed";
-- 调整事务的阻隔等级(针关于大局有用,而且会耐久化到本地,重启后不会丢掉)
set persist global.tx_isolation = "repeatable-read";

经过set persist指令耐久化的参数,能够经过下述指令来查看:

select * from performance_schema.persisted_variables;

这条指令的本质其实是:依据MySQL自带的performance_schema监控库查询耐久化过的参数。

其实参数耐久化的原理也非常简略,当履行set persist指令时,会将改动过的参数写入到本地的mysqld-auto.cnf文件中,MySQL每次启动时都会读取这个文件中的值,假如该文件中存在参数,则会直接将其加载,然后完结了一次修正,永久有用。

但当你想要参数不再耐久化到本地时,能够挑选删除装置目录下的mysqld-auto.cnf文件,或履行reset persist指令来清除,但这两种方法都只对下次重启时收效,究竟本次参数现已被载入内存了,所以只能经过再次手动修正的方法康复。

3.4、增强多表衔接查询

在之前的MySQL版别中,仅支撑穿插衔接、内衔接、左外衔接、右外衔接四种衔接类型,这四种衔接都会选用默许的衔接算法,而在8.0版别中供给了哈希衔接、反衔接两种衔接优化的支撑。

3.1.1、哈希衔接(Hash Join)

所谓的哈希衔接其实并非一种新的连表方法,而是一种连表查询的算法,在联系型数据库中多表连查一般有三种算法:Hash-Join哈希散列衔接、Sort-Merge-Join排序兼并衔接、Nest-Loop-Join嵌套循环衔接,这三种连表算法在Oracle数据库中都支撑,但MySQL之前的版别中,悉数的连表方法都仅支撑Nest-Loop-Join嵌套循环衔接,关于这点在《SQL优化篇-以小驱大》中聊到过。

而到了MySQL8.0.18版别发布后,MySQL对内衔接的方法支撑了哈希衔接算法,那究竟啥叫哈希衔接算法呢?和之前传统的循环衔接算法又有啥差异呢?接下来一起打开聊一聊。

哈希衔接算法和循环衔接算法的差异

先来看看传统的循环衔接算法的连表查询进程是怎样样的呢?如下:

(二十)MySQL特性篇:2022年的我们,必须要懂的那些数据库新技术!

在循环衔接算法中,会首要挑选一张小表作为驱动表,然后顺次将驱动表中每一条数据作为条件,去被驱动表中做遍历,终究得到契合衔接条件的悉数数据,也便是会形成一个下述的伪逻辑:

for(数据 x : 驱动表){
    for(数据 y : 被驱动表){
        if (x == y){
            // 假如契合衔接条件,则记载到衔接查询的成果会集.....
        }
    }
}

这种循环衔接的算法中,明显会造成巨大的开支,由于驱动表每条数据都需求和被驱动表的完好数据做一次遍历。也正是为了处理这个问题,由于MySQL8.0中引进了哈希衔接算法,进程如下:

(二十)MySQL特性篇:2022年的我们,必须要懂的那些数据库新技术!

在哈希衔接算法中会分为两个阶段:

  • 构建阶段:挑选一张小表作为构建表,接着会依据衔接字段做哈希处理,生成哈希值放入内存中构建出一张哈希表。
  • 勘探阶段:遍历大表的每一行数据,然后对衔接字段做哈希处理,经过生成的哈希值与内存哈希表做比较,契合条件则放入成果会集。

比照之前的循环衔接算法,这种哈希衔接算法带来的功用进步直线进步N倍,由于在循环衔接算法中,需求遍历count(驱动表)次,即驱动表中有多少条数据就要遍历多少次。而在这种算法中,只需求将大表遍历一次,伪逻辑代码如下:

// 构建阶段:将小表的每行数据,依据哈希值放入内存哈希表中
Map hashTable = new HashMap();
for(数据 x : 构建表){
    hashTable.put(x);
}
// 勘探阶段:遍历大表的每行数据与内存哈希表做衔接匹配
for(数据 y : 勘探表){
    if (hashTable.get(y) != null){
        // 假如哈希处理后能够在内存哈希表中存在,
        // 则表明这条数据契合衔接条件,则记载到衔接查询的成果会集.....
    }
}

哈希衔接比照循环衔接算法而言,首要在两方面能够得到功用进步:

  • ①哈希衔接算法中,只需求将大表遍历一次,但循环衔接算法需求遍历N次。
  • ②哈希衔接勘探阶段,做衔接判别时只需求先对数据做一次哈希处理,然后在内存中查找即可,复杂度仅为O(1),但循环衔接算法的复杂度为O(n)
哈希衔接算法的丧命问题

但尽管哈希衔接算法能够带来杰出的功用进步,但也存在一个丧命问题,便是内存中join_buffer_size的容量无法彻底载入构建表的哈希数据时怎样办呢?这儿就有两种处理方案:

  • ①分批处理,将构建表的数据拆分为几部分,每次载入一部分到内存,但这样会导致大表的遍历次数,随着分批次数变大而增多。
  • ②使用磁盘完结,也便是首要将构建表的悉数数据做哈希处理,放不下时将一部分处理好的哈希数据放入磁盘,在勘探阶段遍历大表时,每次对大表数据生成哈希值后,做判别时从磁盘顺次读取处理好的哈希值做判别。

MySQL中挑选的是第二种,也便是当内存无法彻底放下构建表的哈希数据时,会选用磁盘+内存混合的模式履行哈希衔接。

MySQL什么状况下会选用哈希衔接?

首要并不是多表衔接的状况下都会运用哈希衔接算法,该算法有几个硬性约束:

  • ①现在哈希衔接算法仅支撑内衔接的多表连查方法。
  • ②哈希衔接算法有必要要求存在等值衔接条件,即a.id=b.id才行,a.id>b.id是不可的。
  • ③假如衔接字段能够走索引查询的状况下,默许仍旧会选用循环衔接算法。

第二点的原因在于:哈希衔接算法生成的哈希值是无序的,所以有必要要用等值衔接才行。
第三点的原因在于:衔接查询时走索引的功率并不低,哈希衔接需求生成哈希表,因而需求时刻,因而在能够走索引连表的状况下,哈希衔接算法的功率反而比不上循环衔接。

也便是说,当连表时存在等值衔接条件,而且未射中索引的状况下,MySQL默许会选用哈希衔接算法来完结连表查询,不过还有一种状况也会运用,便是笛卡尔积状况,即不指定衔接条件的状况下也会运用哈希衔接,此刻MySQL会直接对整条数据生成哈希表。

关于哈希衔接算法,MySQL是默许敞开的,我们可经过set optimizer_switch="hash_join=off";的方法来手动操控开关。

3.1.2、反衔接(Anti Join)

反衔接是MySQL8.0关于一些反范围查询操作的优化,首要针关于下述几种状况会做优化:

  • NOT IN (SELECT … FROM …)
  • NOT EXISTS (SELECT … FROM …)
  • IN (SELECT … FROM …) IS NOT TRUE
  • EXISTS (SELECT … FROM …) IS NOT TRUE
  • IN (SELECT … FROM …) IS FALSE
  • EXISTS (SELECT … FROM …) IS FALSE

MySQL早些版别中,运用NOT EXISTS、NOT IN、IS NOT...这类操作时有或许会导致索引失效,而且也会让查询功率变低,因而MySQL8.0版别中会对上述几类句子进行优化,当你的SQL句子运用了上述语法检索数据时,在MySQL内部会将其转变为反衔接类型的查询句子。

也便是会将右边的子查询成果集,变为一张物理暂时表,然后依据条件字段做衔接查询,官方声称在某些场景下,能够让上述几类句子的查询功用进步20%,但关于这块我没做深入研讨,因而就不打开叙述啦。

3.5、增强索引机制

8.0中官方再一次对索引机制动刀,首要对联合索引供给了一种跳动扫描机制的支撑,也就意味着运用联合索引时,就算未遵循最左前缀匹配准则,也能够运用联合索引来检索数据。除此之外,还有别的三种新的索引特性:躲藏索引、降序索引以及函数索引。

3.5.1、索引跳动式扫描机制(Index Skip Scan)

在之前讲《索引运用篇》时,我们初度提到了最左前缀匹配准则,也便是SQL的查询条件中有必要要包括联合索引的第一个字段,这样才干射中联合索引查询,但实践上这条规则也并不是100%遵循的。由于在MySQL8.0版别中加入了一个新的优化机制,也便是索引跳动式扫描,这种机制使得我们即便查询条件中,没有运用联合索引的第一个字段,也仍旧能够运用联合索引,看起来就像跳过了联合索引中的第一个字段相同,这也是跳动扫描的称号由来。

但跳动扫描究竟是怎样完结的呢?上个栗子快速了解一下。

比方此刻经过(A、B、C)三个列树立了一个联合索引,此刻有如下一条SQL

SELECT * FROM `tb_xx` WHERE B = `xxx` AND C = `xxx`;

按理来说,这条SQL既不契合最左前缀准则,也不具有运用索引掩盖的条件,因而肯定是不会走联合索引查询的,但考虑一个问题,这条SQL中都现已运用了联合索引中的两个字段,成果还不能运用索引,这好像有点亏啊对不?因而MySQL8.x推出了跳动扫描机制,但跳动扫描并不是真实的“跳过了”第一个字段,而是优化器为你重构了SQL,比方上述这条SQL则会重构成如下状况:

SELECT * FROM `tb_xx` WHERE B = `xxx` AND C = `xxx`
UNION ALL
SELECT * FROM `tb_xx` WHERE B = `xxx` AND C = `xxx` AND A = "yyy"
......
SELECT * FROM `tb_xx` WHERE B = `xxx` AND C = `xxx` AND A = "zzz";

其实也便是MySQL优化器会自动对联合索引中的第一个字段的值去重,然后依据去重后的值悉数拼接起来查一遍,一句话来概述便是:尽管你没用第一个字段,但我给你加上去,今天这个联合索引你就得用,不必也得给我用

当然,假如熟悉Oracle数据库的小伙伴应该知道,跳动扫描机制在Oracle中早就有了,但为什么MySQL8.0版别才推出这个机制呢?还记得我们在《MySQL架构篇》中的闲谈嘛?MySQL几经转手后,终究归到了Oracle旗下,因而跳动扫描机制仅是Oracle公司:从Oracle搬到了“自己的MySQL”上罢了。

可是跳动扫描机制也有许多约束,比方多表联查时无法触发、SQL条件中有分组操作也无法触发、SQL中用了DISTINCT去重也无法触发…..,总归有许多约束条件,具体的能够参阅《MySQL官网8.0-跳动扫描》。

其实这个跳动性扫描机制,只要在唯一性较差的状况下,才干发挥出不错的效果,假如你联合索引的第一个字段,是一个值具有唯一性的字段,那去重一次再拼接,简直就等价于走一次全表。

关于索引跳动扫描机制,能够经过set @@optimizer_switch = 'skip_scan=off|on';指令来挑选敞开或封闭跳动式扫描机制。

3.5.2、躲藏索引

躲藏索引并不是一种新的索引类型,而是一种对索引的骚操作,能够了解为对每个索引新增了一个开关按键,首要用于测验环境和灰度场景,在MySQL8.0版别中,能够经过INVISIBLE、VISIBLE来操控索引的开关:

  • 当对一个索引运用INVISIBLE后,会封闭这个索引,优化器在履行SQL时无法发现和运用它。
  • 当对一个索引运用VISIBLE后,会将索引从躲藏状况康复到正常状况。

所谓的躲藏索引,便是指将一个现已创立的索引“藏起来”,被藏起来的索引是无法被优化器勘探到的,因而履行SQL句子时,就算句子中显式运用了索引字段,优化器也不会挑选走这条索引。

这个特性首要是针关于调优、测验场景而研制的,假如躲藏一个索引后,在压测场景下不会对事务产生影响,假如经过重复测验后仍旧不影响SQL功用,那这条索引则能够被判定为无用索引,能够将其删除,躲藏索引的用法如下:

-- 躲藏某张表上已存在的一个索引
alter table 表名 alter index 索引名 invisible;
-- 康复某张表上已存在的一个索引
alter table 表名 alter index 索引名 visible;

3.5.3、降序索引

Descending index降序索引是一种索引的特性,不知我们是否还记得之前界说索引的句子呢,如下:

ALTER TABLE tableName ADD INDEX indexName(columnName(length) [ASC|DESC]);

在创立索引时,能够经过ASC、DESC来界说一个索引是按升序仍是降序存储索引键,但本质上这种语法,在MySQL8.0之前,就算你手动写明了DESC降序,在创立时仍旧会默许忽略,也便是本质上仍是按升序存储索引键的,当你要对某个倒序索引的字段做倒序时,仍旧会产生filesort排序的动作。

到了MySQL8.0官方正式支撑降序索引,也便是当对一个字段树立降序索引后,做降序查询时不需求再次排序,可直接依据索引进行取值。

下面来依据MySQL5.1、MySQL8.0举个简略的比如感受一下:

-- 分别在 MySQL5.1、MySQL8.0 中创立一张 zz_table 表
create table zz_table (
  id1 int,
  id2 int,
  index idx1 (id1 ASC, id2 ASC),
  index idx2 (id1 ASC, id2 DESC),
  index idx3 (id1 DESC, id2 ASC),
  index idx4 (id1 DESC, id2 DESC)
);
insert into zz_table values(1,2);

上述创立了一张索引的测验表zz_table,其间关于两个字段树立四个索引:全升序、全降序、前降后升、前升后降,然后随便刺进了一条数据,接着来看看SQL履行状况:

-- MySQL5.1版别中的测验
explain select * from zz_table order by id1 asc, id2 desc;
+----+-------------+----------+------+-----------------------------+
| id | select_type |  table   | .... | Extra                       |
+----+-------------+----------+------+-----------------------------+
|  1 | SIMPLE      | zz_table | .... | Using index; Using filesort |
+----+-------------+----------+------+-----------------------------+
-- MySQL8.0版别中的测验
explain select * from zz_table order by id1 asc, id2 desc;
+----+-------------+----------+------------+-------+----------------------------------+
| id | select_type |  table   | partitions | ..... | Extra                            |
+----+-------------+----------+------------+-------+----------------------------------+
|  1 | SIMPLE      | zz_table | NULL       | ..... | Backward index scan; Using index |
+----+-------------+----------+------------+-------+----------------------------------+

要点调查最后一个Extra字段,在MySQL8.0之前的版别中,尽管对id2树立了倒序索引,但实践做倒序查询时仍旧会产生Using filesort排序动作,而MySQL8.0中则直接是Backward index scan反向索引扫描,并未触发排序动作。

3.5.4、函数索引

还记得在聊MySQL5.7版别时,最后贴出的其他特性嘛?其间就有一条是引进了躲藏列,完结了类似于Oracle中的函数索引,但其实功用并不健全,而在MySQL8.0中真实的支撑了函数索引,也便是依据函数去创立索引,如下:

alter table 表名 add index 索引名(函数(列名));
-- 比方:创立一个将字段值悉数转为大写后的索引
alter table t1 add index fuc_upper(upper(c1));

依据某个字段创立一个函数索引后,之后依据该字段运用函数作为查询条件时,仍旧能够走索引,如下:

select * from t1 where upper(c1) = 'ABC';

上述这条SQL句子,依照之前《索引运用篇-索引字段运用函数导致失效》中聊到的理论,理论上这条句子由于在=前面运用了函数,明显会导致索引失效,但在MySQL8.0中可创立函数索引,能够支撑条件查询时,在=号之前运用函数。

不过有一点需求紧记:运用什么函数创立的索引,也仅支撑相应函数走索引,比方上面经过了upper()函数创立了一个索引,因而upper(c1) = 'ABC'这种状况能够走索引,但运用其他函数时仍旧会导致索引失效,如:lower(c1) = 'abc'

3.6、CTE通用表表达式(Common Table Expression)

首要要搞了解这个称号,不是通用表达式,而是通用表、表达式,这个称号上有许多人都叫成通用表达式、公用表达式,这明显是不正确的,由于直接将其间的Table省去了,所以我们在这儿要紧记,正确的叫法应该是通用表表达式。

CTE通用表表达式究竟是用来干什么工作的呢?CTE是一个具有变量名的暂时成果集,也便是能够将一条查询句子的成果保存到一个变量里面,后续在其他句子中答应直接经过变量名来运用该成果集,语法如下:

with CTE称号
as (查询句子/子查询句子)
select 句子;

上述的语法是一个一般的CTE用法,一起还有另一种递归的CTE用法,先举个简略的比如来认识一下最基本的用法:

-- MySQL8.0版别之前的子查询句子
select * from t1 where xx in (select xx from t2 where yy = "zzz");
-- MySQL8.0中运用CTE表达式来代替
with cte_query as
    (select xx from t2 where yy = "zzz")
select * from t1 join cte_query on t1.xx = cte_query.xx;

调查上述比如,本来句子中需求运用in来对子查询的多个成果集做匹配,运用CTE后能够将子查询的成果集保存在cte_query变量中,后续的句子中能够将其当作成一张表,然后来做衔接查询。

其实看到这儿,CTE表达式是不是有些类似于暂时表的概念?但它会比暂时表更轻,查询更快。

除开最基本的表达式外,还有一种名为递归CTE表达式的概念,它是一种递归算法的完结,能够重复履行一段SQL,比方当你要查询标签表中,某个尖端标签下悉数的子标签时,它的下级或许也存在其它字标签…..,或许一个尖端标签下面有十八层子标签,这时经过传统的查询句子就无法很好完结,而运用递归的CTE表达式就很简略啦。

递归CTE表达式只需求运用with recursive关键字即可,不过这儿我不贴具体完结啦,我们感兴趣的可自行研讨了解CTE后再完结该需求。

CTE表达式除开能够与select句子嵌套外,还能够与其它类型的句子嵌套,例如:with delete、with update、with recursive、with with、insert with等,我们感兴趣的也可自行研讨,总归CTE在许多状况下的确比较实用~

3.7、窗口函数(Window Function)

窗口函数可谓是MySQL8.0中最大的亮点之一,但在测验去学习时会发现很难了解,先来看看窗口函数的界说。

窗口函数是一种剖析型的OLAP函数,因而也被称之为剖析函数,它能够了解成是数据的调集,类似于group by分组的功用,但之前的MySQL版别依据某个字段分组后,会将数据紧缩到一行显现,如下:

select * from `zz_users`;
+---------+-----------+----------+----------+---------------------+
| user_id | user_name | user_sex | password | register_time       |
+---------+-----------+----------+----------+---------------------+
|       1 | 熊猫      || 6666     | 2022-08-14 15:22:01 |
|       2 | 竹子      || 1234     | 2022-09-14 16:17:44 |
|       3 | 子竹      || 4321     | 2022-09-16 07:42:21 |
|       4 | 猫熊      || 8888     | 2022-09-17 23:48:29 |
+---------+-----------+----------+----------+---------------------+
select user_id from zz_users group by user_sex;
+-----------+
| user_id   |
+-----------+
|       1,4 |
|       2,3 |
+-----------+

而窗口函数则不会将数据紧缩成一行,也便是表中数据本来是多少行,分组完结后仍旧是多少行,窗口函数的语法如下:

[window 窗口函数名 as (window_spec) [, 窗口函数名 AS (window_spec)] ...]
窗口函数名(窗口名/表达式) 
over (
    [partition_defintion]
    [order_definition]
    [frame_definition]
)

其实这个语法看起来不是特别能让人了解,所以结合具体的场景来举例,语法如下:

窗口函数 over([partition by 字段名 order by 字段名 asc|desc])
窗口函数 over 窗口名 ... window 窗口名 
as ([partition by 字段名 order by 字段名 asc|desc])

一眼看下来,成果仍是令人不了解,对吗?这先别急,看不懂也没联系,后面会举例说明,先来看看MySQL8.0中供给了哪些窗口函数呢?如下:

  • 序号函数:
    • row_number():按序排列,相同的值序号会往后推,如88、88、89排序为1、2、3
    • rank():并列排序,相同的值序号会跳过,如88、88、89排序为1、1、3
    • dense_rank():并列排序,相同的值序号不会跳过,如88、88、89排序为1、1、2
  • 散布函数:
    • percent_rank():计算当时行数据的某个字段值占窗口内某个字段悉数值的百分比。
    • cume_dist(): 小于等于当时字段值的行数与整个分组内悉数行数据的占比。
  • 前后函数:
    • lag(expr,n):回来分组中的前n条契合expr条件的数据。
    • lead(expr,n):回来分组中的后n条契合expr条件的数据。
  • 首尾函数:
    • first_value(expr):回来分组中的第一条契合expr条件的数据。
    • last_value(expr):回来分组中的最后一条契合expr条件的数据。
  • 其它函数:
    • nth_value(expr,n):回来分组中的第n条契合expr条件的数据。
    • ntile(n):将一个分组中的数据再分成n个小组,并记载每个小组编号。

这样看过去好像也有些令人模糊,究竟之前对窗口函数则这块接触比较少,因而下面来举个简略的比如切身感受一下(仍是以之前的用户表为例),需求如下:

  • 按性别分组,并依照ID值从大到小对各分组中的数据进行排序,最后输出。

这需求一听就知道一条SQL肯定搞不定,在之前版别中需求创立暂时表来完结,凭借暂时表来拆成多步完结,而在MySQL8.0中则能够凭借窗口函数轻松完结,如下:

select
    -- 运用 row_number() 序号窗口函数
    row_number() over(
        -- 依据性别做分组,然后依据 ID 做倒序
        partition by user_sex order by user_id desc
    ) as  serial_num,
    user_id, user_name, user_sex, password, register_time
from
    zz_users;
+------------+---------+-----------+----------+----------+---------------------+
| serial_num | user_id | user_name | user_sex | password | register_time       |
+------------+---------+-----------+----------+----------+---------------------+
| 1          |       4 | 猫熊      || 8888     | 2022-09-17 23:48:29 |
| 2          |       1 | 熊猫      || 6666     | 2022-08-14 15:22:01 |
| 1          |       3 | 子竹      || 4321     | 2022-09-16 07:42:21 |
| 2          |       2 | 竹子      || 1234     | 2022-09-14 16:17:44 |
+------------+---------+-----------+----------+----------+---------------------+

上述这条SQL便是依据序号窗口函数的完结,其实发现会尤为简略,调查履行成果也会发现,运用窗口函数分组后,并不会将数据紧缩到一行,而是将同一分组的数据在成果会集相邻显现。

上面的比如中就演示了最为简略的窗口函数用法:函数名() over(数据处理),但实践状况中能够灵敏的依据需求变化,但如若想要很好的运用窗口函数,那还需求我们多加以操练,关于这块我们可参阅《MySQL官网-窗口函数示例》、或《宋红康教师的视频教育》。

3.8、MySQL8.0中的其他特性

在前面的内容中,就现已将MySQL8.0中较为重要的改动和特性做了具体论述,但MySQL8.0全体的改动也比较大,因而这儿再列出一些其它方面的特性,如下:

  • 将默许的UTF-8编码格局从latin替换成了utf8mb4,后者包括了悉数emoji表情包字符。
  • 增强NoSQL存储功用,优化了5.6版别引进的NoSQL技能,并完善了对JSON的支撑性。
  • InnoDB引擎再次增强,对自增、索引、加密、死锁、同享锁等方面做了许多改善与优化。
  • 支撑界说原子DDL句子,即当需求对库表结构产生改动时,改动操作可界说为原子性操作。
  • 支撑正则检索,新增REGEXP_LIKE()、EGEXP_INSTR()、REGEXP_REPLACE()、REGEXP_SUBSTR()等函数供给支撑。
  • 优化暂时表,暂时表默许引擎从Memory替换为TempTable引擎,资源开支少,功用更强。
  • 锁机制增强,除开前面聊到的锁特性改动外,新引进了一种备份锁,获取/开释锁语法如下:
    • 获取锁:LOCK INSTANCE FOR BACKUP、开释锁:UNLOCK INSTANCE
  • Bin-log日志增强,过期时刻准确到秒,使用zstd算法增强了日志事务的紧缩功用。
  • 安全性进步,认证加密插件更新、暗码战略改善、新增人物功用、日志文件支撑加密等。
  • 引进资源组的概念,支撑按事务优先级来操控作业线程的CPU资源抢占几率。

.......:更多请参阅《MySQL官网-8.0版手册》。

四、MySQL特性篇总结

在这章中我们介绍了MySQL几个重要的里程碑版别,明显每个版别中都对前版别中做了不小的优化,尤其是MySQL8.0中的新特性和新优化点非常具有吸引力。但线上环境已有数据的状况下,也不适合再做搬迁,究竟数据搬迁是一件非常麻烦的工作,有时候乃至比你重构一个Java项目更累,因而假如你的数据库版别现在足以支撑体系的正常工作,那就没有必要去做版别搬迁。

但如若你的项目数据库现已抵达瓶颈,而且晋级数据库版别着实能够处理现在的困扰,这种状况下则能够测验晋级数据库版别,将旧版别的数据搬迁到新版别的数据库中,但这类作业在有专业人士负责的状况下,最好不要自己去插手,究竟一些企业中会有专门的DBA方向。

最后,在本章节中也仅介绍了一些较为重要的新特性和优化项,但MySQL每个版别中都有一些修修补补的小特性、小改善,这儿就不打开叙说了,我们感兴趣的可直接翻阅MySQL官网供给的手册,以此来具体得知各个版别中的细节改善。