大版本升级最佳实践

本文介绍PolarDB MySQL版的5.6、5.7版本和MySQL 5.6、5.7版本升级至PolarDB MySQL版的8.0版本的优势、预检查以及兼容性说明等内容。

PolarDB MySQL版8.0版本概述

  • 版本发布日期

    • 8.0.1版本发布于2019年12月3日。

    • 8.0.2版本发布于2020年7月22日。

  • 版本优势

    8.0版本增强了架构和内核能力,为用户处理业务提供了更灵活的技术解决方案,性能提升明显。详情请参见功能特性

兼容性预检查

PolarDB MySQL版的5.6、5.7版本和MySQL 5.6、5.7版本向的8.0版本升级过程中,经常会遇到性能、语法兼容以及周边组件是否支持的问题。查询的性能问题一般是由于优化器升级导致执行计划有变化,此类问题需要对性能低下的语句进行针对性的性能优化,单独的性能问题基本不会引发业务报错以及代码改写的问题,此类问题不在本文讨论范围之内。

本文主要讨论兼容性问题,此类问题需要在数据库升级过程中,更新相应的代码或更改环境配置,引发此类问题的主要原因为版本升级后部分语法的变化以及特性的更新和移除。如果确保上述内容不存在问题,可以跳过下面章节进行升级,详情请参见大版本一键升级

预检查功能会提供一个简要清单,帮助您在升级前更好地了解升级过程中可能需要注意的问题。如果下述内容存在对应的问题,请参考后续内容进行操作和检查。

  • 确保没有使用废弃的数据类型、函数和功能,废弃清单信息请参见Features Removed in MySQL 8.0

  • 确保触发器(Triggers)没有丢失、空的definer或无效的内容。

  • 确保只有InnoDB引擎的分区表。

  • 确保关键字和保留关键字没有冲突,详情请参见Keywords and Reserved Words

  • 确保没有和MySQL 5.6、5.7版本的系统数据库、MySQL 8.0版本新增的INNODB_开头的词典表名冲突。

  • 确保不依赖于INFORMATION_SCHEMA下的GLOBALLOCALVARIABLESSTATUS表。

  • 确保sql_mode中没有使用废弃的变量设置,详情请参见参数兼容性

  • 确保表和存储过程单个ENUMSET列元素的长度不超过255个字符或1020个字节。

  • 确保表的分区不在共享InnoDB tablespaces表空间中。

  • 确保查询SQL语句中的GROUP BY子句不带有ASC或DESC。

    说明

    8.0.2.2.11.1版本及以上的版本,在控制台上将loose_group_by_compatible_sorting参数的值设置为TRUE后可以开启兼容模式,兼容模式支持在SQL语句中使用带有ASC或DESC的GROUP BY子句。在控制台上设置参数值的操作步骤请参见设置集群参数和节点参数

  • 确保外键约束名称不超过64个字符。

说明
  • 为了增强Unicode的支持,推荐您将使用utf8mb3(已废弃)或utf8(utf8mb3字符集的别名)字符集的对象更改为utf8mb4字符集。更多信息请参见The utf8mb3 Character Set (3-Byte UTF-8 Unicode Encoding)

  • 升级前需要进行备份,以避免升级过程中可能遇到的其他问题。

引擎和分区表兼容性

在8.0版本中,创建MyISAM类型的分区将导致使用没有此类型支持的存储引擎的分区表创建语句失败并出现错误(ER_CHECK_NOT_IMPLEMENTED)。有关将表从MyISAM转换至InnoDB引擎,请参见将表从MyISAM转换为InnoDB

存储引擎现支持分区处理程序,且服务器不再支持通用引擎分区。

InnoDB还提供仅8.0版本支持的本机分区处理程序的存储引擎。您需要在升级服务器前,将其他存储引擎的分区表的存储引擎转换为InnoDB存储引擎,或删除对应分区表,否则后续将无法使用。如有类似分区,请您提前转换引擎后再进行升级。检查引擎语法如下:

SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE ENGINE NOT IN ('innodb','ndbcluster') AND CREATE_OPTIONS LIKE '%partitioned';

或:

SELECT DISTINCT NAME,SPACE,SPACE_TYPE FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES
WHERE NAME LIKE '%#P#%' AND SPACE_TYPE NOT LIKE 'Single';

将引擎更改为InnoDB引擎语法如下:

ALTER TABLE part ENGINE = INNODB;
Query OK, 0 rows affected (0.09 sec)

删除对应分区表语法如下:

ALTER TABLE part REMOVE PARTITIONING;
Query OK, 0 raws affected (0.06 sec)

如果使用MySQLdump从MySQL 5.6、5.7版本服务器创建的转储文件中将数据导入至 8.0版本的服务器,需确保创建分区表的任何语句都没有同时指定不被支持的存储引擎,您可以通过删除对分区的全部引用、将存储引擎指定为InnoDB或允许将参数default_storage_engine = InnoDB设置为InnoDB的默认值的方法实现该要求。识别在升级到MySQL 8.0版本之前必须更改的分区表的方法请参见为升级准备安装。有关分区限制详细信息请参见与存储有关的分区限制

字符集和排序规则兼容性

MySQL 8.0版本的默认字符集为utf8mb4。 MySQL 8.0版本和PolarDB MySQL版character_set_server值均默认为utf8,您可以根据业务需求进行调整。为支持Unicode,推荐您将使用的utf8mb3字符集转换为使用utf8mb4字符集。详细信息请参见utf8mb3字符集

MySQL 8.0版本新增default_collation_for_utf8mb4参数,该参数的作用为当字符集为utf8mb4时,根据默认排序规则排序,该参数的默认值为utf8mb3_0900_ai_ci,且该默认值只是MySQL中replication使用的内部参数。

若您在从低版本同步到高版本的过程中没有遇到lllegal mix of collations的错误,不建议您将该默认值修改为utf8mb4_general_ciutf8mb4_0900_ai_ci

  • utf8mb4_0900_ai_ci:基于官方Unicode的规则做通用的排序和比较,准确度高,但比对速度稍慢。

  • utf8mb4_general_ci:精简集合的排序规则,目的是提供简化的设计来加快比对速度,虽然没有遵循Unicode的规则,但在相同情况下结果符合预期。

排序规则和字符集不同,它只和排序有关,其中ai表示口音不敏感,即排序时e,è,é,ê和ë之间没有区别;ci表示不区分大小写,即排序时p和P之间没有区别。

说明
  • 在8.0版本向低版本反向同步或dump同步时,可能会存在兼容性问题。

  • 在DTS低版本与高版本双向同步场景下容易出现异常,您需要使用MySQL 5.6、5.7和PolarDB MySQL版5.6、5.7版本默认的排序字符集,否则DTS反向同步的时候会出现异常。

  • 由于排序规则问题,创建视图时可能会报错lllegal mix of collations,例如当您使用了convert(a.c1 using utf8mb4)=b.c1时,可能会报上述错误。

  • 当您使用convert(exp using utf8mb4)且不指定collation时,MySQL会按照utf8mb4查询,返回的charset number值为255。255对应的collation即为MySQL 8.0版本默认的utf8mb4_0900_ai_ci

  • 修改default_collation_for_utf8mb4或在DDL中指定列名、表名或数据库名时,collation都不会起作用。如果您需要使用convert函数,需要在语句中加入collation,如(convert(a.c1 using utf8mb4)collate utf8mb4_general_ci)=b.c1

  • 修改default_collation_for_utf8mb4参数的默认值,如将默认值修改为utf8mb4_general_ci,会导致出现如下问题:

    • 无法正确读取SYS库及其相关函数,报错lllegal mix of collations(utf8mb4_0900_ai_ci.IMPLICIT) and (utf8mb4_general_ci.IMPLICIT) for operation'='

    • 从8.0.1版本升级到8.0.2时,升级失败。该参数是8.0版本新增加的参数,建议不要修改该参数,如果必须使用其他值,请在执行升级操作前,前往配额中心,在配额名称为default_collation_for_utf8mb4操作列,单击申请,申请将参数的默认值重置为utf8mb4_0900_ai_ci,升级完成后,需要将默认值再修改为utf8mb4_general_ci

参数兼容性

lower_case_table_names

从MySQL 8.0.11版本开始,禁止lower_case_table_names使用与服务器初始化时不同的设置来启动服务器。各种数据字典、表字段使用的排序规则基于lower_case_table_names服务器初始化时定义的设置,使用不同的设置重新启动服务器时,会导致标识符的排序和比较方式引入不一致。在PolarDB MySQL版 8.0版本中,集群区分大小写无法在初始化完成后再次更改,您需要在购买 8.0版本的集群时选定集群是否区分大小写。关于lower_case_table_names参数详情请参见lower_case_table_names

sql_mode

为避免8.0版本的集群启动失败,请通过NO_AUTO_CREATE_USER从MySQL选项文件的系统变量sql_mode设置中删除所有集群。

您的系统变量设置中不得定义过时的SQL模式,否则sql_mode会引起许多不同的行为,在版本升级时需要确认对齐。需要取消的配置项如下:

DB2, MAXDB, MSSDL, MYSQL323, MYSQL40, ORACLE, POSTGRESQL, NO_FIELD_OPTIONS, NO_KEY_OPTI
说明

以上配置项大多为组合配置,需要注意是否有不一致的mode选项。例如:

  • sql_mode=TRADITIONAL等于配置如下项:

    STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISIC
  • 在MySQL5.6、5.7和 5.6、5.7版本默认配置时,sql_mode=TRADITIONAL等于配置如下项:

    STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE,
    ERROR_FOR_DIVISIC_BY_ZERO, NO_AUTO_CREATE_USER, and NO_ENGINE_SUBSTITUTION

对比上述配置项,可以看到5.6、5.7版本中多了NO_AUTO_CREATE_USER选项,在8.0版本已经禁止GRANT语句隐式创建账号,5.6、5.7版本虽然添加了NO_AUTO_CREATE_USER选项,但在指定identified by时,可以使用GRANT创建账号。

如果您发现启用ONLY_FULL_GROUP_BY导致现有应⽤程序查询被拒绝,可以使用以下方法恢复操作:

  • 如果可以修改有问题的查询,请去除select投影列、HAVING条件或ORDER BY列表中的非聚集列,这些列既不在GROUP BY中,也不与GROUP BY列有任何函数关系。或者您可以使用ANY_VALUE()函数。

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

    例如,当描述不是GROUP BY的一部分,且没有应用聚合函数(例如MINMAX)时,会出现如下情况:

    5.6版本:

    SELECT id, invoice_id, description FROM invoice_line_items GROUP BY invoice_id;
    +----+------------+-------------+
    | id | invoice_id | description |
    +----+------------+-------------+
    | 1 | 1 | New socks |
    | 3 | 2 | Shoes |
    | 5 | 3 | Tie |
    +----+------------+-------------+
    3 rows in set (0.00 sec)

    8.0版本:

    SELECT id, invoice_id, description FROM invoice_line_items GROUP BY invoice_id;
    ERROR 1055 (42000): Expression #3 of SELECT list is not in GROUP BY clause and contains

explicit_defaults_for_timestamp

从MySQL 8.0开始,MySQL官方将explicit_defaults_for_timestamp的默认值从OFF修改成ON。目前PolarDB MySQL版 8.0中该参数的默认值仍然遵循5.6和5.7版本为OFF

如果迁移过程中不希望自动添加NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,则需要将该参数设置成ON

explicit_defaults_for_timestampOFF,MySQL对于TIMESTAMP类型使用了非标准行为:

  • TIMESTAMP类型的列,如果没有显性定义NULL属性,将会自动添加NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。如果显性定义NULL属性,则保留该属性。

mysql> set explicit_defaults_for_timestamp = OFF;
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> create table t1(c1 timestamp);
Query OK, 0 rows affected (0.01 sec)

mysql> show create table t1;
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1 | CREATE TABLE `t1` (
 `c1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> drop table t1;
Query OK, 0 rows affected (0.01 sec)

mysql> create table t1(c1 int, c2 timestamp null);
Query OK, 0 rows affected (0.01 sec)

mysql> show create table t1;
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
| t1 | CREATE TABLE `t1` (
 `c1` int(11) DEFAULT NULL,
 `c2` timestamp NULL DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
+-------+--------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
  • 表中第一个定义TIMESTAMP的列,要么显性指定NULL,要么显性指定DEFAULT或者ON UPDATE属性,或者自动增加DEFAULT CURRENT_TIMESTAMPON UPDATE CURRENT_TIMESTAMP属性。

  • 表中第二个定义TIMESTAMP的列,如果sql_mode没有设置成NO_ZERO_DATE,且没有显性指定NULL或者DEFAULT属性,会自动定义成DEFAULT '0000-00-00 00:00:00'

    mysql> set sql_mode = '';
    Query OK, 0 rows affected (0.00 sec)
    
    mysql> create table t1(c1 timestamp, c2 timestamp);
    Query OK, 0 rows affected (0.01 sec)
    
    mysql> show create table t1;
    +-------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Table | Create Table |
    +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | t1 | CREATE TABLE `t1` (
     `c1` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
     `c2` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00'
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci |
    +-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.00 sec)

    如果设置成严格模式的NO_ZERO_DATE,则会报错:

    mysql> create table t1(c1 timestamp, c2 timestamp);
    ERROR 1067 (42000): Invalid default value for 'c2'
    mysql> create table t1(c1 timestamp, c2 timestamp);

explicit_defaults_for_timestampON时,该非标准行为将会废弃,该类型和其他类型的行为一致。

视图/表/关键字兼容性

InnoDB相关视图兼容

INFORMATION_SCHEMA中基于InnoDB系统表的视图被数据字典表的内部系统视图所取代。影响InnoDB INFORMATION_SCHEMA的视图已重命名,在系统应用中直接访问InnoDB相关视图时,需要确认应用中是否已经修改。关于参数INFORMATION_SCHEMA的详细信息请参见NFORMATION_SCHEMA Tables

重命名的InnoDB信息模式视图

旧名称

新名称

INNODB_SYS_COLUMNS

INNODB_COLUMNS

INNODB_SYS_DATAFILES

INNODB_DATAFILES

INNODB_SYS_FIELDS

INNODB_FIELDS

INNODB_SYS_FOREIGN

INNODB_FOREIGN

INNODB_SYS_FOREIGN_COLS

INNODB_FOREIGN_COLS

INNODB_SYS_INDEXES

INNODB_INDEXES

INNODB_SYS_TABLES

INNODB_TABLES

INNODB_SYS_TABLESPACES

INNODB_TABLESPACES

INNODB_SYS_TABLESTATS

INNODB_TABLESTATS

INNODB_SYS_VIRTUAL

INNODB_VIRTUAL

在MySQL 5.6、5.7和PolarDB MySQL版 5.6、5.7版本中不能存在PolarDB MySQL版 8.0版本新增的同名视图,在MySQL 5.7或PolarDB MySQL版 5.7版本的集群中执行如下语句,如果有返回则需要确认如何对此类表进行处理,此项检查建议您在自建集群上云升级时执行。

'indexes',
'parameter_type_elements',
'parameters',
'resource_groups',
'routines',
'schemate',
'st_spatial_reference_systems',
'table_partition_systems',
'table_partition_values',
'table_partitions',
'table_states',
'tables',
'tablespace_files',
'tablespaces',
'triggers',
'view_routine_usage'
);

suppose
+--------------+--------------+
| TABLE_SCHEMA |  TABLE_NAME  |
+--------------+--------------+
|     mysql    |   catalogs   |
+--------------+--------------+
1 rows in set (0.00 sec)

在MySQL 5.6或5.7版本的集群中执⾏如下语句,如果有返回则需要确认如何对此类表进⾏处理,此项检查建议您在⾃建集群上云升级时执⾏。

SELECT TABLE_SCHEMA, TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE LOWER(TABLE_SCHEMA) = 'mysql'
and LOWER(TABLE_NAME) IN
(
'catalogs',
'character_sets',
'check_constraints',
'collations',
'column_statistics',
'column_type_elements',
'columns',
'dd_properties',
'events',
'foreign_key_column_usage',
'foreign_keys',
'index_column_usage',
'index_partitions',
'index_stats',
'indexes',
'parameter_type_elements',
'parameters',
'resource_groups',
'routines',
'schemata',

上述出现的此类用户表应在升级前重命名或删除,重命名此类用户表语法如下:

ALTER TABLE catalogs RENAME user_catalogs;
Query OK, 0 rows affected (0.05 sec)

删除此类用户表语法如下:

DROP TABLE catalogs;
Query OK, 0 rows affected (0.06 sec)

视图兼容

在MySQL 8.0版本之前的版本,您最多可以创建具有255个字符的显示列名的视图。为遵守列名的最大长度,MySQL 8.0版本不支持显示列名超过64个字符的视图,目前这些视图只能通过在MySQL 5.6、5.7版本中执行SHOW CREATE VIEW来识别。

SHOW CREATE VIEW v1;
+------+------------------------------------------------------------------------------------------------
| View | Create View
+------+------------------------------------------------------------------------------------------------
|  v1  | CREATE ALGORITHM=UNDEFINED DEFINER='root'@'localhost' SQL SECURITY DEFINER VIEW
+------+------------------------------------------------------------------------------------------------
1 row in set (0.00 sec)

因此,您需要在升级8.0版本前修改视图名称。

ALTER VIEW v1(a12345678901234567890) AS SECLECT 1;

5.6版本系统表兼容

mysql.user系统表的Password列,在MySQL 5.7.6后的版本及8.0版本中被删除。所有凭据都存储在authentication_string列中,包括之前版本存储在该Password列中的数据。

5.6版本INFORMATION_SCHEMA系统和状态变量信息的表兼容

MySQL 5.6和PolarDB MySQL版 5.6版本INFORMATION_SCHEMA中包含系统和状态变量信息的表在8.0版本中被废弃,废弃表如下:

INFORMATION_SCHEMA.GLOBAL_VARIABLES
INFORMATION_SCHEMA.SESSION_VARIABLES
INFORMATION_SCHEMA.GLOBAL_STATUS
INFORMATION_SCHEMA.SESSION_STATUS

8.0版本中将上述废弃的表迁移至PERFORMANCE_SCHEMA中。

performance_schema.global_variables
performance_schema.session_variables
performance_schema.variables_by_thread
performance_schema.global_status
performance_schema.session_status
performance_schema.status_by_thread
performance_schema.status_by_account
performance_schema.status_by_host
performance_schema.status_by_user

如果您直接使用该视图,推荐使用SHOW命令代替,而非直接使用相应的视图。

SHOW VARIABLES
SHOW STATUS

5.6版本INNODB表兼容

DYNAMIC替换COMPACT为InnoDB表的隐式默认⾏格式。配置选项innodb_default_row_format指定默认的InnoDB⾏格式,允许DYNAMIC的值包括COMPACT(默认值)和REDUNDANT。升级到8.0后,除⾮您明确定义⾏格式(ROW_FORMAT),否则您创建的任何新表都需要使⽤定义的⾏格式。对于未显式定义ROW_FORMAT选项或使⽤的现有表ROW_FORMAT=DEFAULT,任何重建表的操作都会将表的⾏格式更改为定义的格式:innodb_default_row_format。更多详细信息请参见表的⾏格式

5.6版本GET_LOCK函数兼容

GET_LOCK()功能在MySQL 5.7.5及之后的版本中使⽤元数据锁定(MDL)⼦系统重新实现,并且其功能已得到扩展:

  • 以前版本中,GET_LOCK()⼀次只允许获取⼀个命名锁,第⼆次调用GET_LOCK()时释放所有现有锁。8.0版本中GET_LOCK()允许同时获取多个命名锁,并且不会释放现有锁。

    依赖于GET_LOCK()释放所有先前锁的⾏为的应⽤程序必须针对新⾏为进⾏修改。

  • 获取多个锁的能⼒可能会在客户端之间引⼊死锁。MDL⼦系统检测死锁且ER_USER_LOCK_DEADLOCK在发⽣这种情况时返回错误。

  • MDL⼦系统对锁名称添加了64个字符的限制,因此该限制也适⽤于命名锁。之前版本没有强制执⾏⻓度限制。

  • 获取的锁GET_LOCK()现在出现在Performance Schema metadata_locks中。OBJECT_TYPE列表示USER LEVEL LOCKOBJECT_NAME列表示锁定名称。

  • 8.0版本支持RELEASE_ALL_LOCKS()允许⼀次释放所有获得的命名锁。

更多信息请参见锁定功能

类型兼容

枚举和集合类型兼容

表或存储过程的单个ENUMSET列元素的长度不得超过255个字符或1020个字节。

5.6版本YEAR类型

废弃YEAR(2)类型,需要⽤YEAR(4)替换YEAR(2)

5.6版本类型数据插入兼容

  • 将负值插⼊⽆符号列时会报错。示例如下:

    1. 创建⼀个包含⽆符号列的表:

       CREATE TABLE test (id int unsigned);
    2. 插⼊⼀个负值。

      INSERT INTO test VALUES (-1);
      • 5.6版本中显示结果如下:

        Query OK, 1 row affected, 1 warning (0.01 sec)
      • 8.0版本中显示结果如下:

        ERROR 1264 (22003): Out of range value for column 'a' at row 1
  • 数据除以零会报错。示例如下:

    1. 创建测试表:

      CREATE TABLE test2 (id int unsigned);
    2. 数据除以零。

      INSERT INTO test2 VALUES (0/0);
      • 5.6版本显示结果如下:

        Query OK, 1 row affected (0.01 sec)
      • 8.0版本显示结果如下:

        ERROR 1365 (22012): Division by 0
  • 字符超⻓插⼊报错。示例如下:

    1. 将20个字符的字符串插⼊10个字符的列会报错。创建⼀个包含10个字符的列的表:

      CREATE TABLE test3 (a varchar(10));
    2. 插⼊更⻓的字符串。

      INSERT INTO test3 VALUES ('abcdefghijklmnopqrstuvwxyz');
      • 5.6版本显示结果如下:

        Query OK, 1 row affected, 1 warning (0.00 sec)
      • 8.0版本显示结果如下:

        ERROR 1406 (22001): Data too long for column 'a' at row 1
  • ⾮标准零⽇期插⼊⽇期时间列会报错。示例如下:

    1. 创建⼀个包含⽇期时间列的表。

      CREATE TABLE test3 (a datetime);
    2. 插⼊0000-00-00 00:00:00

      INSERT INTO test3 VALUES ('0000-00-00 00:00:00');
      • 5.6版本显示结果如下:

        Query OK, 1 row affected, 1 warning (0.00 sec)
      • 8.0版本显示结果如下:

        ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'a' at ro

5.7版本JSON类型中INT类型数据变化

JSON中的部分INT类型被添加了.0变成类似1.0或者9999.0,初步确认是5.7和8.0版本对JSON里面双精度处理方式不同而导致,解决方案需要做DTS数据校验,如有需求您可以在配置DTS界面配置数据校验。

5.x旧式类型兼容

旧式decimal、旧式varchar、旧式TIME/DATETIME和TIMESTAMP等数据类型分别在MySQL 5.0、MySQL 5.1和MySQL 5.6版本中已过时,由于二进制升级一直持续到MySQL 5.6、5.7版本,所以在MySQL 8.0版本中不被支持。这些表可以通过在升级前在MySQL 5.6、5.7版本中运行CHECK TABLE...FOR UPGRADE或使用带有check-upgrade选项的mysqlcheck来识别。此外,使用旧式TIME/DATETIME和TIMESTAMP的表还可以通过启用会话变量来识别,

check table 41_decimal for upgrade;
+-----------------+-------+----------+------------------------------------------------
| Table           | Op    | Msg_type | Msg_text                                         
+-----------------+-------+----------+------------------------------------------------
| test.41_decimal | check | error    | Table upgrade required for `test`.`41_decimal`. 
+-----------------+-------+----------+-------------------------------------------------
1 row in set (0.00 sec) 
check table 55_temporal for upgrade;
+------------------+-------+----------+------------------------------------------------
| Table            | Op    | Msg_type | Msg_text                                        
+------------------+-------+----------+------------------------------------------------
| test.55_temporal | check | error    | Table upgrade required. Please do "REPAIR TABLE 
1 row in set (0.00 sec) 
nisha@nisha-PORTEGE-Z30-A:~/workspace1/mysql-5.7/dbg-5.7/client/mysqlcheck --user=root 
error    : Table upgrade required for `test`.`41_decimal`. Please dump/reload table to 
test.55_temporal
error    : Table upgrade required. Please do "REPAIR TABLE `55_temporal`" or dump/reloa
test.child                                         OK
test.geom                                          OK
test.jemp                                          OK
test.jemp_myisam                                   OK
test.opening_lines                                 OK

使用此类数据类型的表无法升级,应通过REPAIR TABLE修复,并为旧式varchar、旧式decimal转储和重新加载:

REPAIR TABLE 55_temporal; 
+------------------+--------+----------+---------------------------------------------------
| Table            | Op     | Msg_type | Msg_text                                          
+------------------+--------+----------+---------------------------------------------------
| test.55_temporal | repair | Note     | TIME/TIMESTAMP/DATETIME columns of old format have
| test.55_temporal | repair | status   | OK                                                
+------------------+--------+----------+---------------------------------------------------
2 rows in set (0.01)
Dump:
$./client/mysqldump --databases test --socket=5.6/data/mysql.sock --user=root>test.sql
Restore:
.\ test.sql

关键词与保留字

PolarDB MySQL版 8.0版本可以通过 information_schema.KEYWORDS表查看当前版本的关键词与保留字,不得有关键字或保留字违规的情况。PolarDB MySQL版 8.0版本中可能保留了部分以前未保留的关键字,详情请参见关键字和保留字。建议所有自定义内容(表名、字段名、函数名)等全部规避使用。除此之外,KICKOUTPolarDB MySQL版 8.0的保留关键字。因此,若您已经在MySQL 5.6、5.7或原生MySQL 8.0版本上使用该关键字作为对象名称(如表名、字段名、存储过程名等),在迁移到PolarDB MySQL版 8.0版本前,请您先修改对象名称避免使用该关键字,否则迁移时,将会出现错误码为1064的语法报错。

SQL兼容性

GRANT授权

在MySQL 8.0.11中,删除了部分与账户管理相关、已弃用的功能,例如使用GRANT语句修改用户账户的非特权特性。

GRANT REPLICATION CLIENT ON *.* TO 'odps'@'%'; You are not allowed to create a user with
create user;
grant privielges;

不支持GROUP BY ASC/DESC

自MySQL 8.0.13开始,已删除不推荐使用的子句ASC和DESC限定符GROUP BY,之前依赖GROUP BY排序的查询可能会产生与之前MySQL版本不同的结果。要生成给定的排序顺序,您需要提供一个GROUP BY子句。示例如下:

将SQL语句:

select id,count(*) from sbtest.sbtest1 where id < 10 group by id desc

改写为:

select id,count(*) from sbtest.sbtest1 where id < 10 group by id order by id
说明

PolarDB MySQL版 8.0.2.2.11.1版本及以上的版本,不需要执行以上改写操作。您只需要在控制台上将loose_group_by_compatible_sorting参数的值设置为TRUE,即可直接在SQL语句中使用带有ASC或DESC的GROUP BY子句。在控制台上设置参数值的操作步骤请参见设置集群参数和节点参数

外键约束定义

在MySQL 5.6、5.7版本中,定义FOREIGN KEY的InnoDB不得带有CONSTRAINT的关键字且指定外键约束名称不得超过64个字符。在MySQL 8.0之前的版本中,当您未明确指定外键约束名称时,InnoDB会通过在表名后附加_ibfk_X来自动生成外键约束名称,其中X是一个数字。如果表名是多字节64字符,如下面示例中使用的⻄里尔表名 имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк,则自动生成的外键约束名称将超过64个字符。应通过删除约束并确保外键约束名称不超过64个字符来添加具有显式约束名称的约束来更改这些表。

ALTER TABLE `имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк` DR
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
ALTER TABLE `имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк` AD
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0

5.7版本空间函数

在MySQL 5.7中,不推荐使⽤多个名称下可⽤的部分空间函数。示例如下:

CREATE TABLE t_gcol_dep (fid INTEGER NOT NULL PRIMARY KEY, g POINT GENERATED ALWA
Query OK, 0 rows affected, 1 warning (0.07 sec)
show warnings;
+---------+------+---------------------------------------------------------------------
| Level | Code | Message
+---------+------+---------------------------------------------------------------------
| Warning | 1287 | 'POINTFROMTEXT' is deprecated and will be removed in a future releas
+---------+------+---------------------------------------------------------------------
1 row in set (0.00 sec)

由于空间函数名称更改,这些空间函数在8.0版本中已被删除。此更改有助于命名约定保持⼀致,即函数以ST_开头(精确执⾏操作情况下)或者以MBR开头(执⾏基于最⼩边界矩形的操作情况下),使⽤此类函数⽣成的列应在升级前更改。已删除空间函数的列表请参见Features Removed in MySQL 8.0。您需要更改⽣成的列以使⽤相应的ST_MBR函数。

ALTER TABLE t_gcol_dep MODIFY g POINT GENERATED ALWAYS AS (ST_POINTFROMTEXT(POINT
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

触发器兼容

MySQL 5.0.17之前的CREATE TRIGGER不⽀持definer属性。此类具有缺失/空定义器属性或⽆效创建上下⽂(即character_set_clientcollation_collection、数据库排序规则属性)的触发器定义⼀直存在导致MySQL 5.6、5.7版本时⽆法升级。这些触发器可以通过在MySQL 5.6、5.7版本中运⾏带有检查升级选项的mysqlcheckCHECK TABLE来识别。

$./client/mysqlcheck --user=root --socket=5.7/data/mysql.sock --databases triggers --ch
triggers.t1
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_insert'. The trig
Warning : No definer attribute for trigger 'triggers'.'t1_bi'. The trigger will be act
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert_1'. The tri
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert'. The trigg
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert_3'. The tri
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_update_3'. The tr
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_update'. The trig
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_update'. The trigg
Warning : No definer attribute for trigger 'triggers'.'trg1'. The trigger will be acti
status : OK
triggers.t2 OK
check table t1;
+-------------+-------+----------+-----------------------------------------------------
| Table | Op | Msg_type | Msg_text
+-------------+-------+----------+-----------------------------------------------------
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'t1_bi'.
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_

您需要转储或重新加载此类触发器解决此类问题:

Dump:
$./client/mysqldump --databases triggers --socket=5.6/data/mysql.sock --user=root>trigge
Restore:
.\ triggers.sql

客户端兼容性

对于Java应⽤来说,MySQL Connector/J升级到8.0以上版本,连接账户需要连接器/J 8.0.9或更⾼版本的 caching_sha2_password。如果未在数据源中将dataworks设置为utf8,可能会出错,建议修改数据库名。在的连接串中增加:characterEncoding=utf8&com.mysql.jdbc.faultInjection.serverCharsetIndex=使Java客户端在连接中显性指定session级别字符集。

Unknown system variable 'tx_read_only'兼容性

MySQL和 8.0版本中已经删除tx_read_only环境变更,需要使⽤transaction_read_only代替。

即需要将:

 select @@tx_read_only

改写为:

select @@transaction_read_only

常见问题

并行查询导致的排序问题

8.0版本开始⽀持并⾏查询能⼒,并⾏扫描由于随机访问数据会导致MySQL默认串⾏扫描的顺序每次随机变化,尤其是涉及到分⻚的SQL。如果您需要⽣成给定的排序顺序,请提供⼀个ORDER BY⼦句保证顺序。

5.6版本子查询问题

5.6版本子查询中的order by不再起作用,例如:

SELECT *
FROM
(
SELECT * FROM `information_schema`. TABLES
ORDER BY table_name DESC
) AS sg
GROUP BY table_name

内层的order by会被5.7、8.0版本的优化器忽略,您需要通过修改语句解决这个问题,最简单的方法是添加limit使排序生效,例如:

SELECT *
FROM
(
SELECT * FROM `information_schema`. TABLES
ORDER BY table_name DESC limit 10000 # 需要⾜够⼤的⾏数
) AS sg
GROUP BY table_name

5.6版本派⽣表问题

优化器现在以⼀致的⽅式处理⼦句中的派⽣表和视图,使用FROM以更好地避免不必要的物化,并允许使⽤、产⽣更有效的执⾏计划的下推条件。但在 8.0版本以及修改表之类的语句中, DELETEUPDATE之前实现的派⽣表使⽤合并策略可能会导致ER_UPDATE_TABLE_USED错误:

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

将派⽣表合并到外部查询块中会导致从表中选择和修改表语句时发⽣错误。(物化不会导致问题,因为它实际上将派⽣表转换为了单独的表。)为避免此类错误的解决⽅法是在执⾏语句前禁⽤使用系统变量的derived_merge标志optimizer_switch

SET optimizer_switch = 'derived_merge=off';

derived_merge标志控制优化器是否尝试将FROM⼦句中的⼦查询和视图合并到外部查询块中。假设没有其他规则阻⽌合并,默认情况下,该标志是on启⽤合并。设置标志off阻止合并,可以避免上述描述的错误。更多信息请参见使用合并或实现优化派生表和查看引用

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);
说明

在 8.0版本中,要求必须使⽤括号,MySQL之前的版本可能允许这样的语句不带括号。

相关文档

What Is New in MySQL 8.0

Changes in MySQL 8.0

准备安装进行升级

升级到MySQL 8.0?这是你需要知道的...

MySQL官方5.6、5.7、8.0版本差异比较: