2.11.3 MySQL 5.7 中的更改

在升级到 MySQL 5.7 之前,请查看本节中描述的更改,以识别适用于当前 MySQL 安装和应用程序的更改。执行任何建议的操作。

标为 不兼容的更改 的更改与 MySQL 的早期版本不兼容,并且升级之前可能需要引起您的注意。我们的目的是避免这些更改,但是有时它们对于纠正比发行版之间的不兼容性更严重的问题是必要的。如果适用于您的安装的升级问题涉及不兼容,请按照说明中给出的说明进行操作。有时这涉及转储和重新加载 table,或使用诸如CHECK TABLEREPAIR TABLE之类的语句。

有关转储和重新加载的说明,请参见第 2.11.12 节,“重建或修复 table 或索引”。涉及USE_FRM选项的REPAIR TABLE的任何过程都必须在升级之前完成。将该语句与用于创建 table 的 MySQL 版本(即在升级后使用它)不同的 MySQL 版本使用可能会损坏 table。参见第 13.7.2.5 节“ REPAIR TABLE 语句”

Configuration Changes

在 MySQL 5.7.11 中,默认的--early-plugin-load值为keyring_file插件库文件的名称,因此默认情况下已加载该插件。 InnoDBtable 空间加密要求在InnoDB初始化之前先加载keyring_file插件,因此默认--early-plugin-load值的此更改引入了从 5.7.11 升级到 5.7.12 或更高版本的不兼容性。加密InnoDBtable 空间的 Management 员必须采取显式操作,以确保 continue 加载keyring_file插件:使用名为插件库文件的--early-plugin-load选项启动服务器。有关更多信息,请参见第 6.4.4.1 节“安装 Keyring 插件”

有关从INFORMATION_SCHEMAtable 迁移到 Performance Schematable 的建议,请参阅第 25.20 节“迁移到性能模式系统和状态变量 table”。为了协助迁移,您可以使用show_compatibility_56系统变量,它会影响INFORMATION_SCHEMA和 Performance Schematable 以及SHOW VARIABLESSHOW STATUS语句提供系统和状态变量信息的方式。 show_compatibility_56在 5.7.6 和 5.7.7 中默认启用,在 MySQL 5.7.8 中默认禁用。

有关show_compatibility_56的效果的详细信息,请参见第 5.1.7 节“服务器系统变量”为了更好地理解,强烈建议您还阅读以下部分:

CREATE USER 'root'@'127.0.0.1' IDENTIFIED BY 'root-password';
CREATE USER 'root'@'::1' IDENTIFIED BY 'root-password';
  • 不兼容的更改 :从 MySQL 5.7.6 开始,对于某些 Linux 平台,当使用 RPM 和 Debian 软件包安装 MySQL 时,现在使用 systemd 而不是mysqld_safe来 Management 服务器的启动和关闭,而未安装mysqld_safe。这可能需要对指定服务器选项的方式进行一些调整。有关详细信息,请参见第 2.5.10 节“使用 systemdManagementMySQL 服务器”

  • 不兼容的更改 :在 MySQL 5.7.5 中,mysql_install_db的可执行二进制版本位于bin安装目录中,而 Perl 的版本位于scripts安装目录中。对于从旧版本的 MySQL 升级,您可能会在两个目录中都找到一个版本。为避免混淆,请删除scripts目录中的版本。对于 MySQL 5.7.5 或更高版本的全新安装,仅在bin目录中找到mysql_install_db,而不再存在scripts目录。希望在scripts目录中找到mysql_install_db的应用程序应更新为在bin目录中查找。

从 MySQL 5.7.6 开始,mysql_install_db的位置已不再重要,因为从该版本开始,不推荐使用mysql_install_db,而推荐使用_或mysqld --initialize-insecure。见第 2.10.1 节“初始化数据目录”

  • 不兼容的更改 :在 MySQL 5.7.5 中,进行了以下 SQL 模式更改:

  • 现在默认情况下为事务存储引擎(_)启用严格的 SQL 模式。

如果您发现启用ONLY_FULL_GROUP_BY导致对现有应用程序的查询被拒绝,则以下任一操作均应恢复操作:

  • 如果可以修改有问题的查询,请这样做,以使不确定的非聚合列在功能上取决于GROUP BY列,或者通过使用ANY_VALUE()引用非聚合列。

    • 如果无法修改有问题的查询(例如,如果它是由第三方应用程序生成的),则在服务器启动时将sql_mode系统变量设置为不启用ONLY_FULL_GROUP_BY

有关 SQL 模式和GROUP BY查询的更多信息,请参见第 5.1.10 节“服务器 SQL 模式”第 12.20.3 节“ MySQL BY GROUP BY 的处理”

系统 table 更改

  • 不兼容的更改 :在 MySQL 5.7.6 中删除了mysql.user系统 table 的Password列。所有凭证都存储在authentication_string列中,包括以前存储在Password列中的凭证。如果执行就地升级到 MySQL 5.7.6 或更高版本,请按照就地升级程序的指示运行mysql_upgrade,以将Password列的内容迁移到authentication_string列。

如果使用 5.7.6 之前的 MySQL 安装中的mysqldump转储文件执行logical upgrade,则必须遵守用于生成转储文件的mysqldump命令的以下条件:

逻辑升级程序中所述,请在运行mysql_upgrade之前将 5.7.6 之前的转储文件加载到 5.7.6(或更高版本)服务器中。

Server Changes

  • 不兼容的更改 :自 MySQL 5.7.5 起,不再支持使用较早的 4.1 之前的密码哈希格式的密码,这涉及以下更改。必须修改使用不再受支持的功能的应用程序。

  • 删除了使用 4.1 之前的密码哈希值的mysql_old_password身份验证插件。使用该插件的帐户在启动时被禁用,服务器将“未知插件”消息写入错误日志。有关升级使用此插件的帐户的说明,请参阅第 6.4.1.3 节“迁移到 4.1 版之前的密码哈希和 mysql_old_password 插件”

    • 对于old_passwords系统变量,不再允许使用值 1(产生 4.1 之前的哈希值)。

    • 服务器和 Client 端程序的--secure-auth选项是默认选项,但现在是禁止操作。不推荐使用,它将在将来的 MySQL 版本中删除。

    • 服务器和 Client 端程序的--skip-secure-auth选项不再受支持,使用它会产生错误。

    • secure_auth系统变量仅允许值为 1;值 0 不再被允许。

    • OLD_PASSWORD()功能已删除。

  • 不兼容的更改 :在 MySQL 5.6.6 中,不赞成使用两位数的YEAR(2)数据类型。在 MySQL 5.7.5 中,删除了对YEAR(2)的支持。升级到 MySQL 5.7.5 或更高版本后,所有剩余的 2 位YEAR(2)列都必须转换为 4 位YEAR列才能再次使用。有关转换策略,请参见第 11.2.5 节“ 2 位数字年份(2)限制并迁移到 4 位数字年份”。升级后运行mysql_upgrade是可能的转换策略之一。

  • 从 MySQL 5.7.7 开始,如果检查 table...升级table 包含 5.6.4 之前的格式的旧时态列(TIMEDATETIMETIMESTAMP列不支持小数秒精度),则报告该 table 需要重建,并且avoid_temporal_upgrade系统变量已禁用。这有助于mysql_upgrade检测和升级包含旧时态列的 table。如果启用了avoid_temporal_upgrade,则FOR UPGRADE会忽略 table 中存在的旧时态列;因此,mysql_upgrade不会升级它们。

从 MySQL 5.7.7 开始,如果 table_5 包含旧的时间列(采用 5.6.4 之前的格式)并且REPAIR TABLE系统变量被禁用,则REPAIR TABLE升级 table。如果启用了avoid_temporal_upgrade,则REPAIR TABLE会忽略 table 中存在的旧时态列,并且不会升级它们。

要检查包含此类临时列且需要重建的 table,请在执行检查 table...升级之前禁用avoid_temporal_upgrade

要升级包含此类临时列的 table,请在执行REPAIR TABLEmysql_upgrade之前禁用avoid_temporal_upgrade

  • 不兼容的更改 :自 MySQL 5.7.2 起,服务器要求mysql.user系统 table 中的帐户行具有非空的plugin列值,并禁用具有空值的帐户。这要求您升级mysql.usertable 以填写所有plugin值。从 MySQL 5.7.6 开始,请使用以下过程:

如果您打算使用现有 MySQL 安装中的数据目录进行升级,请执行以下操作:

  • 停止旧的(MySQL 5.6)服务器

  • 通过将旧的二进制文件替换为新的二进制文件来升级 MySQL 二进制文件

  • 正常启动 MySQL 5.7 服务器(无特殊选项)

  • 运行mysql_upgrade升级系统 table

  • 重新启动 MySQL 5.7 服务器

如果您打算通过重新加载现有 MySQL 安装生成的转储文件进行升级,请执行以下操作:

  • 要生成转储文件,请使用--add-drop-table选项(不带--flush-privileges选项)运行mysqldump

  • 停止旧的(MySQL 5.6)服务器

  • 升级 MySQL 二进制文件(用新的二进制文件替换旧的二进制文件)

  • 正常启动 MySQL 5.7 服务器(无特殊选项)

  • 重新加载转储文件(mysql <dump_file)

  • 运行mysql_upgrade升级系统 table

  • 重新启动 MySQL 5.7 服务器

在 MySQL 5.7.6 之前,该过程涉及更多:

如果您打算使用现有 MySQL 安装中的数据目录进行升级,请执行以下操作:

  • 停止旧的(MySQL 5.6)服务器

  • 升级 MySQL 二进制文件(用新的二进制文件替换旧的二进制文件)

  • 使用--skip-grant-tables选项重新启动服务器以禁用特权检查

  • 运行mysql_upgrade升级系统 table

  • 正常重启服务器(没有--skip-grant-tables)

如果您打算通过重新加载现有 MySQL 安装生成的转储文件进行升级,请执行以下操作:

mysql_upgrade默认以 MySQL root用户身份运行。对于上述过程,如果在运行mysql_upgraderoot密码已过期,则会看到一条消息,提示您的密码已过期,而mysql_upgrade失败。要解决此问题,请重置root密码以使其失效,然后再次运行mysql_upgrade

shell> mysql -u root -p
Enter password: ****  <- enter root password here
mysql> ALTER USER USER() IDENTIFIED BY 'root-password'; # MySQL 5.7.6 and up
mysql> SET PASSWORD = PASSWORD('root-password');        # Before MySQL 5.7.6
mysql> quit

shell> mysql_upgrade -p
Enter password: ****  <- enter root password here

如果服务器以--skip-grant-tables启动,则密码重置语句通常不起作用,但是第一次调用mysql_upgrade会刷新特权,因此在运行mysql时,该语句会被接受。

如果mysql_upgrade本身已过期root密码,则您将需要以相同的方式再次重置密码。

按照上述说明进行操作之后,建议 DBA 将使用mysql_old_password身份验证插件的帐户转换为使用mysql_native_password,因为已经删除了对mysql_old_password的支持。有关帐户升级的说明,请参阅第 6.4.1.3 节“迁移到 4.1 版之前的密码哈希和 mysql_old_password 插件”

  • 不兼容的更改DEFAULT列的值可能在 table 创建时对sql_mode值有效,但在插入或更新行时对_值无效。例:
SET sql_mode = '';
CREATE TABLE t (d DATE DEFAULT 0);
SET sql_mode = 'NO_ZERO_DATE,STRICT_ALL_TABLES';
INSERT INTO t (d) VALUES(DEFAULT);

在这种情况下,CREATE TABLE应该接受 0,而INSERT则拒绝 0.但是,以前,服务器未针对当前sql_mode评估用于插入或更新的DEFAULT值。在示例中,INSERT成功,并将'0000-00-00'插入DATE列。

从 MySQL 5.7.2 开始,服务器在插入或更新时应用适当的sql_mode检查以生成警告或错误。

如果您使用基于语句的日志记录(binlog_format=STATEMENT),则导致复制的不兼容性是,如果升级了从属服务器,则未升级的主服务器将执行上述示例而不会出错,而INSERT将在从属服务器上失败并停止复制。

为了解决这个问题,请在主服务器上停止所有新语句,然后 await 从服务器追上。然后先升级从机,再升级主机。或者,如果您无法停止新语句,则暂时更改为主服务器上的基于行的日志记录(binlog_format=ROW),然后 await 直到所有从属服务器都处理了所有生成此更改为止的二进制日志。然后先升级从属服务器,再升级主服务器,然后将主服务器改回基于语句的日志记录。

  • 不兼容的更改 :为了更好地与 Oracle Audit Vault 兼容,对审核日志插件进行了一些更改。出于升级目的,主要问题是审核日志文件的默认格式已更改:以前使用属性写入的<AUDIT_RECORD>元素中的信息现在使用子元素写入。

<AUDIT_RECORD>格式的示例:

<AUDIT_RECORD
 TIMESTAMP="2013-04-15T15:27:27"
 NAME="Query"
 CONNECTION_ID="3"
 STATUS="0"
 SQLTEXT="SELECT 1"
/>

新格式的示例:

<AUDIT_RECORD>
 <TIMESTAMP>2013-04-15T15:27:27 UTC</TIMESTAMP>
 <RECORD_ID>3998_2013-04-15T15:27:27</RECORD_ID>
 <NAME>Query</NAME>
 <CONNECTION_ID>3</CONNECTION_ID>
 <STATUS>0</STATUS>
 <STATUS_CODE>0</STATUS_CODE>
 <USER>root[root] @ localhost [127.0.0.1]</USER>
 <OS_LOGIN></OS_LOGIN>
 <HOST>localhost</HOST>
 <IP>127.0.0.1</IP>
 <COMMAND_CLASS>select</COMMAND_CLASS>
 <SQLTEXT>SELECT 1</SQLTEXT>
</AUDIT_RECORD>

如果您以前使用了较旧版本的审核日志插件,请使用以下过程来避免将新格式的日志条目写入包含旧格式的条目的现有日志文件中:

  • 停止服务器。

  • 手动重命名当前审核日志文件。该文件将仅包含旧格式的日志条目。

  • 更新服务器并重新启动它。审核日志插件将创建一个新的日志文件,该文件仅包含新格式的日志条目。

有关审核日志插件的信息,请参阅第 6.4.5 节“ MySQL 企业审核”

  • 从 MySQL 5.7.7 开始,复制从属服务器的默认连接超时从 3600 秒(一小时)更改为 60 秒(一分钟)。当没有设置slave_net_timeout系统变量的复制从属服务器升级到 MySQL 5.7 时,将应用新的默认值。心跳间隔的默认设置计算为slave_net_timeout值的一半,该默认设置调节心跳 signal 以在没有数据的情况下停止连接超时(如果连接仍然良好)。心跳间隔记录在从站的主信息日志(mysql.slave_master_infotable 或master.info文件)中,并且在更改slave_net_timeout的值或默认设置时不会自动更改。一个使用默认连接超时和心跳间隔,然后又升级到 MySQL 5.7 的 MySQL 5.6 从站,因此其心跳间隔比连接超时长得多。

如果主服务器上的活动级别足以使对二进制日志的更新至少每 60 秒发送一次到从属服务器,则这种情况就不成问题了。但是,如果未从主机接收到任何数据,则由于未发送心跳,因此连接超时将到期。因此,从站认为与主站的连接已丢失,并进行了多次重新连接尝试(由MASTER_CONNECT_RETRYMASTER_RETRY_COUNT设置控制,也可以在主站信息日志中看到)。重新连接尝试会产生许多主机必须杀死的僵尸转储线程,从而导致主机的错误日志包含错误 ER_RPL_ZOMBIE_ENCOUNTERED 的多个实例。为避免此问题,在将复制从属服务器升级到 MySQL 5.7 之前,请立即检查slave_net_timeout系统变量是否使用默认设置。如果是这样,请使用MASTER_HEARTBEAT_PERIOD选项发出更改为主,并将心跳间隔设置为 30 秒,以便它与升级后适用的 60 秒的新连接超时一起使用。

InnoDB Changes

  • 从 MySQL 5.7.24 开始,与 MySQLBinding 在一起的zlib library版本从 1.2.3 版本提高到 1.2.11 版本。

zlib 1.2.11 中的 zlib compressBound()函数返回的压缩大小估计值比 zlib 1.2.3 版中的压缩大小要高一些。 InnoDB函数调用compressBound()函数,这些函数确定创建压缩的InnoDBtable 或将行插入压缩的InnoDBtable 时允许的最大行大小。结果,行大小非常接近在早期版本中成功的最大行大小的创建 table... ROW_FORMAT = COMPRESSEDINSERT操作现在可能会失败。

如果压缩的InnoDBtable 具有较大的行,建议在升级之前在 MySQL 5.7 测试实例上测试压缩的 tableCREATE TABLE语句。

  • 不兼容的更改 :为了简化崩溃恢复期间的InnoDBtable 空间发现,MySQL 5.7.5 中引入了新的重做日志记录类型。此增强功能更改了重做日志格式。在执行就地升级之前,请使用_5 或1innodb_fast_shutdown设置执行干净关闭。建议在In-Place Upgrade中使用innodb_fast_shutdown=0缓慢关闭。

  • 不兼容的更改 :MySQL 5.7.8 和 5.7.9 撤消日志可能包含有关空间列的信息不足,这可能导致升级失败(错误#21508582)。在执行从 MySQL 5.7.8 或 5.7.9 到 5.7.10 或更高版本的就地升级之前,请使用innodb_fast_shutdown=0进行缓慢关机以清除撤消日志。建议在In-Place Upgrade中使用innodb_fast_shutdown=0缓慢关闭。

  • 不兼容的更改 :MySQL 5.7.8 撤消日志可能包含的有关虚拟列和虚拟列索引的信息不足,可能导致升级失败(错误#21869656)。在执行从 MySQL 5.7.8 到 MySQL 5.7.9 或更高版本的就地升级之前,请使用innodb_fast_shutdown=0执行缓慢关机以清除撤消日志。建议在In-Place Upgrade中使用innodb_fast_shutdown=0缓慢关闭。

  • 不兼容的更改 :自 MySQL 5.7.9 起,第一个重做日志文件(ib_logfile0)的重做日志头包括格式版本标识符和文本字符串,该字符串标识创建重做日志文件的 MySQL 版本。此增强功能更改了重做日志格式,要求在执行就地升级到 MySQL 5.7.9 或更高版本之前,使用__ 01innodb_fast_shutdown设置彻底关闭 MySQL。建议在In-Place Upgrade中使用innodb_fast_shutdown=0缓慢关闭。

  • 在 MySQL 5.7.9 中,DYNAMIC替换COMPACT作为InnoDBtable 的隐式默认行格式。新的配置选项innodb_default_row_format指定默认的InnoDB行格式。允许的值包括DYNAMIC(默认值),COMPACTREDUNDANT

升级到 5.7.9 后,除非您明确定义行格式(ROW_FORMAT),否则您创建的任何新 table 都将使用innodb_default_row_format定义的行格式。

对于未显式定义ROW_FORMAT选项或使用ROW_FORMAT=DEFAULT的现有 table,任何重建 table 的操作也会将 table 的行格式默默更改为innodb_default_row_format定义的格式。否则,现有 table 将保留其当前行格式设置。有关更多信息,请参见定义 table 格的行格式

  • 从 MySQL 5.7.6 开始,InnoDB存储引擎将其自己的内置(“本机”)分区处理程序用于使用InnoDB创建的任何新分区 table。在 MySQL 早期版本中创建的InnoDB分区 table 不会自动升级。您可以使用以下两种方法之一轻松升级此类 table,以在 MySQL 5.7.9 或更高版本中使用InnoDB本机分区:

  • 要将单个 table 从通用分区处理程序升级到* InnoDB *本机分区,请执行语句ALTER TABLE table_name 升级分区

    • 要将使用通用分区处理程序的所有InnoDBtable 升级为使用本机分区处理程序,请运行mysql_upgrade

SQL Changes

  • 不兼容的更改GET_LOCK()函数已在 MySQL 5.7.5 中使用元数据锁定(MDL)子系统重新实现,其功能已得到扩展:

  • 以前,GET_LOCK()一次仅允许获取一个命名锁,而第二个GET_LOCK()调用则释放了任何现有锁。现在GET_LOCK()允许获取多个同时命名的锁,并且不会释放现有的锁。

依赖GET_LOCK()释放任何先前锁定行为的应用程序必须针对新行为进行修改。

  • 获取多个锁的能力引入了 Client 端之间死锁的可能性。 MDL 子系统检测到死锁,并在发生这种情况时返回ER_USER_LOCK_DEADLOCK错误。

  • MDL 子系统对锁名称施加了 64 个字符的限制,因此该限制现在也适用于命名锁。以前,没有实施长度限制。

  • 现在,用GET_LOCK()获取的锁将显示在“性能模式metadata_locks”table 中。 OBJECT_TYPE列 table 示USER LEVEL LOCK,而OBJECT_NAME列 table 示锁名称。

  • 新功能RELEASE_ALL_LOCKS()允许一次释放所有获得的命名锁。

有关更多信息,请参见第 12.14 节“锁定功能”

  • 现在,优化器以一致的方式处理FROM子句中的派生 table 和视图,以更好地避免不必要的实现,并允许使用产生更有效执行计划的下推条件。但是,对于诸如DELETEUPDATE之类的用于修改 table 的语句,对先前实现的派生 table 使用合并策略可能会导致ER_UPDATE_TABLE_USED错误:
mysql> DELETE FROM t1
    -> WHERE id IN (SELECT id
    ->              FROM (SELECT t1.id
    ->                    FROM t1 INNER JOIN t2 USING (id)
    ->                    WHERE t2.status = 0) AS t);
ERROR 1093 (HY000): You can't specify target table 't1'
for update in FROM clause

当将派生 table 合并到外部查询块中时,会导致从 table 中进行选择和修改的语句发生错误。 (进行归一化处理不会导致此问题,因为实际上它会将派生 table 转换为一个单独的 table.)为避免此错误,请在执行以下语句之前禁用optimizer_switch系统变量的derived_merge标志:

SET optimizer_switch = 'derived_merge=off';

假设没有其他规则阻止合并,则derived_merge标志控制优化程序是否尝试将FROM子句中的子查询和视图合并到外部查询块中。默认情况下,该标志为on以启用合并。将标志设置为off可以防止合并,并避免上述错误。有关更多信息,请参见第 8.2.2.4 节“通过合并或实现来优化派生 table 和视图引用”

  • 一些关键字可能在 MySQL 5.7 中保留,而在 MySQL 5.6 中未保留。参见第 9.3 节“关键字和保留字”。这可能导致以前用作标识符的单词变得非法。要修复受影响的语句,请使用标识符引号。参见第 9.2 节“架构对象名称”

  • 升级后,建议您测试应用程序代码中指定的优化器提示,以确保仍需要这些提示来实现所需的优化策略。优化器增强有时可能使某些优化器提示不必要。在某些情况下,不必要的优化器提示甚至可能适得其反。

  • UNION语句中,要将ORDER BYLIMIT应用于单个SELECT,请将子句放在括起SELECT的括号内:

(SELECT a FROM t1 WHERE a=10 AND B=1 ORDER BY a LIMIT 10)
UNION
(SELECT a FROM t2 WHERE a=11 AND B=2 ORDER BY a LIMIT 10);

MySQL 的早期版本可能允许不带括号的此类语句。在 MySQL 5.7 中,强制使用括号。