不可不知的 MySQL 升级利器及 5.7 升级到 8.0 的注意事项

数据库升级是一项苦乐参半的工程。好消息是,通过升级,你可以享受到新版本带来的新功能和性能提升。令人担忧的是,新版本可能与旧版本不兼容,这主要体现在以下三个方面:

[En]

Database upgrade is a bittersweet project. The good news is that through the upgrade, you can enjoy the new features and performance improvements brought by the new version. The worry is that the new version may not be compatible with the old version, which is mainly reflected in the following three aspects:

因此,在升级在线数据库之前,通常会在测试环境中进行大量测试,包括功能测试和性能测试。

[En]

Therefore, before upgrading the online database, a large number of tests are generally carried out in the test environment, including functional testing and performance testing.

很多人可能会觉得麻烦,所以对升级抱着一种不主动、也拒绝的态度,新版本怎么会有更好的性能、更多的新功能,而老版本在产品维护周期结束后也存在安全隐患。

[En]

Many people may find it troublesome, so they take a “do not take the initiative, also refuse” attitude towards the upgrade, how can the new version have better performance and more new features, and the old version also has security risks after the end of the product maintenance cycle.

升还是不升呢?that is a question。

下面我们介绍一个 MySQL 升级利器,可极大减轻 DBA 包括开发童鞋在升级数据库时的心智负担和工作负担。

这个利器就是 pt-upgrade。

pt-upgrade 是 Percona Toolkit 中的一个工具,可帮忙我们从业务 SQL 层面检查新老版本的兼容性。

它的检测思路很简单,给定一个 SQL,分别在两个不同版本的实例上执行,看看是否一致。

具体地说,它检查以下内容:

[En]

Specifically, it examines the following:

  • Row count:查询返回的行数是否一致。
  • Row data:查询的结果是否一致。
  • Warnings:是否提示 warning。正常来说,要么都提示 warning,要么都不提示 warning。
  • Query time:查询时间是否在同一个量级,或者新版本的执行时间是否更短。
  • Query errors:查询如果在一个实例中出现语法错误,会提示 Query errors。
  • SQL errors:查询如果在两个实例中同时出现语法错误,会提示 SQL errors。

pt-upgrade 的使用比较简单,只需提供两个实例的 DSN (实例连接信息)和文件名。

常见用法有以下两种:

(1)直接比较一个文件中的 SQL 在两个实例中的执行效果。

# pt-upgrade h=host1 h=host2 slow.log

可通过 –type 指定文件的类型,支持 slowlog(慢日志),genlog(General Log),binlog(通过 mysqlbinlog 解析后的文本文件),rawlog( SQL语句 ),tcpdump。不指定,则默认是慢日志。

(2)先生成一个基准测试结果,然后再基于这个结果测试其它环境的兼容性。

#&#xA0;pt-upgrade&#xA0;h=host1&#xA0;--save-results&#xA0;host1_results/&#xA0;slow.log<br>#&#xA0;pt-upgrade&#xA0;host1_results1/&#xA0;h=host2

第二种情况适用于无法同时访问两个实例,或者需要根据基准测试结果进行多个测试的情况。

[En]

The second usage applies when two instances cannot be accessed at the same time, or multiple tests are required based on a benchmark result.

看下面这个 Demo。

pt_upgrade_test.sql 包含了若干条测试语句。

#&#xA0;cat&#xA0;/tmp/pt_upgrade_test.sql<br>select&#xA0;"a&#xA0;word&#xA0;a"&#xA0;REGEXP&#xA0;"[[:<:]]word[[:>:]]";<br>select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;desc;<br>grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;'u1'@'%'&#xA0;identified&#xA0;by&#xA0;'123456';<br>create&#xA0;table&#xA0;employees.t1(id&#xA0;int&#xA0;primary&#xA0;key,c1&#xA0;text&#xA0;not&#xA0;null&#xA0;default&#xA0;(''));&#xA0;<br>select&#xA0;*&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no;<br></:]]word[[:>

这里给出的几条测试语句都极具代表性,都是升级过程中需要注意的 SQL。

下面我们看看这些语句在 MySQL 5.7 和 MySQL 8.0 中的执行情况。

#&#xA0;pt-upgrade&#xA0;h=127.0.0.1,P=3307,u=pt_user,p=pt_pass&#xA0;h=127.0.0.1,P=3306,u=pt_user,p=pt_pass&#xA0;--type&#xA0;rawlog&#xA0;/tmp/pt_upgrade_test.sql&#xA0;--no-read-only<br><br>#-----------------------------------------------------------------------<br>#&#xA0;Logs<br>#-----------------------------------------------------------------------<br><br>File:&#xA0;/tmp/pt_upgrade_test.sql<br>Size:&#xA0;311<br><br>#-----------------------------------------------------------------------<br>#&#xA0;Hosts<br>#-----------------------------------------------------------------------<br><br>host1:<br><br>&#xA0;&#xA0;DSN:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;h=127.0.0.1,P=3307<br>&#xA0;&#xA0;hostname:&#xA0;&#xA0;slowtech<br>&#xA0;&#xA0;MySQL:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MySQL&#xA0;Community&#xA0;Server&#xA0;(GPL)&#xA0;5.7.36<br><br>host2:<br><br>&#xA0;&#xA0;DSN:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;h=127.0.0.1,P=3306<br>&#xA0;&#xA0;hostname:&#xA0;&#xA0;slowtech<br>&#xA0;&#xA0;MySQL:&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;MySQL&#xA0;Community&#xA0;Server&#xA0;-&#xA0;GPL&#xA0;8.0.27<br><br>########################################################################<br>#&#xA0;Query&#xA0;class&#xA0;00A13DD81BF65D41<br>########################################################################<br><br>Reporting&#xA0;class&#xA0;because&#xA0;it&#xA0;has&#xA0;diffs,&#xA0;but&#xA0;hasn't&#xA0;been&#xA0;reported&#xA0;yet.<br><br>Total&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Unique&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Discarded&#xA0;queries&#xA0;&#xA0;0<br><br>grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;?@?&#xA0;identified&#xA0;by&#xA0;?;<br><br>##<br>##&#xA0;Query&#xA0;errors&#xA0;diffs:&#xA0;1<br>##<br><br>--&#xA0;1.<br><br>No&#xA0;error<br><br>vs.<br><br>DBD::mysql::st&#xA0;execute&#xA0;failed:&#xA0;You&#xA0;have&#xA0;an&#xA0;error&#xA0;in&#xA0;your&#xA0;SQL&#xA0;syntax;&#xA0;check&#xA0;the&#xA0;manual&#xA0;that&#xA0;corresponds&#xA0;to&#xA0;your&#xA0;MySQL&#xA0;server&#xA0;version&#xA0;for&#xA0;the&#xA0;right&#xA0;syntax&#xA0;to&#xA0;use&#xA0;near&#xA0;'identified&#xA0;by&#xA0;'123456''&#xA0;at&#xA0;line&#xA0;1&#xA0;[for&#xA0;Statement&#xA0;"grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;'u1'@'%'&#xA0;identified&#xA0;by&#xA0;'123456';"]<br><br>grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;'u1'@'%'&#xA0;identified&#xA0;by&#xA0;'123456';<br><br>########################################################################<br>#&#xA0;Query&#xA0;class&#xA0;296E46FE3AEE9B6C<br>########################################################################<br><br>Reporting&#xA0;class&#xA0;because&#xA0;it&#xA0;has&#xA0;SQL&#xA0;errors,&#xA0;but&#xA0;hasn't&#xA0;been&#xA0;reported&#xA0;yet.<br><br>Total&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Unique&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Discarded&#xA0;queries&#xA0;&#xA0;0<br><br>select&#xA0;*&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no;<br><br>##<br>##&#xA0;SQL&#xA0;errors:&#xA0;1<br>##<br><br>--&#xA0;1.<br><br>On&#xA0;both&#xA0;hosts:<br><br>DBD::mysql::st&#xA0;execute&#xA0;failed:&#xA0;Expression&#xA0;#1&#xA0;of&#xA0;SELECT&#xA0;list&#xA0;is&#xA0;not&#xA0;in&#xA0;GROUP&#xA0;BY&#xA0;clause&#xA0;and&#xA0;contains&#xA0;nonaggregated&#xA0;column&#xA0;'employees.dept_emp.emp_no'&#xA0;which&#xA0;is&#xA0;not&#xA0;functionally&#xA0;dependent&#xA0;on&#xA0;columns&#xA0;in&#xA0;GROUP&#xA0;BY&#xA0;clause;&#xA0;this&#xA0;is&#xA0;incompatible&#xA0;with&#xA0;sql_mode=only_full_group_by&#xA0;[for&#xA0;Statement&#xA0;"select&#xA0;*&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no;"]<br><br>select&#xA0;*&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no;<br><br>########################################################################<br>#&#xA0;Query&#xA0;class&#xA0;8B81ACF1E68DE066<br>########################################################################<br><br>Reporting&#xA0;class&#xA0;because&#xA0;it&#xA0;has&#xA0;diffs,&#xA0;but&#xA0;hasn't&#xA0;been&#xA0;reported&#xA0;yet.<br><br>Total&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Unique&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Discarded&#xA0;queries&#xA0;&#xA0;0<br><br>create&#xA0;table&#xA0;employees.t?(id&#xA0;int&#xA0;primary&#xA0;key,c?&#xA0;text&#xA0;not&#xA0;?&#xA0;default&#xA0;(?));<br><br>##<br>##&#xA0;Query&#xA0;errors&#xA0;diffs:&#xA0;1<br>##<br><br>--&#xA0;1.<br><br>DBD::mysql::st&#xA0;execute&#xA0;failed:&#xA0;You&#xA0;have&#xA0;an&#xA0;error&#xA0;in&#xA0;your&#xA0;SQL&#xA0;syntax;&#xA0;check&#xA0;the&#xA0;manual&#xA0;that&#xA0;corresponds&#xA0;to&#xA0;your&#xA0;MySQL&#xA0;server&#xA0;version&#xA0;for&#xA0;the&#xA0;right&#xA0;syntax&#xA0;to&#xA0;use&#xA0;near&#xA0;'(''))'&#xA0;at&#xA0;line&#xA0;1&#xA0;[for&#xA0;Statement&#xA0;"create&#xA0;table&#xA0;employees.t1(id&#xA0;int&#xA0;primary&#xA0;key,c1&#xA0;text&#xA0;not&#xA0;null&#xA0;default&#xA0;(''));&#xA0;"]<br><br>vs.<br><br>No&#xA0;error<br><br>create&#xA0;table&#xA0;employees.t1(id&#xA0;int&#xA0;primary&#xA0;key,c1&#xA0;text&#xA0;not&#xA0;null&#xA0;default&#xA0;(''));<br><br>########################################################################<br>#&#xA0;Query&#xA0;class&#xA0;92E8E91AB47593A5<br>########################################################################<br><br>Reporting&#xA0;class&#xA0;because&#xA0;it&#xA0;has&#xA0;diffs,&#xA0;but&#xA0;hasn't&#xA0;been&#xA0;reported&#xA0;yet.<br><br>Total&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Unique&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Discarded&#xA0;queries&#xA0;&#xA0;0<br><br>select&#xA0;?&#xA0;regexp&#xA0;?;<br><br>##<br>##&#xA0;Query&#xA0;errors&#xA0;diffs:&#xA0;1<br>##<br><br>--&#xA0;1.<br><br>No&#xA0;error<br><br>vs.<br><br>DBD::mysql::st&#xA0;execute&#xA0;failed:&#xA0;Illegal&#xA0;argument&#xA0;to&#xA0;a&#xA0;regular&#xA0;expression.&#xA0;[for&#xA0;Statement&#xA0;"select&#xA0;"a&#xA0;word&#xA0;a"&#xA0;REGEXP&#xA0;"[[:<:]]word[[:>:]]";"]<br><br>select&#xA0;"a&#xA0;word&#xA0;a"&#xA0;REGEXP&#xA0;"[[:<:]]word[[:>:]]";<br><br>########################################################################<br>#&#xA0;Query&#xA0;class&#xA0;D3F390B1B46CF9EA<br>########################################################################<br><br>Reporting&#xA0;class&#xA0;because&#xA0;it&#xA0;has&#xA0;diffs,&#xA0;but&#xA0;hasn't&#xA0;been&#xA0;reported&#xA0;yet.<br><br>Total&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Unique&#xA0;queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>Discarded&#xA0;queries&#xA0;&#xA0;0<br><br>select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;desc;<br><br>##<br>##&#xA0;Query&#xA0;errors&#xA0;diffs:&#xA0;1<br>##<br><br>--&#xA0;1.<br><br>No&#xA0;error<br><br>vs.<br><br>DBD::mysql::st&#xA0;execute&#xA0;failed:&#xA0;You&#xA0;have&#xA0;an&#xA0;error&#xA0;in&#xA0;your&#xA0;SQL&#xA0;syntax;&#xA0;check&#xA0;the&#xA0;manual&#xA0;that&#xA0;corresponds&#xA0;to&#xA0;your&#xA0;MySQL&#xA0;server&#xA0;version&#xA0;for&#xA0;the&#xA0;right&#xA0;syntax&#xA0;to&#xA0;use&#xA0;near&#xA0;'desc'&#xA0;at&#xA0;line&#xA0;1&#xA0;[for&#xA0;Statement&#xA0;"select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;desc;"]<br><br>select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;desc;<br><br>#-----------------------------------------------------------------------<br>#&#xA0;Stats<br>#-----------------------------------------------------------------------<br><br>failed_queries&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1<br>not_select&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>queries_filtered&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>queries_no_diffs&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0<br>queries_read&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;5<br>queries_with_diffs&#xA0;&#xA0;&#xA0;&#xA0;0<br>queries_with_errors&#xA0;&#xA0;&#xA0;4<br></:]]word[[:></:]]word[[:>

3307,3306 端口分别对应 MySQL 5.7、MySQL 8.0 实例。

对于文件中的每一个 SQL ,都会在这两个实例中执行。如果每个差异 SQL 的结果都打印出来的话,最后的输出将十分庞杂。为了简化最后的输出结果,pt-upgrade 会对 SQL 进行分类,同一类 SQL 的输出次数受到 –max-class-size 和 –max-examples 的限制。

结合执行的 SQL,我们分析下输出结果。

SQL 3

grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;'u1'@'%'&#xA0;identified&#xA0;by&#xA0;'123456';

在 MySQL 8.0 之前,对一个用户进行授权(grant)操作,如果该用户不存在,会隐式创建。而在 MySQL 8.0 中,该命令会直接报错,必须先创建用户,再授权。

所以,上面这条 SQL 需拆分为以下两条 SQL 来执行。

create&#xA0;user&#xA0;'u1'@'%'&#xA0;identified&#xA0;by&#xA0;'123456';<br>grant&#xA0;select&#xA0;on&#xA0;employees.*&#xA0;to&#xA0;'u1'@'%';

这个查询只在一个实例中出现语法错误,所以 pt-upgrade 会将其归类为 Query errors 。

SQL 5

select&#xA0;*&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no;

从 MySQL 5.7 开始,SQL_MODE 的默认值发生了变化,包含了 ONLY_FULL_GROUP_BY 。

ONLY_FULL_GROUP_BY 要求,对于 GROUP BY 操作,SELECT 列表中只能出现分组列(即 GROUP BY 后面的列)和聚合函数( SUM,AVG,MAX等 ),不允许出现其它非分组列。

很明显,上面这条 SQL 违背了这一要求。所以,无论是在 MySQL 5.7 还是 8.0 中,该 SQL 都会报错。

这个查询在两个实例中都出现了语法错误,所以 pt-upgrade 会将其归类为 SQL errors 。

SQL 4

create&#xA0;table&#xA0;employees.t1(id&#xA0;int&#xA0;primary&#xA0;key,c1&#xA0;text&#xA0;not&#xA0;null&#xA0;default&#xA0;(''));

从 MySQL 8.0.13 开始,允许对 BLOB,TEXT,GEOMETRY 和 JSON 字段设置默认值。之前版本,则不允许。

SQL 1

select&#xA0;"a&#xA0;word&#xA0;a"&#xA0;REGEXP&#xA0;"[[:<:]]word[[:>:]]";<br></:]]word[[:>

在 MySQL 8.0 中,正则表达式底层库由 Henry Spencer 调整为了 International Components for Unicode (ICU)。

在 Henry Spencer 库中,[[:

select&#xA0;"a&#xA0;word&#xA0;a"&#xA0;REGEXP&#xA0;"\\bword\\b";

SQL 2

select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;desc;

在 MySQL 8.0 之前,如果我们要对分组后的结果进行排序,可使用 GROUP BY col_name ASC/DESC ,没有指定排序列,默认是对分组列进行排序。

在 MySQL 8.0 中,不再支持这一语法,如果要进行排序,需显式指定排序列。所以,对于上面这个 SQL,在 MySQL 8.0 中的写法如下。

select&#xA0;dept_no,count(*)&#xA0;from&#xA0;employees.dept_emp&#xA0;group&#xA0;by&#xA0;dept_no&#xA0;order&#xA0;by&#xA0;dept_no&#xA0;desc;

–[no]read-only

默认情况下,pt-upgrade 只会执行 SELECT 和 SET 操作。如果要执行其它操作,必须指定 –no-read-only。

–[no]create-upgrade-table,–upgrade-table

默认情况下,pt-upgrade 会在目标实例上创建一张 percona_schema.pt_upgrade 表(由 –upgrade-table 参数指定),每执行完一个 SQL,都会执行一次 SELECT * FROM percona_schema.pt_upgrade LIMIT 1 以清除上一个 SQL 有可能出现的 warning 。

–max-class-size,–max-examples

pt-upgrade 会对 SQL 进行分类,这两个参数可用来限制同一类 SQL 输出的数量。其中,–max-class-size 用来限制不重复 SQL 的数量,默认是 1000。–max-examples 用来限制 SQL 的数量,包括重复 SQL,默认是 3。

pt-upgrade 基于什么对 SQL 进行分类呢?fingerprint。

fingerprint 这个术语,我们在很多工具中都会看到,如 ProxySQL,pt-query-digest,可理解为基于某些规则,提取 SQL 的一般形式,类似于 JDBC 中的 PreparedStatement 。

譬如下面这几条 SQL,就可归为同一类 select c? from d?t? where id=?

select&#xA0;c1&#xA0;from&#xA0;db1.t1&#xA0;where&#xA0;id=1;<br>select&#xA0;c1&#xA0;from&#xA0;db1.t1&#xA0;where&#xA0;id=1;<br>select&#xA0;c1&#xA0;from&#xA0;db1.t1&#xA0;where&#xA0;id=2;<br>select&#xA0;c2&#xA0;from&#xA0;db1.t1&#xA0;where&#xA0;id=3;<br>select&#xA0;c3&#xA0;from&#xA0;db1.t2&#xA0;where&#xA0;id=4;<br>select&#xA0;c4&#xA0;from&#xA0;db2.t3&#xA0;where&#xA0;id=5;<br>select&#xA0;c5&#xA0;from&#xA0;db2.t4&#xA0;where&#xA0;id=6;

Percona Toolkit 中的提取规则如下:

–save-results

将查询结果保存到目录。

[En]

Save the query results to the directory.

#&#xA0;pt-upgrade&#xA0;h=127.0.0.1,P=3307,u=pt_user,p=pt_pass&#xA0;--save-results&#xA0;/tmp/pt_upgrade_result&#xA0;--type&#xA0;rawlog&#xA0;/tmp/pt_upgrade_test.sql&#xA0;--no-read-only&#xA0;<br>#&#xA0;pt-upgrade&#xA0;/tmp/pt_upgrade_result/&#xA0;h=127.0.0.1,P=3306,u=pt_user,p=pt_pass

在执行 pt-upgrade 之前,必须确保两个实例中的数据完全一致,且不会发生变更,否则会产生误判。

基于此,pt-upgrade 更适合在测试环境或开发环境使用,不建议在生产环境上使用。

MySQL 5.7 升级到 MySQL 8.0,目前已知的,需要注意的点主要有以下两个:

一、不再支持 GROUP BY col_name ASC/DESC。如果要排序,需显式指定排序列。

二、MySQL 8.0 的正则表达式底层库由 Henry Spencer 调整为了 International Components for Unicode (ICU),Spencer 库的部分语法不再支持。具体来说:

  1. Spencer 库是以字节方式工作的,不是多字节安全的,在碰到多字节字符时有可能不会得到预期效果。而 ICU 支持完整的 Unicode 并且是多字节安全的。
mysql&#xA0;5.7>&#xA0;select&#xA0;'&#x10D;'&#xA0;regexp&#xA0;'^.$';<br>+-------------------+<br>|&#xA0;'&#x10D;'&#xA0;regexp&#xA0;'^.$'&#xA0;&#xA0;|<br>+-------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+-------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;'&#x10D;'&#xA0;regexp&#xA0;'^.$';<br>+-------------------+<br>|&#xA0;'&#x10D;'&#xA0;regexp&#xA0;'^.$'&#xA0;&#xA0;|<br>+-------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+-------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)
  1. 在 Spencer 库中, .可用来匹配任何字符,包括回车符(\r)和换行符(\n)。而在 ICU 中, . 默认不会匹配回车符和换行符。如果要匹配,需指定正则修饰符 n
mysql&#xA0;5.7>&#xA0;select&#xA0;'new\nline'&#xA0;regexp&#xA0;'new.line';<br>+-------------------------------+<br>|&#xA0;'new\nline'&#xA0;regexp&#xA0;'new.line'&#xA0;|<br>+-------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+-------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;'new\nline'&#xA0;regexp&#xA0;'new.line';<br>+-------------------------------+<br>|&#xA0;'new\nline'&#xA0;regexp&#xA0;'new.line'&#xA0;|<br>+-------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+-------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;regexp_like('new\nline','new.line','n');<br>+-----------------------------------------+<br>|&#xA0;regexp_like('new\nline','new.line','n')&#xA0;|<br>+-----------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+-----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)
  1. Spencer 库支持通过 [[:
mysql&#xA0;5.7>&#xA0;select&#xA0;'a&#xA0;word&#xA0;a'&#xA0;regexp&#xA0;'[[:<:]]word[[:>:]]';<br>+----------------------------------------+<br>|&#xA0;'a&#xA0;word&#xA0;a'&#xA0;regexp&#xA0;'[[:<:]]word[[:>:]]'&#xA0;|<br>+----------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;'a&#xA0;word&#xA0;a'&#xA0;regexp&#xA0;'[[:<:]]word[[:>:]]';<br>ERROR&#xA0;3685&#xA0;(HY000):&#xA0;Illegal&#xA0;argument&#xA0;to&#xA0;a&#xA0;regular&#xA0;expression.<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;'a&#xA0;word&#xA0;a'&#xA0;regexp&#xA0;'\\bword\\b';<br>+--------------------------------+<br>|&#xA0;'a&#xA0;word&#xA0;a'&#xA0;regexp&#xA0;'\\bword\\b'&#xA0;|<br>+--------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+--------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br></:]]word[[:></:]]word[[:></:]]word[[:>
  1. Spencer 库支持 [.characters.],这里的 characters 既可以是字符,又可以是字符名称,譬如字符 : 对应的字符名称是 colon 。 ICU 中不支持字符名称。
mysql&#xA0;5.7>&#xA0;select&#xA0;':'&#xA0;regexp&#xA0;'[[.:.]]';<br>+----------------------+<br>|&#xA0;':'&#xA0;regexp&#xA0;'[[.:.]]'&#xA0;|<br>+----------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;5.7>&#xA0;select&#xA0;':'&#xA0;regexp&#xA0;'[[.colon.]]';<br>+--------------------------+<br>|&#xA0;':'&#xA0;regexp&#xA0;'[[.colon.]]'&#xA0;|<br>+--------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+--------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.01&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;':'&#xA0;regexp&#xA0;'[[.:.]]';<br>+----------------------+<br>|&#xA0;':'&#xA0;regexp&#xA0;'[[.:.]]'&#xA0;|<br>+----------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;':'&#xA0;regexp&#xA0;'[[.colon.]]';<br>+--------------------------+<br>|&#xA0;':'&#xA0;regexp&#xA0;'[[.colon.]]'&#xA0;|<br>+--------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+--------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)
  1. ICU 中如果要匹配右括号 ) ,需使用转义符。
mysql&#xA0;5.7>&#xA0;select&#xA0;')'&#xA0;regexp&#xA0;(')');<br>+------------------+<br>|&#xA0;')'&#xA0;regexp&#xA0;(')')&#xA0;|<br>+------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;')'&#xA0;regexp&#xA0;(')');<br>ERROR&#xA0;3691&#xA0;(HY000):&#xA0;Mismatched&#xA0;parenthesis&#xA0;in&#xA0;regular&#xA0;expression.<br><br>mysql&#xA0;8.0>&#xA0;select&#xA0;')'&#xA0;regexp&#xA0;('\\)');<br>+--------------------+<br>|&#xA0;')'&#xA0;regexp&#xA0;('\\)')&#xA0;|<br>+--------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+--------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

相信有了 pt-upgrade 的加持,后续我们再进行数据库升级时心里会有底很多。

MySQL 8.0 虽然引入了很多新特性,但升级时需要注意的点其实也不多。

除了上面提到的两点外,如果发现其他需要注意的地方,也会及时更新到留言中。欢迎您继续关注我们。

[En]

In addition to the two points mentioned above, if you find other points that need to be paid attention to later, they will also be updated to the message in time. You are welcome to follow us continuously.

除了 pt-upgrade,另外一个推荐的数据库升级工具是 MySQL Shell 中的 util.checkForServerUpgrade()。

与 pt-upgrade 不一样的是,util.checkForServerUpgrade() 更多的是从实例的基础数据本身来判定实例是否满足升级条件,譬如是否使用了移除的函数、表名是否存在冲突等,一共有 21 个检查项,这个工具我们后面也会介绍,敬请期待。

Original: https://www.cnblogs.com/ivictor/p/16275919.html
Author: iVictor
Title: 不可不知的 MySQL 升级利器及 5.7 升级到 8.0 的注意事项

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/505377/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 日志:Redo Log 和 Undo Log

    本篇文章主要介绍 Redo Log 和 Undo Log: 利用 Redo Log 和 Undo Log 实现本地事务的原子性、持久性 Redo Log 的写回策略 Redo Lo…

    数据库 2023年6月11日
    082
  • 名言小抄(六)

    1.一个人对世界最大的贡献就是让自己快乐起来。 4.人生最好的三个词 久别重逢、失而复得、虚惊一场却没有,和好如初 ,只因和好容易,如初太难。很多东西,一旦打破,就很难圆满。有些故…

    数据库 2023年6月16日
    081
  • 强大博客搭建全过程(1)-hexo博客搭建保姆级教程

    1、 前言 本人本来使用国内的开源项目solo搭建了博客,但感觉1核CPU2G内存的服务器,还是稍微有点重,包括服务器内还搭建了数据库。如果自己开发然后搭建,耗费时间又比较多,于是…

    数据库 2023年6月16日
    0115
  • [Mysql]root密码忘了怎样重新设置密码

    环境 Ubuntu 20.04 LTSMysql 8.0+ 停止mysql服务 service mysql stop 修改 my.cnf 文件 vim /etc/mysql/my….

    数据库 2023年6月16日
    073
  • Shell 第二章《流控》

    前言 无论什么编程语言都离不开条件判断(流控)。SHELL也不例外。例如,用户输入的密码不够长时提示用户,你太短了例如,用户输入了备份的目录,如果有目录继续备份,如果没有目录创建目…

    数据库 2023年6月14日
    0102
  • Java面试题(九)–Spring MVC

    1、Spring MVC中的拦截器和Servlet中的filter有什么区别? 过滤器:依赖于servlet容器,在实现上基于函数回调,可以对几乎所有请求进行过滤 拦截器:依赖于w…

    数据库 2023年6月16日
    078
  • form表单内容序列化的两种方法

    form表单内容序列化 form表单自带两种方法serialize()方法和serializeArray()方法 1.serialize()方法 &#x63CF;&…

    数据库 2023年6月14日
    085
  • Javaweb06-JDBC

    1、jdbc.properties配置文件 jdbc.properties driverClass=com.mysql.jdbc.Driver jdbcUrl=jdbc:mysql…

    数据库 2023年6月16日
    086
  • 【数据库】– MySQL中比like更高效的三个写法

    一般在项目中我们进行模糊查询常见使用like ‘%findStr%’进行,但是在字段中进行模糊匹配及contains类查询还有下面三种写法: SELECT …

    数据库 2023年6月6日
    097
  • Golang context

    Context Go 语言中提供了 context 包,通过显示传递 context, 实现请求级别的元数据、取消信号、终止信号的传递。context 包提供了从现有的上下文值(c…

    数据库 2023年6月16日
    089
  • 0812Java核心技术卷(1)随笔

    自增运算符与自减运算符 这些运算符改变了变量的值,所以它的操作数不能是数值。例如4++就是一条非法语句不建议在其他表达式内部使用++,因为这样会降低代码可读性,产生bug Orig…

    数据库 2023年6月14日
    0102
  • javaWeb知识点大集合!!!

    pom文件: 4.0.0 org.example javaweb_maven 1.0-SNAPSHOT war UTF-8 1.7 1.7 com.github.pagehelpe…

    数据库 2023年6月16日
    086
  • 编程相关书单

    软工概论软件工程软件工程:实践者的研究方法 职业素养软技能码农翻身技术之瞳程序员修炼之道程序员的职业素养程序员的自我修养 程序设计计算机程序的构造和解释 (SICP) UML软件建…

    数据库 2023年6月11日
    080
  • 避坑!SimpleDateFormat不光线程不安全,还有这个隐患

    众所周知,SimpleDateFormat是多线程不安全的 下面这段代码通过多线程使用同一个SimpleDateFormat对象的parse方法, 多次执行代码来测试,可以看到会出…

    数据库 2023年6月9日
    0103
  • Nginx 简介、安装、核心配置

    Nginx简介 背景介绍 Nginx(”engine x”)一个具有高性能的【HTTP】和【反向代理】的【WEB服务器】,同时也是一个【POP3/SMTP/…

    数据库 2023年6月6日
    0104
  • Python第二十二天 stat模块 os.chmod方法 os.stat方法 pwd grp模块 os.access()方法

    Python第二十二天 stat模块 os.chmod方法 os.stat方法 pwd grp模块 os.access()方法 stat模块描述了os.stat(filename)…

    数据库 2023年6月9日
    070
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球