升级概述
为什么选择升级到PolarDB MySQL 8.0?
PolarDB MySQL 8.0.1 (基于官方MySQL 8.0.13内核版本)发布于2019-12-03和PolarDB MySQL 8.0.2(基于官方MySQL 8.0.18内核版本)发布于2020-07-22*,增强了诸多卓越的架构增强和内核能力,为业务提供更灵活的技术解决方案和强大收益的性能提升,主要包括:
-
Serverless :Serverless数据库能够使得数据库集群资源随客户业务负载动态弹降,将客户从复杂的业务资源评估和运维工作中解放出来。
-
多主集群(库表) :在一个集群中通过多个主节点来实现从一写多读架构到多写多读架构的升级,主要面向SaaS多租户、游戏、电商等高并发读写的应用场景。
-
弹性并行查询(Elastic Parallel Query) :弹性并行查询(Elastic Parallel Query,ePQ)目前支持单机并行和多机并行*两种并行引擎,单机并行引擎等效于原有的并行查询,多机并行引擎支持集群内跨节点的自适应弹性调度*。
-
列存索引(IMCI) :面向OLAP场景大数据量复杂查询。通过列存索引,PolarDB MySQL实现了一体化的实时事务处理和实时数据分析的能力,成为一站式HTAP数据库产品解决方案。通过一套数据库系统,即可满足业务的OLTP及OLAP需求。
-
高压缩引擎(X-Engine):阿里巴巴自研的基于LSM-tree架构的存储引擎X-Engine提供了强大的数据压缩能力,满足了归档数据库低存储成本的要求。通过LSM-Tree(Log-Structured Merge-Tree)层次化架构和Zstandard(ZSTD)压缩算法实现了更高的数据压缩率,对比使用InnoDB作为存储引擎,最高可节省70%的存储空间。
-
分区表增强:支持更多分区功能增强(全二级分区类型支持、Interval Range分区、List Default Hash分区、异构分区、部分分区索引、全局二级索引等),性能改进(分区MDL锁、动态剪枝、Partition-Wise连接等)帮助客户解决大表性能、运维和管理。
-
冷数据归档:为了降低数据存储成本,PolarDB for MySQL支持将低频使用的冷数据归档到OSS对象存储中,支持冷热数据管理语法和存储过程方式。
-
DDL增强优化:支持并行DDL、秒级加字段、DDL预读、DDL多路归并排序、DDL异步IO、非阻塞DDL等增强了DDL的性能、稳定性和易用性。
-
事务系统增强: 全新的事务系统PolarTrans, 它利用提交时间戳技术CTS对高并发在线交易场景进行了优化,可以有效提升数据库的读写性能;同时PolarTrans利用现有的网络基础设施资源,与RDMA技术深度结合,推出高性能集群强一致性读SCC功能。SCC可以确保集群任何RW和RO节点都可以提供写后读的强一致性,通过对强一致性读请求进行RO分流,有效降低了RW节点的负载。在OLTP场景下,极大的提升了集群的整体吞吐能力。
-
SQL优化 :包括利用Window Function和Group By Aggregation对子查询解关联;通过CBQT组件(Cost Based Query Transformation)实现基于代价的查询变换,从而大幅提升复杂查询的执行效率;Limit Offset下推、谓词完全下推、 扫描完全下推(FastTraverse)和针对 HashJoin的Bloom Filter下推能力;Partial Result Cache(简称PTRC)功能来缓存查询语句中算子的中间结果集,来减少这些复杂算子的重复计算,以此来提升查询性能。
-
性能监控增强: Performance Agent是PolarDB提供的一种更加便捷的性能数据统计方案。通过PolarDB MySQL引擎插件的方式,实现PolarDB MySQL引擎集群中的节点内部各项性能数据的采集与统计。SQL Trace功能,用于跟踪SQL语句的执行信息,如:执行计划和执行统计信息(包括扫描行数、执行时间等)。可以帮助您快速地发现因执行计划变更而引发的性能变化,并统计当前集群中占用内存最多的查询语句。
另外,PolarDB MySQL 8.0.x版本还受益于官方从各个方面带来的令人兴奋的能力,详细参考《What’s New in MySQL 8.0》:
-
SQL全面增强 :支持窗口函数(Window functions), 公共表表达式( Common Table Expressions) , 优化并发SELECT ... FOR UPDATE的NOWAIT和SKIP LOCKED, 降序索引(Descending Indexes), Grouping函数, 正则表达式函数(Regular Expressions), 字符集增强(Character Sets), 代价模型增强(Cost Model), 直方图(Histograms),哈希连接(Hash Join)*,横向派生表(LATERAL),[NOT] IN/EXISTS子查询转换增强*,EXPLAIN ANALYZE*, 索引级别的优化器HINT ,派生表条件下推*
-
TempTable临时表内存引擎 :代替MEMORY引擎,更高效的支持VARCHAR和VARBINARY类型。
-
支持JSON数据* :JSON数据存储、JSON函数、改进排序和部分更新
-
支持GIS数据 :空间数据存储、空间类型、空间函数和空间索引
-
可靠性(Reliability) :基于InnoDB存储的元数据管理和事务性的数据字典改进,使得DDL成为操作和灾难恢复保证安全。
-
可观测性(Observability) : 显著增强了Performance Schema,Information Schema,配置变量和错误日志。
-
易于运维(Manageability) :支持Undo tablespace管理,支持instant DDL,极大缩短了一些常见DDL的操作。
-
安全(Security) 改进了OpenSSL,增加了新的默认认证方式,SQL角色等等。
-
性能(Performance) InnoDB显著的增进了Read/Write负载、IO bound负载, 和高竞争的热点(hot spot)负载。
预检验
PolarDB MySQL 5.6/MySQL 5.6 向 8.0 升级过程中,经常遇到的问题主要是性能问题、语法兼容性问题,以及周边组件是否的支持,查询的性能问题一般是由于优化器升级导致执行计划有变,此类问题需要对性能低下的语句进行针对性的性能优化,但性能问题基本不会引发业务报错以及代码的改写问题,此类问题不在本文讨论范围之内。
本文主要讨论真实的兼容性问题,此类问题需要在数据库升级过程中,对代码做出对应的更新或环境配置的更改,引发原因主要是版本升级后一些语法的变化以及特性的更新、移除。预检验主要提供一个简要清单来帮助用户在升级前能够更好的了解升级过程中可能注意的问题,如果遇到下列问题,可以到版本升级详细说明章节进行操作和检查。
-
确保触发器Triggers没有丢失或者空的definer或无效的内容。
-
确保只有InnoDB引擎的分区表。
-
确保没有和MySQL 5.6的系统数据库没有和MySQL 8.0的新增INNODB_开头的词典表名冲突。
-
确保不依赖于INFORMATION_SCHEMA下的GLOBAL|LOCAL]_[VARIABLES|STATUS]表
-
确保sql_mode中不使用废弃的变量设置。
-
确保表或存储过程单个ENUM或者SET 列元素的长度不得超过 255 个字符或 1020 个字节。
-
确保表分区不在共享InnoDB tablespaces表空间。
-
确保查询SQL中的GROUP BY不带有 ASC or DESC 。
-
确保外键约束名字不超过64字符。
-
为了增强Unicode的支持,考虑将使用utf8mb3字符集(已废弃)的对象改为utf8mb4字符集。另外,同样也需要考虑使用utf8mb4代替utf8,因为utf8是utf8mb3字符集的别名。更多信息参考 The utf8mb3 character set (3-byte UTF-8 unicode encoding) 。
如果上述内容确保没有存在,可以跳过下面章节进行升级,请参考《PolarDB for MySQL引擎大版本一键升级》。注意:升级前一定要进行备份,以避免升级过程可能遇到的其他问题。另外,达摩院的DAS团队还推出了智能压测能力,方便客户对新升级实例进行流量回放的压力测试,详细可以了解《智能数据库DAS之智能压测技术》。
版本升级详细说明
配置兼容性
引擎和分区表兼容
有关将MyISAM 表转换为 的信息InnoDB,请参阅 第“将表从 MyISAM 转换为 InnoDB”。在PolarDB MySQL 8.0中,将导致使用没有此类型支持的存储引擎分区表创建语句失败并出现错误 ( ER_CHECK_NOT_IMPLEMENTED )。
PolarDB MySQL 存储引擎现在负责提供自己的分区处理程序,并且PolarDB MySQL 服务器不再提供通用引擎分区支持。 InnoDB是唯一提供 PolarDB MySQL 8.0 支持的本机分区处理程序的存储引擎。必须在升级服务器之前InnoDB更改使用任何其他存储引擎的分区表将其转换为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引擎或删除分区:
<mysql> ALTER TABLE part ENGINE = INNODB;
Query OK, 0 rows affected (0.09 sec)
OR
<mysql> ALTER TABLE part REMOVE PARTITIONING;
Query OK, 0 rows affected (0.06 sec)
如果使用 mysqldump从在 MySQL 5.6(或更早版本)中创建的转储文件将数据库导入PolarDB MySQL 8.0 服务器,则必须确保创建分区表的任何语句都不会同时指定不受支持的存储引擎,方法是删除对分区的任何引用,或通过将存储引擎指定为 InnoDB或允许将其设置为 InnoDB默认值。“为升级准备安装”中给出的过程描述了如何识别在升级到 MySQL 8.0 之前必须更改的分区表。有关详细信息,请参阅“与存储引擎相关的分区限制”。
字符集&排序规则兼容
官方版本 8.0 默认字段集改为 utf8mb4,MySQL/PolarDB MySQL 8.0 默认字符集为了兼容性目前默认 character_set_server 均为 utf8,可以按业务需求调整,为了改进 Unicode 支持,请考虑将使用该字符集的对象转换utf8mb3为使用该utf8mb4字符集。不推荐使用utf8mb3字符集。另外,考虑使用utf8mb4字符集引用而不是 utf8,因为当前 utf8是utf8mb3字符集的别名。有关详细信息,请参阅 utf8mb3 字符集(3 字节 UTF-8 unicode 编码)在 MySQL 文档中。
官方MySQL版本 8.0 新增了 default_collation_for_utf8mb4 参数,此参数的作用是在字符集为 utf8mb4 时,默认排序规则,默认值为 utf8mb4_0900_ai_ci,官方文档注明只是为MySQL Replication使用的内部参数,所以建议如果没有从低版本同步过程中遇到Illegal mix of collations错误前不建议修改该默认值为utf8mb4_general_ci/utf8_general_ci。
utf8mb4_unicode_ci 是基于官方Unicode的规则来做通用的排序和比较,准确度高,但比对速度稍慢。
utf8mb4_general_ci 是精简集合的排序规则,目的是提供简化的一个设计来加快速度,虽然没有去遵循Unicode的规则,但是结果在相同情况下是符合预期的。
排序规则和字符集不同,它之和排序和比较有关系,其中ai指的是口音不敏感。也就是说,排序时e,è,é,ê和ë之间没有区别, ci表示不区分大小写。也就是说,排序时p和P之间没有区别。
注意事项
-
比如在 8.0向低版本反向同步或者 dump 同步时,有可能导致脚本不支持,
-
比较容易在 DTS 低版本与高版本双向同步场景下出现,需要使用5.6默认的排序字符集,否则DTS反向同步的时候会有异常。
-
创建视图可能会报错Illegal 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 里面指定 column,table, db 的 collation 都不会起作用。 如果一定要用 convert,可以明确带上 collation,类似这样写 (convert(a.c1 using utf8mb4) collate utf8mb4_general_ci) = b.c1
-
修改 default_collation_for_utf8mb4 默认值如 utf8mb4_unicode_ci,会导致SYS库无法读取及其相关函数无法读取,报错“Illegal mix of collations (utf8mb4_unicode_ci,IMPLICIT) and (utf8mb4_0900_ai_ci,IMPLICIT) for operation '='”,也会导致会导致从PolarDB 8.0.1升级到PolarDB 8.0.2失败,因为该参数是8.0的新参数,所以建议不要修改该参数,如果必须使用其他值,请升级前提工单重置为默认 utf8mb4_0900_ai_ci 升级后修改回来。
参数兼容
lower_case_table_names
从 MySQL 8.0.11 开始,禁止 lower_case_table_names 使用与服务器初始化时使用的设置不同的设置来启动服务器。该限制是必要的,因为各种数据字典表字段使用的排序规则基于 lower_case_table_names 服务器初始化时定义的设置,并且使用不同的设置重新启动服务器会在标识符的排序和比较方式方面引入不一致。实例区分大小写在 8.0 版本中,无法在初始化完成后再次更改,需要在购买PolarDB MySQL 8.0实例时选定。
sql_mode
为避免PolarDB MySQL 8.0 上的启动失败,请NO_AUTO_CREATE_USER从 sql_modeMySQL 选项文件中的系统变量设置中删除任何实例。sql_mode您的系统变量设置中不得定义过时的 SQL 模式,sql_mode 会引起许多行为的不同,在版本升级时需要确认对齐。取消如下配置项:
DB2, MAXDB, MSSQL, MYSQL323, MYSQL40, ORACLE, POSTGRESQL, NO_FIELD_OPTIONS , NO_KEY_OPTIONS, NO_TABLE_OPTIONS
以上配置项大多为组合配置,需要注意是否有不一致的 mode 选项,如: sql_mode=TRADITIONAL等于配置如下项:
STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_ENGINE_SUBSTITUTION.
在 5.6 默认配置时,sql_mode=TRADITIONAL等于配置如下项:
STRICT_TRANS_TABLES, STRICT_ALL_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE,
ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, and NO_ENGINE_SUBSTITUTION.
可以看到 5.6 多了 NO_AUTO_CREATE_USER 项,但其实 8.0 已经禁止使用 GRANT 语句隐式创建账号,5.6 虽然添加了NO_AUTO_CREATE_USER 选项,但在指定 identified by 时,同样可以使用 GRANT 创建账号。
如果您发现 ONLY_FULL_GROUP_BY启用导致对现有应用程序的查询被拒绝,则这些操作中的任何一个都应该恢复操作:
例如,当描述不是的一部分GROUP BY,并且没有应用聚合函数(例如MIN或MAX)时,就会发生这种情况。
以前的行为:
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)
PolarDB MySQL 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 nonaggregated column 'invoice_line_items.description' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
INFORMATION_SCHEMA系统和状态变量信息的表
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
视图/表以及关键词
InnoDB相关视图
INFORMATION_SCHEMA基于InnoDB系统表的视图被数据字典表的内部系统视图取代。受影响 InnoDB INFORMATION_SCHEMA的视图已重命名:,如果系统应用中有直接访问 InnoDB 相关视图,需要确认应用中是否已经修改。
重命名的 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 |
在 5.6 版本中不能存在 8.0 中新增的同名视图,在 5.6 实例中执行如下语句,如果有返回则需要确认如何对此类表进行处理,此项检查建议在自建实例上云升级时执行
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',
'st_spatial_reference_systems',
'table_partition_values',
'table_partitions',
'table_stats',
'tables',
'tablespace_files',
'tablespaces',
'triggers',
'view_routine_usage',
'view_table_usage'
);
Suppose
+--------------+------------+
| TABLE_SCHEMA | TABLE_NAME |
+--------------+------------+
| mysql | catalogs |
+--------------+------------+
1 row in set (0.00 sec)
因此,此类用户表应在升级前重命名或删除:
mysql>ALTER TABLE catalogs RENAME user_catalogs;
Query OK, 0 rows affected (0.05 sec)
OR
mysql> DROP TABLE catalogs;
Query OK, 0 rows affected (0.06 sec)
视图兼容
在 MySQL 8.0 之前,用户可以创建具有最多 255 个字符的显式列名的视图。为遵守列名的最大长度,MySQL 8.0 不支持显式列名超过 64 个字符的视图。目前这些视图只能通过 在 MySQL 5.6 中执行SHOW CREATE VIEW来识别。
mysql> SHOW CREATE VIEW v1;
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| View | Create View | character_set_client | collation_connection |
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
| v1 | CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select 1 AS `a123456789012345678901234567890123456789012345678901234567890123456789` | utf8 | utf8_general_ci |
+------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------+----------------------+
1 row in set (0.00 sec
应在升级PolarDB MySQL 8.0前修改视图名字
mysql> ALTER VIEW v1(a12345678901234567890) AS SELECT 1;
系统表兼容
mysql.user系统表的 Password列 mysql.user在 MySQL 5.7.6 之后及8.0中被删除。所有凭据都存储在该 authentication_string列中,包括以前存储在该Password 列中的那些。
INNODB表兼容
DYNAMIC替换 COMPACT为InnoDB表的隐式默认行格式。一个新的配置选项,innodb_default_row_format指定默认的InnoDB行格式。允许DYNAMIC的值包括(默认值)COMPACT、 和 REDUNDANT。升级到PolarDB MySQL 8.0 后,您创建的任何新表都使用定义的行格式,innodb_default_row_format 除非您明确定义行格式 ( ROW_FORMAT)。对于未显式定义 ROW_FORMAT选项或使用 的现有表ROW_FORMAT=DEFAULT,任何重建表的操作也会默默地将表的行格式更改为定义的格式 innodb_default_row_format。否则,现有表将保留其当前行格式设置。有关详细信息,请参阅定义表的行格式。
类型兼容
枚举和集合类型兼容
表或存储过程的单个ENUM或SET列元素的长度不得超过 255 个字符或 1020 个字节。
YEAR类型
YEAR(2) 类型废弃,需要用YEAR(4) 替换。
类型数据插入兼容
-
将负值插入无符号列会报错
创建一个包含无符号列的表:
CREATE TABLE test (id int unsigned);
插入一个负值,以前的行为:
INSERT INTO test VALUES (-1);
Query OK, 1 row affected, 1 warning (0.01 sec)
PolarDB MySQL 8.0的行为:
INSERT INTO test VALUES (-1);
ERROR 1264 (22003): Out of range value for column 'a' at row 1
-
除以零会报错
创建测试表:
CREATE TABLE test2 (id int unsigned);
尝试除以零,以前的行为:
INSERT INTO test2 VALUES (0/0);
Query OK, 1 row affected (0.01 sec)
PolarDB MySQL 8.0的行为:
INSERT INTO test2 VALUES (0/0);
ERROR 1365 (22012): Division by 0
-
字符超长插入报错
将 20 个字符的字符串插入 10 个字符的列会报错,创建一个包含 10 个字符的列的表:
CREATE TABLE test3 (a varchar(10));
尝试插入更长的字符串,以前的行为:
INSERT INTO test3 VALUES ('abcdefghijklmnopqrstuvwxyz');
Query OK, 1 row affected, 1 warning (0.00 sec)
PolarDB MySQL 8.0的行为:
INSERT INTO test3 VALUES ('abcdefghijklmnopqrstuvwxyz');
ERROR 1406 (22001): Data too long for column 'a' at row 1
-
非标准零日期插入日期时间列会报错
创建一个包含日期时间列的表:
CREATE TABLE test3 (a datetime);
插入0000-00-00 00:00:00,以前的行为:
INSERT INTO test3 VALUES ('0000-00-00 00:00:00');
Query OK, 1 row affected, 1 warning (0.00 sec)
PolarDB MySQL 8.0的行为:
INSERT INTO test3 VALUES ('0000-00-00 00:00:00');
ERROR 1292 (22007): Incorrect datetime value: '0000-00-00 00:00:00' for column 'a' at row 1
5.x 旧式类型兼容
旧式decimal、旧式varchar、旧式TIME/DATETIME 和 TIMESTAMP类型等数据类型分别在 MySQL 5.1 、 MySQL 5.0 和 MySQL 5.6 中已过时,由于二进制升级而一直持续到 MySQL 5.6 将不被支持在 MySQL 8.0 中。这些表可以通过在升级前在 MySQL 5.6 中运行CHECK TABLE…FOR UPGRADE 或带有check-upgrade选项的 mysqlcheck 来识别。此外,使用旧式T IME/DATETIME 和 TIMESTAMP的表可以通过启用会话变量来识别,参考"How to Easily Identify Tables With Temporal Types in Old Format!"。
mysql> check table 41_decimal for upgrade;
+-----------------+-------+----------+-------------------------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+-----------------+-------+----------+-------------------------------------------------------------------------------------+
| test.41_decimal | check | error | Table upgrade required for `test`.`41_decimal`. Please dump/reload table to fix it! |
+-----------------+-------+----------+-------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> check table 55_temporal for upgrade;
+------------------+-------+----------+------------------------------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+------------------+-------+----------+------------------------------------------------------------------------------------------+
| test.55_temporal | check | error | Table upgrade required. Please do "REPAIR TABLE `55_temporal`" or dump/reload to fix it! |
+------------------+-------+----------+------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
nisha@nisha-PORTEGE-Z30-A:~/workspace1/mysql-5.6/dbg-5.6/client/mysqlcheck --user=root --socket=/home/nisha/workspace1/mysql-5.6/dbg-5.6/data/mysql.sock --databases test --check-upgrade
error : Table upgrade required for `test`.`41_decimal`. Please dump/reload table to fix it!
test.55_temporal
error : Table upgrade required. Please do "REPAIR TABLE `55_temporal`" or dump/reload to fix it!
test.child OK
test.geom OK
test.jemp OK
test.jemp_myisam OK
test.opening_lines OK
test.parent OK
test.t_blackhole OK
test.t_blob OK
test.t_blob_myisam OK
test.t_compressed OK
test.t_compressed2 OK
test.t_compressed3 OK
test.t_dynamic OK
test.t_gen_stored OK
test.t_gen_stored_myisam OK
test.t_gen_stored_myisam2 OK
test.t_index OK
test.t_json OK
test.t_myisam_compressed OK
test.t_myisam_compressed2 OK
test.t_myisam_compressed3 OK
test.t_sc~!@#$%^&*( OK
test.vt2 OK
使用此类数据类型的表无法升级,应通过REPAIR TABLE 修复,并为旧式 varchar/旧式 decimal 转储/重新加载:
mysql> REPAIR TABLE 55_temporal;
+------------------+--------+----------+-------------------------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+------------------+--------+----------+-------------------------------------------------------------------------------------+
| test.55_temporal | repair | Note | TIME/TIMESTAMP/DATETIME columns of old format have been upgraded to the new format. |
| test.55_temporal | repair | status | OK |
+------------------+--------+----------+-------------------------------------------------------------------------------------+
2 rows in set (0.01 sec)
mysql>
Dump:
$./client/mysqldump --databases test --socket=5.6/data/mysql.sock --user=root>test.sql
Restore:
mysql> .\ test.sql
关键词与保留字
PolarDB MySQL 8.0 可以通过 information_schema.KEYWORDS 表查看当前版本的关键词与保留字,不得有关键字或保留字违规。PolarDB MySQL 8.0 中可能保留了一些以前未保留的关键字,有关详细信息,请参阅关键字和保留字在 MySQL 文档中。建议所有自定义内容(表名、字段名、函数 名)等等全部要规避使用。除此之外, KICKOUT 是 PolarDB MySQL 8.0 的保留关键字。因此,若您已经在 MySQL 5.6 或开源 MySQL 8.0 上使用该关键字作为对象名称(如表名、字段名、存储过程名等),在迁移到 PolarDB MySQL 8.0 前,请您先修改对象名称避免使用该关键字。否则迁移时,将会出现错误码为1064 的语法报错。
补充关键词(RDS)
有业务会使用自建序列号生成器函数 nextval、currval,这两个关键词在 RDS MySQL 8.0 中为保留字,需要改写函数名称或者直接使用 RDS 提供的 seq 功能
CREATE sequence s START WITH 1 minvalue 1 MAXVALUE 9999999 increment BY 1 CACHE 20 cycle;
SELECT nextval(s),currval(s);
SQL兼容性
GRANT授权
在 MySQL 8.0.11 中,删除了与帐户管理相关的几个已弃用的功能,例如使用 GRANT语句修改用户帐户的非特权特性。例如
GRANT REPLICATION CLIENT ON *.* TO 'odps'@'%'; You are not allowed to create a user with GRANT 需要改为两步建
create user;
grant privielges;
不支持 GROUP BY ASC/DESC 写法
从 MySQL 8.0.13 开始,已删除不推荐使用的子句ASC或 DESC限定符GROUP BY以前依赖GROUP BY排序的查询可能会产生与以前的 MySQL 版本不同的结果。要生成给定的排序顺序,请提供一个ORDER BY子句。
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
外键约束定义
在 MySQL 5.6 中,定义FOREIGN KEY定义的InnoDB 不带CONSTRAINT 的关键字或者指定外键约束名称不得超过 64 个字符。在 MySQL 8.0 之前的版本中,当用户未明确指定时,InnoDB 通过在表名后附加 '_ibfk_X' 来自动生成外键约束名称,其中 X 是一个数字。如果表名是多字节 64 个字符,例如下面示例中使用的西里尔表名 'имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк',则自动生成的外键约束名称超过 64 个字符。应通过删除约束并通过确保外键约束名称不超过 64 个字符来添加具有显式约束名称的约束来更改这些表。
mysql> ALTER TABLE `имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк` DROP FOREIGN KEY `имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк_ibfk_1`;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> ALTER TABLE `имя_базы_в_кодировке_утф8_длиной_больше_чем_45имя_азы_в_кодировк` ADD CONSTRAINT FOREIGN KEY FK1 (fld2) REFERENCES t1(fld1);
Query OK, 0 rows affected (0.13 sec)
Records: 0 Duplicates: 0 Warnings: 0
触发器兼容
MySQL 5.0.17 之前的 CREATE TRIGGER 不支持 definer 属性。此类具有缺失/空定义器属性或无效创建上下文(即 character_set_client、collation_collection、数据库排序规则属性)的触发器定义 一直存在到 MySQL 5.6 无法升级。这些触发器可以通过在 MySQL 5.6 中运行带有检查升级选项的mysqlcheck或CHECK TABLE来识别。
$./client/mysqlcheck --user=root --socket=5.6/data/mysql.sock --databases triggers --check-upgrade
triggers.t1
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_insert'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'t1_bi'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert_1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_insert_3'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_update_3'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_before_update'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg_t1_after_update'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
Warning : No definer attribute for trigger 'triggers'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
status : OK
triggers.t2 OK
mysql> check table t1;
+-------------+-------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Op | Msg_type | Msg_text |
+-------------+-------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_before_insert'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'t1_bi'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_after_insert_1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_after_insert'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_after_insert_3'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_before_update_3'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_before_update'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg_t1_after_update'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | Warning | No definer attribute for trigger 'triggers'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger. |
| triggers.t1 | check | status | OK |
+-------------+-------+----------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
10 rows in set (0.01 sec)
mysql> select definer, trigger_name from INFORMATION_SCHEMA.TRIGGERS where definer='';
+---------+------------------------+
| definer | trigger_name |
+---------+------------------------+
| | trg_t1_before_insert |
| | t1_bi |
| | trg_t1_after_insert_1 |
| | trg_t1_after_insert |
| | trg_t1_after_insert_3 |
| | trg_t1_before_update_3 |
| | trg_t1_before_update |
| | trg_t1_after_update |
| | trg1 |
+---------+------------------------+
9 rows in set (0.02 sec)
mysql>
应转储/重新加载此类触发器以解决问题:
Dump:
$./client/mysqldump --databases triggers --socket=5.6/data/mysql.sock --user=root>triggers.sql
Restore:
mysql> .\ triggers.sql
并行查询导致的排序问题
PolarDB MySQL 8.0开始支持并行查询能力,并行扫描由于随机访问数据导致MySQL默认串行扫描的顺序每次会随机变化,尤其涉及到分页的SQL,需要要生成给定的排序顺序,请提供一个ORDER BY子句保证顺序。
子查询问题
子查询中的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
派生表问题
优化器现在以一致的方式处理子句中的派生表和视图, FROM以更好地避免不必要的物化,并允许使用产生更有效执行计划的下推条件。但是,在 PolarDB MySQL 8.0 中,以及对于修改表之类的语句,DELETE对 UPDATE先前实现的派生表使用合并策略可能会导致 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
当将派生表合并到外部查询块中会导致从表中选择和修改表的语句时发生错误。(物化不会导致问题,因为它实际上将派生表转换为单独的表。)避免此错误的解决方法是在执行语句之前禁用系统变量的derived_merge 标志 :optimizer_switch
SET optimizer_switch = 'derived_merge=off';
该derived_merge标志控制优化器是否尝试将FROM子句中的子查询和视图合并到外部查询块中,假设没有其他规则阻止合并。默认情况下,该标志是on启用合并。设置标志以off 防止合并并避免刚刚描述的错误。有关更多信息,请参阅 第 8.2.2.4 节,“使用合并或实现优化派生表和查看引用”。
-
在 UNION 语句中,要应用 ORDER BY 或 LIMIT 应用于个人 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 可能允许这样的语句不带括号。在 PolarDB MySQL 8.0 中,强制要求使用括号。
GET_LOCK函数兼容
该 GET_LOCK()功能在 MySQL 5.7.5 中使用元数据锁定 (MDL) 子系统重新实现,并且其功能已得到扩展:
-
以前, GET_LOCK() 一次只允许获取一个命名锁,第二次 GET_LOCK() 调用释放任何现有锁。现在 GET_LOCK() 允许同时获取多个命名锁,并且不会释放现有锁。
依赖于GET_LOCK()释放任何先前锁的行为的应用程序必须针对新行为进行修改。
-
获取多个锁的能力会在客户端之间引入死锁的可能性。MDL 子系统检测死锁并 ER_USER_LOCK_DEADLOCK 在发生这种情况时返回错误。
-
MDL 子系统对锁名称施加了 64 个字符的限制,因此该限制现在也适用于命名锁。以前,没有强制执行长度限制。
-
获取的锁 GET_LOCK() 现在出现在 Performance Schema metadata_locks 表中。列 OBJECT_TYPE 说 USER LEVEL LOCK , OBJECT_NAME 列表示锁名。
-
一个新功能, RELEASE_ALL_LOCKS() 允许一次释放所有获得的命名锁。
有关更多信息,请参阅 第 12.15 节,“锁定功能”。
其他
客户端兼容
对于 java 应用来说,MySQL Connector/J 升级到 5.1.46 以上版本 到 8.0.8 能够连接到 MySQL 8.0 服务器,但使用 caching_sha2_password. (连接帐户需要连接器/J 8.0.9 或更高版本 caching_sha2_password。)。
dataworks由于未在数据源中设置utf8可能出错,建议修改数据库名,并和RDS的设置一致。在PolarDB MySQL的连接串增加:characterEncoding=utf8&com.mysql.jdbc.faultInjection.serverCharsetIndex=
Unknown system variable 'tx_read_only'
8.0 中已经删除 tx_read_only 环境变更,需要使用 transaction_read_only 代替
select @@tx_read_only
需要改为
select @@transaction_read_only
升级检查器
官方目前提供了8.0升级检查器,目前PolarDB MySQL未支持,自建库升级前请参考检查器。
参考文档
-
官方56/57/80差异