Mysql 8.0 新特性测试
Role
MySQL8.0版本添加了role特性,role是一种逻辑概念是权限的集合,可以将一个或以上的权限赋予给role,再将role赋给user。Oracle,Postgresql和Mariadb中早已存在role这个特性。
create role role_test;
grant select,insert,delete,update on zhongwc.tab01 to role_test;
create user 'user1'@'%' identified by 'user1';
grant role_test to 'user1'@'%';
show grants for 'user1'@'%';
使用root用户撤销role中的某些权限
revoke delete,update on zhongwc.tab01 from role_test;
MySQL8.0加入了两张系统表来维护role特性
default_roles;
desc role_edges;
隐藏索引
隐藏索引的特性对于性能调试非常有用。在 8.0 中,索引可以被“隐藏”和“显示”。当一个索引隐藏时,它不会被查询优化器所使用。
也就是说,我们可以隐藏一个索引,然后观察对数据库的影响。如果数据库性能有所下降,就说明这个索引是有用的,于是将其“恢复显示”即可;如果数据库性能看不出变化,说明这个索引是多余的,可以删掉了。
ALTER
TABLE
t ALTER
INDEX
i INVISIBLE;
恢复显示该索引的语法是:
ALTER TABLE t ALTER INDEX i VISIBLE;
参数持久化
MySQL 的设置可以在运行时通过 SET GLOBAL 命令来更改,但是这种更改只会临时生效,到下次启动时数据库又会从配置文件中读取。
MySQL 8 新增了 SET PERSIST 命令,例如:
SET
PERSIST max_connections = 500;
MySQL 会将该命令的配置保存到数据目录下的 mysqld-auto.cnf 文件中,下次启动时会读取该文件,用其中的配置来覆盖缺省的配置文件。
UTF8mb4为默认编码
With 语句(仿oracle)
复杂的查询会使用嵌入式表,例如:
SELECT t1.*, t2.* FROM (SELECT col1 FROM table1) t1, (SELECT col2 FROM table2) t2; |
而有了 CTE,我们可以这样写:
WITH t1 AS (SELECT col1 FROM table1), t2 AS (SELECT col2 FROM table2) SELECT t1.*, t2.* FROM t1, t2; |
这样看上去层次和区域都更加分明,改起来也更清晰的知道要改哪一部分。
窗口函数(仿oracle)
MySQL 被吐槽最多的特性之一就是缺少 rank() 函数,当需要在查询当中实现排名时,必须手写 @ 变量。但是从 8.0 开始,MySQL 新增了一个叫窗口函数的概念,它可以用来实现若干新的查询方式。
窗口函数有点像是 SUM()、COUNT() 那样的集合函数,但它并不会将多行查询结果合并为一行,而是将结果放回多行当中。也就是说,窗口函数是不需要 GROUP BY 的。
假设我们有一张 “班级学生人数” 表:
mysql> select * from classes; +--------+-----------+ | name | stu_count | +--------+-----------+ | class1 | 41 | | class2 | 43 | | class3 | 57 | | class4 | 57 | | class5 | 37 | +--------+-----------+ 5 rows in set (0.00 sec) |
如果我要对班级人数从小到大进行排名,可以这样利用窗口函数:
mysql> select *, rank() over w as `rank` from classes -> window w as (order by stu_count); +--------+-----------+------+ | name | stu_count | rank | +--------+-----------+------+ | class5 | 37 | 1 | | class1 | 41 | 2 | | class2 | 43 | 3 | | class3 | 57 | 4 | | class4 | 57 | 4 | +--------+-----------+------+ 5 rows in set (0.00 sec) |
在这里我们创建了名为 w 的 window,规定它对 stu_count 字段进行排序,然后在 select 子句中对 w 执行 rank() 方法,将结果输出为 rank 字段。
其实,window 的创建是可选的。例如我要在每一行中加入学生总数,则可以这样:
mysql> select *, sum(stu_count) over() as total_count -> from classes; +--------+-----------+-------------+ | name | stu_count | total_count | +--------+-----------+-------------+ | class1 | 41 | 235 | | class2 | 43 | 235 | | class3 | 57 | 235 | | class4 | 57 | 235 | | class5 | 37 | 235 | +--------+-----------+-------------+ 5 rows in set (0.00 sec) |
这样做有什么用呢?这样我们就可以一次性将每个班级的学生人数占比查出来了:
mysql> select *, -> (stu_count)/(sum(stu_count) over()) as rate -> from classes; +--------+-----------+--------+ | name | stu_count | rate | +--------+-----------+--------+ | class1 | 41 | 0.1745 | | class2 | 43 | 0.1830 | | class3 | 57 | 0.2426 | | class4 | 57 | 0.2426 | | class5 | 37 | 0.1574 | +--------+-----------+--------+ 5 rows in set (0.00 sec) |
这在以前可是要写一大段晦涩难懂的语句才能做到的哦!关于窗口函数的更多介绍在这里。
自适应内存参数innodb_dedicated_server=ON
适应场景
- 运行MySQL的服务器上是专门给MySQL提供服务的。innodb_dedicated_server的默认设置都是假设这个服务器的资源,MySQL都能用起来。
不适应场景
- 单机多实例情况下不适应。
- 其他有特殊场景要求的不适用。比如:不是主要以InnoDB为存储引擎的;服务器上还有其他应用程序的等等。
可以设置参数 innodb_dedicated_server=ON来让MySQL自动探测服务器的内存资源,确定innodb_buffer_pool_size, innodb_log_file_size 和 innodb_flush_method 三个参数的取值。具体取值策略如下。
innodb_buffer_pool_size:
- <1G: 128M(innodb_dedicated_server=为OFF时的默认取值)
- <=4G: 探测到的物理内存 * 0.5
- >4G: 探测到的物理内存 * 0.75
innodb_log_file_size:
- <1G: 48M(innodb_dedicated_server=为OFF时的默认取值)
- <=4G: 128M
- <=8G: 512M
- <=16G: 1024M
- >16G: 2G
innodb_flush_method:
如果系统允许设置为O_DIRECT_NO_FSYNC。如果系统不允许,则设置为InnoDB默认的Flush method。
上述这些参数在MySQL每次启动时自动探测服务器(包括虚拟机和容器的内存)配置并自动生效。
自适应参数使用注意
- innodb_dedicated_server默认设置为OFF,不会自适应调整3个参数值。该参数也不是动态参数,无法动态调整,也就是说MySQL启动后无法修改这个参数
- innodb_dedicated_server=ON 设置以后它其实只探测了服务器内存,所以目前只能自适应调整内存相关的三个参数
- innodb_dedicated_server=ON的情况下,如果还显式设置了 innodb_buffer_pool_size / innodb_log_file_size / innodb_flush_method 参数,显示设置的这些参数会优先生效,并且在MySQL的错误日志中会打印如下内容:
"[Warning] InnoDB: Option innodb_dedicated_server is ignored for because 'variable name'=? is specified explicitly."
'variable name' 指的就是 innodb_buffer_pool_size/innodb_log_file_size/inndob_flush_method参数。
注意:你不管是在配置文件、命令行、还是MySQL新引入的固化配置中设定上述三个参数都被认为是显式指定了参数值,都会优先生效。
- 显示指定某一个值,并不会影响其他变量的自适应参数值设置。例如显式设置了innodb_buffer_pool_size,那么buffer pool会按照你显示设置的值初始化,而不是 innodb_dedicated_server参数对应的值。但是innodb_log_file_size 和 innodb_flush_method 并不会受影响,它们还是会按照innodb_dedicated_server的自适应值按照服务器的内存大小来设置。
- innodb_dedicated_server=ON的情况下,mysqld服务进程每次重启后都会自动调整上述三个参数值。在任何时候MySQL都不会将自适应值保存在持久配置中。
- 如果系统不支持O_DIRECT_NO_FSYNC,MySQL会沿用之前的默认值。MySQL仍然必须保证在所有平台上能正常启动,不需要任何其他更改。
- 如果自适应导致innodb_log_file_size对应的redo log file超过了磁盘空间限制(这个空间得有多小!),将会采取以下措施:
- 新生成的日志文件redo log将被删除
- 错误日志显示如下
"[ERROR] InnoDB: Error number 28 means 'No space left on device'
[ERROR] InnoDB: Cannot set log file to size MB"
* mysqld
服务拒绝启动。
- innodb_dedicated_server=ON并不见得是最优的配置。例如,你用了MyISAM,MyRocks等其他存储引擎时,建议手工调整,而不是设置innodb_dedicated_server=ON
- XFS系统请手工设置inndob_flush_method=O_DIRECT。在inndob_flush_method=O_DIRECT_NO_FSYNC下,InnoDB使用O_DIRECT来刷新IO,但是跳过fsync()步骤。对某些文件系统有效,但是对XFS文件系统并不适用。为了保证文件的metadata刷新到磁盘中,XFS必须使用O_DIRECT。
取消默认MyISAM 引擎
由于采用了新的本地数据字典,现在我们不在需要MyISAM系统表了!
这些表和数据字典表现在都在一个名为mysql.idb的InNoDB表空间文件中。
这意味着如果你没有明确使用MyISAM表(为了你的数据,我们并不建议这样做),你可以创建一个没有任何MyISAM表的MySQL实例。
UNDO 空间回收
UNDO空间回收
在MySQL5.7中,我们已经可以截断UNDO空间了(设置innodb_undo_log_truncate,默认情况下禁用)。
在MySQL8中,我们改进了磁盘格式来使得每个UNDO表有大量的UNDO段。
此外,现在默认为两个单独的UNDO表空间(而非InnoDB系统表空间(最小为2,大小动态变化))中创建UNDO段。
我们不推荐使用innodb_undo_tablespaces来设置该值,因为我们将提供SQL命令让数据库管理员与UNDO表空间进行交互。
自动截断UNDO表空间默认启用。
取消Query Cache
我在性能审计中建议的第一件事就是禁用Query Cache,因为它给设计带来了很多麻烦。
MySQL QC造成的问题比它解决问题要多的多。因此我们决定在MySQL 8.0中取消它,因为大家就不应该使用它。
如果您的工作负载需要Query Cache,那么您应该改用ProxySQL替代Query Cache。
院子DDL
原子DDL
由于采用了新的数据字典,MySQL 8.0现在支持原子数据定义语句(原子DDL)。
这意味着当执行DDL时,数据字典更新,存储引擎操作以及二进制日志中的写入操作会合并到单个原子事务中,该事务要么完全执行,要么根本不执行。
这提高了DDL的稳定性保证未完成的DDL不会留下任何不完整的数据。