MySQL8.0新特性

1. 默认字符集由latin1变为utf8mb4

在8.0版本之前,默认字符集为latin1,utf8指向的是utf8mb3,8.0版本默认字符集为utf8mb4,utf8默认指向的也是utf8mb4。
注:在Percona Server 8.0.15版本上测试,utf8仍然指向的是utf8mb3,与官方文档有出入。

Warning | 3719 | 'utf8' is currently an alias for the character set UTF8MB3, but will be an alias for UTF8MB4 in a future release. Please consider using UTF8MB4 in order to be unambiguous. |

2. MyISAM系统表全部换成InnoDB表

系统表全部换成事务型的innodb表,默认的MySQL实例将不包含任何MyISAM表,除非手动创建MyISAM表。

# MySQL 5.7
mysql>select distinct(ENGINE) from information_schema.tables;
+--------------------+
|ENGINE  |
+--------------------+
|MEMORY  |
|InnoDB  |
|MyISAM  |
|CSV  |
|PERFORMANCE_SCHEMA|
|NULL  |
+--------------------+
6rows inset (0.00sec)
# MySQL 8.0
mysql>select distinct(ENGINE) from information_schema.tables;
+--------------------+
|ENGINE  |
+--------------------+
|NULL  |
|InnoDB  |
|CSV  |
|PERFORMANCE_SCHEMA|
+--------------------+
4rows inset (0.00sec)

3. 自增变量持久化

在8.0之前的版本,自增主键AUTO_INCREMENT的值如果大于max(primary key)+1,在MySQL重启后,会重置AUTO_INCREMENT=max(primary key)+1,这种现象在某些情况下会导致业务主键冲突或者其他难以发现的问题。自增主键重启重置的问题很早就被发现(https://bugs.mysql.com/bug.php?id=199),一直到8.0才被解决,8.0版本将会对AUTO_INCREMENT值进行持久化,MySQL重启后,该值将不会改变。

4. DDL原子化

InnoDB表的DDL支持事务完整性,要么成功要么回滚,将DDL操作回滚日志写入到data dictionary 数据字典表mysql.innodb_ddl_log 中用于回滚操作,该表是隐藏的表,通过show tables无法看到。通过设置参数,可将ddl操作日志打印输出到mysql错误日志中。

mysql>set global log_error_verbosity=3;
mysql>set global innodb_print_ddl_logs=1;
mysql>create table t1(c int) engine=innodb;
 
# MySQL错误日志:
2019-06-26T11:25:25.817245+08:0044[Note] [MY-012473] [InnoDB] InnoDB:DDL log insert :[DDL record:DELETE SPACE, id=41, thread_id=44, space_id=6, old_file_path=./db/t1.ibd]
2019-06-26T11:25:25.817369+08:0044[Note] [MY-012478] [InnoDB] InnoDB:DDL log delete:by id 41
2019-06-26T11:25:25.819753+08:0044[Note] [MY-012477] [InnoDB] InnoDB:DDL log insert :[DDL record:REMOVE CACHE, id=42, thread_id=44, table_id=1063, new_file_path=db/t1]
2019-06-26T11:25:25.819796+08:0044[Note] [MY-012478] [InnoDB] InnoDB:DDL log delete:by id 42
2019-06-26T11:25:25.820556+08:0044[Note] [MY-012472] [InnoDB] InnoDB:DDL log insert :[DDL record:FREE, id=43, thread_id=44, space_id=6, index_id=140, page_no=4]
2019-06-26T11:25:25.820594+08:0044[Note] [MY-012478] [InnoDB] InnoDB:DDL log delete:by id 43
2019-06-26T11:25:25.825743+08:0044[Note] [MY-012485] [InnoDB] InnoDB:DDL log post ddl :begin forthread id:44
2019-06-26T11:25:25.825784+08:0044[Note] [MY-012486] [InnoDB] InnoDB:DDL log post ddl :end forthread id:44

来看另外一个例子,库里只有一个t1表,drop table t1,t2; 试图删除t1,t2两张表,在5.7中,执行报错,但是t1表被删除,在8.0中执行报错,但是t1表没有被删除,证明了8.0 DDL操作的原子性,要么全部成功,要么回滚。

# MySQL 5.7
mysql>show tables;
+---------------+
|Tables_in_db |
+---------------+
|t1  |
+---------------+
1row inset(0.00sec)
mysql>drop table t1, t2;
ERROR 1051(42S02): Unknown table 'db.t2'
mysql>show tables;
Empty set(0.00sec)
# MySQL 8.0
mysql>show tables;
+---------------+
|Tables_in_db |
+---------------+
|t1  |
+---------------+
1row inset(0.00sec)
mysql>drop table t1, t2;
ERROR 1051(42S02): Unknown table 'db.t2'
mysql>show tables;
+---------------+
|Tables_in_db |
+---------------+
|t1  |
+---------------+
1row inset(0.00sec)

5. 参数修改持久化

MySQL 8.0版本支持在线修改全局参数并持久化,通过加上PERSIST关键字,可以将修改的参数持久化到新的配置文件(mysqld-auto.cnf)中,重启MySQL时,可以从该配置文件获取到最新的配置参数。
例如执行:
set PERSIST expire_logs_days=10 ;
系统会在数据目录下生成一个包含json格式的mysqld-auto.cnf 的文件,格式化后如下所示,当my.cnf 和mysqld-auto.cnf 同时存在时,后者具有更高优先级。

{
  "Version":1,
  "mysql_server":{
  "expire_logs_days":{
  "Value":"10",
  "Metadata":{
  "Timestamp":1529657078851627,
  "User":"root",
  "Host":"localhost"
  }
  }
  }
}

6. 新增降序索引

MySQL在语法上很早就已经支持降序索引,但实际上创建的仍然是升序索引,如下MySQL 5.7 所示,c2字段降序,但是从show create table看c2仍然是升序。8.0可以看到,c2字段降序。

# MySQL 5.7
mysql>create table t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc));
Query OK, 0rows affected (0.03sec)
mysql>show create table t1\G
***************************1.row ***************************
  Table: t1
Create Table: CREATE TABLE `t1`(
  `c1`int(11) DEFAULT NULL,
  `c2`int(11) DEFAULT NULL,
  KEY `idx_c1_c2`(`c1`,`c2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1row in set (0.00sec)
# MySQL 8.0
mysql>create table t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc));
Query OK, 0rows affected (0.06sec)
mysql>show create table t1\G
***************************1.row ***************************
  Table: t1
Create Table: CREATE TABLE `t1`(
  `c1`int(11) DEFAULT NULL,
  `c2`int(11) DEFAULT NULL,
  KEY `idx_c1_c2`(`c1`,`c2`DESC)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
1row in set (0.00sec)

再来看看降序索引在执行计划中的表现,在t1表插入10万条随机数据,查看select * from t1 order by c1 , c2 desc;的执行计划。从执行计划上可以看出,5.7的扫描数100113远远大于8.0的5行,并且使用了filesort。

DELIMITER;;
CREATEPROCEDUREtest_insert ()
BEGIN
DECLAREi INTDEFAULT1;
WHILEi<100000
DO
insert into t1 select rand()*100000, rand()*100000;
SETi=i+1;
ENDWHILE;
commit;
END;;
DELIMITER;
CALLtest_insert();
 
# MySQL 5.7
mysql>explain select *from t1 order by c1 , c2 desc limit 5;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
|id |select_type |table |partitions |type  |possible_keys |key  |key_len |ref  |rows |filtered |Extra  |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
|  1|SIMPLE  |t1  |NULL  |index |NULL  |idx_c1_c2 |10  |NULL|100113|  100.00|Usingindex; Usingfilesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
1row inset, 1warning (0.00sec)
 
# MySQL 8.0
mysql>explain select *from t1 order by c1 , c2 desc limit 5;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
|id |select_type |table |partitions |type  |possible_keys |key  |key_len |ref  |rows |filtered |Extra  |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
|  1|SIMPLE  |t1  |NULL  |index |NULL  |idx_c1_c2 |10  |NULL|  5|  100.00|Usingindex |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
1row inset, 1warning (0.00sec)

降序索引只是对查询中特定的排序顺序有效,如果使用不当,反而查询效率更低,比如上述查询排序条件改为order by c1 desc, c2 desc,这种情况下,5.7的执行计划要明显好于8.0的,如下:

# MySQL 5.7
mysql>explain select *from t1  order by c1 desc , c2 desc limit 5;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
|id |select_type |table |partitions |type  |possible_keys |key  |key_len |ref  |rows |filtered |Extra  |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
|  1|SIMPLE  |t1  |NULL  |index |NULL  |idx_c1_c2 |10  |NULL|  5|  100.00|Usingindex |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
1row inset, 1warning (0.01sec)
# MySQL 8.0
mysql>explain select *from t1 order by c1 desc , c2 desc limit 5;
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
|id |select_type |table |partitions |type  |possible_keys |key  |key_len |ref  |rows |filtered |Extra  |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
|  1|SIMPLE  |t1  |NULL  |index |NULL  |idx_c1_c2 |10  |NULL|100429|  100.00|Usingindex; Usingfilesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
1row inset, 1warning (0.01sec)

7. group by 不再隐式排序

mysql 8.0 对于group by 字段不再隐式排序,如需要排序,必须显式加上order by 子句。

# 表结构
mysql>show create table tb1\G
***************************1.row ***************************
  Table: tb1
CreateTable: CREATETABLE`tb1` (
  `id` int(11) NOTNULLAUTO_INCREMENT,
  `name` varchar(50) DEFAULTNULL,
  `group_own` int(11) DEFAULT'0',
  PRIMARYKEY(`id`)
) ENGINE=InnoDBAUTO_INCREMENT=11DEFAULTCHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ciROW_FORMAT=DYNAMIC
1row inset (0.00sec)
 
# 表数据
mysql>select *from tb1;
+----+------+-----------+
|id |name |group_own|
+----+------+-----------+
|  1|1  |  0|
|  2|2  |  0|
|  3|3  |  0|
|  4|4  |  0|
|  5|5  |  5|
|  8|8  |  1|
|10|10  | 5|
+----+------+-----------+
7rows inset (0.00sec)
 
# MySQL 5.7
mysql>select count(id), group_own from tb1 group by group_own;
+-----------+-----------+
|count(id)|group_own|
+-----------+-----------+
|  4|  0|
|  1|  1|
|  2|  5|
+-----------+-----------+
3rows inset (0.00sec)
 
# MySQL 8.0.11
mysql>select count(id), group_own from tb1 group by group_own;
+-----------+-----------+
|count(id)|group_own|
+-----------+-----------+
|  4|  0|
|  2|  5|
|  1|  1|
+-----------+-----------+
3rows inset (0.00sec)
 
# MySQL 8.0.11显式地加上order by进行排序
mysql>select count(id), group_own from tb1 group by group_own order by group_own;
+-----------+-----------+
|count(id)|group_own|
+-----------+-----------+
|  4|  0|
|  1|  1|
|  2|  5|
+-----------+-----------+
3rows inset (0.00sec)

8. JSON特性增强

MySQL 8 大幅改进了对JSON 的支持,添加了基于路径查询参数从JSON字段中抽取数据的JSON_EXTRACT() 函数,以及用于将数据分别组合到JSON 数组和对象中的JSON_ARRAYAGG() 和JSON_OBJECTAGG() 聚合函数。

在主从复制中,新增参数 binlog_row_value_options,控制JSON数据的传输方式,允许对于Json类型部分修改,在binlog中只记录修改的部分,减少json大数据在只有少量修改的情况下,对资源的占用。

9. redo & undo 日志加密

增加以下两个参数,用于控制redo、undo日志的加密。
innodb_undo_log_encrypt
innodb_undo_log_encrypt

10. innodb select for update跳过锁等待

select ... for update,select ... for share(8.0新增语法) 添加NOWAIT、SKIP LOCKED语法,跳过锁等待,或者跳过锁定。
在5.7及之前的版本,select...for update,如果获取不到锁,会一直等待,直到innodb_lock_wait_timeout超时。

在8.0版本,通过添加nowait,skip locked语法,能够立即返回。如果查询的行已经加锁,那么nowait会立即报错返回,而skip locked也会立即返回,只是返回的结果中不包含被锁定的行。

# session1:
mysql>begin;
mysql>select*fromt1 wherec1 =2forupdate;
+------+-------+
|c1  |c2  |
+------+-------+
|  2|60530|
|  2|24678|
+------+-------+
2rows inset(0.00sec)
 
# session2:
mysql>select*fromt1 wherec1 =2forupdate nowait;
ERROR3572(HY000): Statementaborted because lock(s) could not be acquired  immediately and NOWAITisset.
mysql>select*fromt1 wherec1 =2forupdate skip locked;
Emptyset(0.00sec)

11. 增加SET_VAR语法

在sql语法中增加SET_VAR语法,动态调整部分参数,有利于提升语句性能。

· select /*+ SET_VAR(sort_buffer_size = 16M) */ id from test order id ;
· insert /*+ SET_VAR(foreign_key_checks=OFF) */ into test(name) values(1);

12. 支持不可见索引

使用INVISIBLE关键字在创建表或者进行表变更中设置索引是否可见。索引不可见只是在查询时优化器不使用该索引,即使使用force index,优化器也不会使用该索引,同时优化器也不会报索引不存在的错误,因为索引仍然真实存在,在必要时,也可以快速的恢复成可见。

# 创建不可见索引
create table t2(c1 int,c2 int,index idx_c1_c2(c1,c2 desc) invisible );
# 索引可见
alter table t2 alter index idx_c1_c2 visible;
# 索引不可见
alter table t2 alter index idx_c1_c2 invisible;

13. 支持直方图

优化器会利用column_statistics的数据,判断字段的值的分布,得到更准确的执行计划。

可以使用ANALYZE TABLE table_name [UPDATE HISTOGRAM on col_name with N BUCKETS |DROP HISTOGRAM ON clo_name] 来收集或者删除直方图信息。

直方图统计了表中某些字段的数据分布情况,为优化选择高效的执行计划提供参考,直方图与索引有着本质的区别,维护一个索引有代价。每一次的insert、update、delete都会需要更新索引,会对性能有一定的影响。而直方图一次创建永不更新,除非明确去更新它。所以不会影响insert、update、delete的性能。

# 添加/更新直方图
mysql>analyze table t1 update histogram on c1, c2 with 32buckets;
+--------+-----------+----------+-----------------------------------------------+
|Table  |Op |Msg_type|Msg_text  |
+--------+-----------+----------+-----------------------------------------------+
|db.t1 |histogram|status  |Histogramstatistics created forcolumn 'c1'. |
|db.t1 |histogram|status  |Histogramstatistics created forcolumn 'c2'. |
+--------+-----------+----------+-----------------------------------------------+
2rows inset (2.57sec)
 
# 删除直方图
mysql>analyze table t1 drop histogram on c1, c2;
+--------+-----------+----------+-----------------------------------------------+
|Table  |Op |Msg_type|Msg_text  |
+--------+-----------+----------+-----------------------------------------------+
|db.t1 |histogram|status  |Histogramstatistics removed forcolumn 'c1'. |
|db.t1 |histogram|status  |Histogramstatistics removed forcolumn 'c2'. |
+--------+-----------+----------+-----------------------------------------------+
2rows inset (0.13sec)

14. 新增innodb_dedicated_server参数

能够让InnoDB根据服务器上检测到的内存大小自动配置innodb_buffer_pool_size,innodb_log_file_size,innodb_flush_method三个参数。

15. 日志分类更详细

在错误信息中添加了错误信息编号[MY-010311]和错误所属子系统[Server]

# MySQL 5.7
2019-06-08T09:07:20.114585+08:00 0 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode.
2019-06-08T09:07:20.117848+08:00 0 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2019-06-08T09:07:20.117868+08:00 0 [Warning] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.
 
 
# MySQL 8.0
2019-06-21T17:53:13.040295+08:00 28 [Warning] [MY-010311] [Server] 'proxies_priv'  entry '@ root@localhost' ignored in --skip-name-resolve mode.
2019-06-21T17:53:13.040520+08:00 28 [Warning] [MY-010330] [Server] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2019-06-21T17:53:13.040542+08:00 28 [Warning] [MY-010330] [Server] 'tables_priv' entry 'sys_config mysql.sys@localhost' ignored in --skip-name-resolve mode.

16. undo空间自动回收

· innodb_undo_log_truncate参数在8.0.2版本默认值由OFF变为ON,默认开启undo日志表空间自动回收。

· innodb_undo_tablespaces参数在8.0.2版本默认为2,当一个undo表空间被回收时,还有另外一个提供正常服务。

· innodb_max_undo_log_size参数定义了undo表空间回收的最大值,当undo表空间超过这个值,该表空间被标记为可回收。

17. 增加资源组

MySQL 8.0新增了一个资源组功能,用于调控线程优先级以及绑定CPU核。
MySQL用户需要有RESOURCE_GROUP_ADMIN权限才能创建、修改、删除资源组。
在Linux环境下,MySQL进程需要有 CAP_SYS_NICE 权限才能使用资源组完整功能。

[root@localhost~]# sudo setcap cap_sys_nice+ep /usr/local/mysql8.0/bin/mysqld
[root@localhost~]# getcap /usr/local/mysql8.0/bin/mysqld

/usr/local/mysql8.0/bin/mysqld =cap_sys_nice+ep

默认提供两个资源组,分别是USR_default,SYS_default

创建资源组:
create resource group test_resouce_group type=USER vcpu=0,1 thread_priority=5;
将当前线程加入资源组:
SET RESOURCE GROUP test_resouce_group;
将某个线程加入资源组:
SET RESOURCE GROUP test_resouce_group FOR thread_id;
查看资源组里有哪些线程:
select * from Performance_Schema.threads where RESOURCE_GROUP='test_resouce_group';
修改资源组:
alter resource group test_resouce_group vcpu = 2,3 THREAD_PRIORITY = 8;
删除资源组 :
drop resource group test_resouce_group;
# 创建资源组
mysql>create resource group test_resouce_group type=USERvcpu=0,1thread_priority=5;
QueryOK, 0rows affected (0.03sec)
 
mysql>select *from RESOURCE_GROUPS;
+---------------------+---------------------+------------------------+----------+-----------------+
|RESOURCE_GROUP_NAME|RESOURCE_GROUP_TYPE|RESOURCE_GROUP_ENABLED|VCPU_IDS|  THREAD_PRIORITY|
+---------------------+---------------------+------------------------+----------+-----------------+
|USR_default  |USER  |  1|0-3  |  0|
|SYS_default  |SYSTEM  |  1|0-3  |  0|
|test_resouce_group  |USER  |  1|0-1  |  5|
+---------------------+---------------------+------------------------+----------+-----------------+
3rows inset (0.00sec)
 
# 把线程id为60的线程加入到资源组test_resouce_group中,线程id可通过Performance_Schema.threads获取
mysql>SETRESOURCEGROUPtest_resouce_group FOR60;
QueryOK, 0rows affected (0.00sec)
 
# 资源组里有线程时,删除资源组报错
mysql>drop resource group test_resouce_group;
ERROR3656(HY000): Resourcegroup test_resouce_group is busy.
 
# 修改资源组
mysql>alter resource group test_resouce_group vcpu =2,3THREAD_PRIORITY=8;
QueryOK, 0rows affected (0.10sec)
mysql>select *from RESOURCE_GROUPS;
+---------------------+---------------------+------------------------+----------+-----------------+
|RESOURCE_GROUP_NAME|RESOURCE_GROUP_TYPE|RESOURCE_GROUP_ENABLED|VCPU_IDS|THREAD_PRIORITY|
+---------------------+---------------------+------------------------+----------+-----------------+
|USR_default  |USER  |  1|0-3  | 0|
|SYS_default  |SYSTEM  |  1|0-3  | 0|
|test_resouce_group  |USER  |  1|2-3  | 8|
+---------------------+---------------------+------------------------+----------+-----------------+
3rows inset (0.00sec)
 
# 把资源组里的线程移出到默认资源组USR_default
mysql>SETRESOURCEGROUPUSR_defaultFOR60;
QueryOK, 0rows affected (0.00sec)
 
# 删除资源组
mysql>drop resource group test_resouce_group;
QueryOK, 0rows affected (0.04sec)

18. 增加角色管理

角色可以认为是一些权限的集合,为用户赋予统一的角色,权限的修改直接通过角色来进行,无需为每个用户单独授权。

# 创建角色
mysql>create role role_test;
QueryOK, 0rows affected (0.03sec)
 
# 给角色授予权限
mysql>grant select on db.*to 'role_test';
QueryOK, 0rows affected (0.10sec)
 
# 创建用户
mysql>create user 'read_user'@'%'identified by '123456';
QueryOK, 0rows affected (0.09sec)
 
# 给用户赋予角色
mysql>grant 'role_test'to 'read_user'@'%';
QueryOK, 0rows affected (0.02sec)
 
# 给角色role_test增加insert权限
mysql>grant insert on db.*to 'role_test';
QueryOK, 0rows affected (0.08sec)
 
# 给角色role_test删除insert权限
mysql>revoke insert on db.*from 'role_test';
QueryOK, 0rows affected (0.10sec)
 
# 查看默认角色信息
mysql>select *from mysql.default_roles;
+------+-----------+-------------------+-------------------+
|HOST|USER  |DEFAULT_ROLE_HOST|DEFAULT_ROLE_USER|
+------+-----------+-------------------+-------------------+
|%  |read_user |%  |role_test  |
+------+-----------+-------------------+-------------------+
1row inset (0.00sec)
 
# 查看角色与用户关系
mysql>select *from mysql.role_edges;
+-----------+-----------+---------+-----------+-------------------+
|FROM_HOST|FROM_USER|TO_HOST|TO_USER  |WITH_ADMIN_OPTION|
+-----------+-----------+---------+-----------+-------------------+
|%  |role_test |%  |read_user |N  |
+-----------+-----------+---------+-----------+-------------------+
1row inset (0.00sec)
 
# 删除角色
mysql>drop role role_test;
QueryOK, 0rows affected (0.06sec)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值