【MySQL 8.0】MySQL 8.0新特性介绍与升级MySQL 8.0

TangLu MySQL 2021-12-21 1307 0

一、MySQL 8.0主要新特性

截至2023年12月,MySQL官方发布的稳定版为8.0.35,另有一个MySQL8.2为创新版,所以暂不做考虑


· 快速新增/删除列

虽然 MySQL 在8.0 以前就已经支持通过 Online DDL实现DDL操作不阻塞DML操作,但在对一些大表进行DDL操作时仍然需要等待很长时间,这样就面临从库延时、耗时过久或者因为DDL操作而创建的临时表产生的资源开销问题。在8.0.12版本开始支持了instant add new column特性,在DDL执行过程中不需要修改存储数据,只用修改存储在系统表中的结构,这样就避免了最耗时的rebuild和apply row log过程,因此效率非常高。经过实际测试,在同服务器下对一个500W的表进行新增或删除字段操作,MySQL 5.7 耗时接近6分钟,MySQL 8.0.35 下仅需要5秒左右


· 自增列持久化

在8.0之前的版本中,如果在自增主键AUTO_INCREMENT值大于max(primary key) + 1 的时候重启了服务,会重置AUTO_INCREMENT的值为max(primary key) + 1。如果主键发生过删除行为,并且对主键列有过更新操作,会触发BUG导致主键冲突。而8.0以后AUTO_INCREMENT会进行持久化存储,不管是删除还是更新操作都会记录到文件中,不会再有这种情况

#5.7 BUG复现过程

#t1表有3行数据
select * from t1  ;
id   c1 
1   test1
2   test2
3   test3

#此时删除AUTO_INCREMENT为3的数据
delete from t1 where id = 3;

select * from t1  ;
id   c1 
1   test1
2   test2

#重启服务后插入新数据
insert into t1(c1) values('test4') ;

#查看新插入的数据,AUTO_INCREMENT将回退为3
select * from t1  ;
id   c1 
1   test1
2   test2
3   test4

#手动修改一条数数据,用到了AUTO_INCREMENT为5
update t1 set id = 5 where c1 = "test1";

select * from t1 ; 
id   c1 
2   test2
3   test4
5   test1

#继续插入数据
insert into t(c1) values('test5') ;

select * from t1  ;
id   c1 
2   test2
3   test4
4   test5
5   test1

#继续插入数据会出现主键冲突,因为mysql此时自动生成的AUTO_INCREMENT为5
insert into t(c1) values('test6') ;


· 新增函数索引

MySQL 8.0.13之前的版本中如果在查询中使用了函数,会导致索引失效。而从MySQL 8.0.13开始,支持在索引中使用函数或表达式的值。函数索引基于虚拟列功能实现,该列的值都是通过前面的函数或者表达式计算出来的,当使用函数索引的时候就会使用这个计算后的列作为索引

#在未创建函数索引的列上使用函数,不会用到索引
EXPLAIN SELECT * FROM `t_audit_info` WHERE DATE(create_time) > '2021-11-21';

#在t3表的create_time列创建一个使用了DATE函数的索引
ALTER TABLE t3 ADD INDEX idx_create_time_func((DATE(create_time)));

#再次执行查询可以使用索引
EXPLAIN SELECT * FROM `t_audit_info` WHERE DATE(create_time) > '2021-11-21';


· 新增降序索引

倒叙索引的语法在5.7的时候虽然可以使用,但是不会真正生效,添加索引后再查看表结构会发现依然使用的是升序索引。降序索引从8.0 正式支持使用,在对多个字段进行排序时,不同的字段的排序规则可能不同,通过倒叙索引可以提高反向扫描的效率

#创建一个包含降序索引的表格
create table t1(
c1 int,
c2 int,
index idx_c1_c2(c1,c2 desc)
);

#下列包含降序查询的语句可以直接使用索引,执行计划中没有using filesort而是using index
select * from t1 order by c1,c2 desc;


· 新增隐藏索引(不可见索引)

使用invisible关键词可以将索引设置为隐藏索引,查询语句不会使用被隐藏的索引(即便使用force index也不会使用)。该特性一般用于对需要删除的索引进行观察,当索引被隐藏后如果不会对业务带来影响那么就可以正式删除,这样可以减少对大表误删索引后再添加带来的性能成本。需要注意的是索引被隐藏后,如果数据发生更新,索引依然会被更新,长期被隐藏的索引一定要记得删除

creata table t1(
c1 int,
c2 int,
index idx_c1(c1),
index idx_c2(c2) invisible
);

#也可以修改原索引不可见
alter table t1 alter index idx_c1 invisiable;

#不会使用索引
select * from t1 where c2=1;


· Innodb存储引擎支持跳过锁等待

FOR UPDATE语句支持添加NOWAIT、SKIP LOCKED语句。NOWAIT表示如果查询行已经被加锁,那么直接报错返回,不用等待锁超时;SKIP LOCKED可以跳过被锁的行,返回其他没有锁定的记录

select * from t1 for update skip locked;


· GROUP BY语句不再进行隐式排序

在5.7的时候经过group by的字段会默认进行隐式排序,8.0开始需要显式加上order by字句,这个主要是考虑对其他数据库没有自动隐式排序进行兼容,语法更严谨

#5.7支持隐式排序时语法
select count(*) from t1 group by c2;

#5.7版本结果
count(*)        c2
1               10
2               50
1               80
1               100

#8.0版本结果
count(*)        c2
1               10
2               50
1               100
1               80

#8.0开始必须指定order by语句
select count(*) from t1 group by c2 order by c2;


· 新增innodb_dedicated_server自适应参数

该参数可以让InnoDB根据服务器内存自动调整innodb_buffer_pool、innodb_log_file_size等参数,尽可能的使用内存资源。该参数默认关闭,如果服务器上存在其他组件或者是多实例部署,不建议打开该功能

show variables like '%innodb_dedicated_server%';


· undo文件不再使用系统表空间

8.0 将为Undo log默认创建2个单独的表空间,不再使用系统表空间。Undo Log主要存储了回滚数据,是MySQL MVCC机制的根本。在MySQL 8以前这些回滚数据默认存储在了系统表空间ibdata1文件中(在5.7之前甚至无法分离出来)。在有大量并发事务或者大事务未提交的情况下会导致ibdata暴涨的问题,而这部分空间通常只有重启数据库\重建实例才能回收

801.jpg


· binlog日志过期时间可以精确到秒

在8.0之前通过expire_logs_day参数控制binlog的过期时间,8.0开始默认使用更为精确的binlog_expire_logs_seconds参数,expire_logs_day会在未来版本弃用


· DDL事务原子化

MySQL 8.0开始支持了更多的数据字典,元数据全部采用InnoDB引擎进行存储,不再存在.frm文件。因此也让DDL开始支持事务完整性,一个事务中如果提交了多个DDL,它们要么全部成功要么全部回滚,不再出现部分成功的情况


· 可在线持久化配置

MySQL 8.0通过PERSIST命令可以在线修改全局参数并持久化到配置文件中,在线修改的参数会保存到data/mysqld.auto.cnf(该配置文件优先级高于my.cnf),启动MySQL时会从该配置文件拉取配置

SET PERSIST innodb_lock_wait_timeout=15;


· 支持公共表表达式,即WITH语句(CTE,Common Table Expression)

可以将复杂的子查询提取出来,主查询中直接使用,降低子查询复杂度

WITH cte_name AS (
    SELECT ...
)
SELECT * FROM cte_name;

· 支持窗口函数和通用表达式(主要用于OLAP场景)

窗口函数可以在一组查询行上执行类似于聚合的操作,但是相比原有的聚合函数,它不会修改原有语句的输出结果,而是直接添加新的聚合字段进行展现,就像是对查询结果返回的窗口进行函数处理。窗口函数主要用于OLAP场景,比如处理复杂的报表、统计分析等

select name,sum(balance) from account_channel group by name;

#不再需要group by,聚合结果在每一行中展示
select name,channel,balance,sum(balance) over(partition by name) as sum_balance from account_channel;

 802.jpg


除了上述亮点特性以外,还有以下更新:

· 在官方测评中 MySQL 8.0 性能峰值几乎是5.7的两倍

· 调整默认字符集为utf8mb4

· 使用新的密码认证插件caching_sha2_password(替代原本的mysql_native_password)(客户端需要升级驱动),支持更高的密码策略,即便相同的密码加密后的密文也是不同的

· 重构SQL分析器,增强优化器和CBO特性

· 支持使用shutdown命令直接关闭服务

· 错误日志增加了不同错误的错误编号,方便查询

· 并行复制writeset机制,提升从库复制性能

· 支持创建系统级别或者用户级别资源组以限制SQL对服务器资源的占用

· 新增计算列功能,比如C列的数据是通过A列和B列计算后产生

· 增加CREATE TABLE ... SELECT的原子性和crash safe支持,解决了MGR架构下无法使用的问题

· 角色role功能

· 可并行写入redo log,提升大量事务写入时的性能

· 可在线调整redo log buffer和undo log相关设置

· 可针对单个会话SET_VAR设置变量,提升灵活性


二、升级8.0前的准备

1、先阅读官方What Is New In MySQL 8.0文档,关注被废弃的功能,避免配置文件中依然存在这些历史配置

2、需要考虑回滚方案

3、通过先升级从库的方式进行平稳过渡

4、升级前需要关注是否存在关键词兼容问题以及GROUP BY语句兼容问题,可以使用官方的检查工具

mysqlsh root:123456@192.168.1.101:3306 -e "util.checkForServerUpgrade();"

5、5.7版本支持直接升级8.0(5.6不支持),升级大版本前建议先把小版本升级到最新

6、建议升级方式采用逻辑备份+导入的方式


三、升级MySQL 8.0步骤

1、关闭当前MySQL

2、备份数据

3、使用新版本二进制包替换原版本

4、更改配置文件

5、启动服务,不需要mysql_upgrade,MySQL 8.0支持通过配置upgrade = AUTO参数来自动处理升级需要做的一切 

评论