MySQL5.7 的新特点

时间:2024-02-24 16:30:12

1、安全性

MySQL 5.7 的目标是成为发布以来最安全的 MySQL 服务器,其在 SSL/TLS 和全面安全开发方面有一些重要的改变。

mysql.user表结构升级

MySQL5.7用户表mysql.user的plugin字段不允许为空,默认值是mysql_native_password,而不是mysql_old_password,不再支持旧密码格式。
从旧版本升级,直接将原有的SQL导入到MySQL5.7,需要进行user表结构的升级:

  1. shell> /usr/local/mysql/bin/mysql_upgrade -uroot -p
  2. 重启MySQL

mysql.user表中已经没有了password字段,取而代之的是“authentication_string

# 修改密码(或者忘记密码的处理方式):
# 运行:
shell> mysqld_safe --skip-grant-tables &
# 如果此时不想被远程连接:
shell> mysqld_safe --skip-grant-tables --skip-networking &

# 更改密码:
mysql> update mysql.user set authentication_string=password(\'123AAAbbb2323#\') where user=\'root\' and Host = \'localhost\';
mysql> flush privileges;
或者: 
mysql> alter user \'root\'@\'localhost\' identified by \'123AAAbbb2323#\';
mysql> flush privileges;

账号安全

用户长度最大为32字节,之前最大长度为16字节,并且CREATE USER 和 DROP USER 命令里实现了 IF [NOT] EXISTS 条件判断。

创建用户分2步:先通过create user 创建用户,再通过grant来授权。

# 先创建用户
mysql> CREATE USER \'dba\'@\'localhost\' IDENTIFIED BY \'123456\';
# 或者
mysql> CREATE USER \'dba\'@\'localhost\' IDENTIFIED WITH \'mysql_native_password\' BY \'123456\';
# 或者
mysql> create user ‘test1’@’%’ identified with mysql_native_password as ‘23AE809DDACAF96AF0FD78ED04B6A265E05AA257’

# 再授权
mysql> grant select,insert,update,delete on *.* to dba@localhost;

直接使用grant命令创建用户将会报如下警告:

Using GRANT for creating new user is deprecated and will be removed in future release. Create new user with CREATE USER statement. 

密码过期策略

增加密码过期机制,过期后需要修改密码,否则可能会被禁用,或者进入沙箱模式。

为用户设置密码过期时间,一定时间以后,强制用户修改密码。可以直接在create user的时候设置,也可以alter user设置:

  • PASSWORD EXPIRE DEFAULT   # 默认,过期时间受全局变量 default_password_lifetime 控制
    • PASSWORD EXPIRE NEVER #永不过期
  • PASSWORD EXPIRE INTERVAL N DAY  #N天后过期
    • PASSWORD EXPIRE #过期

举例:

# 直接创建用户的时候设置 10天后过期:
mysql> create user dba@localhost identified by \'123456\' password expire interval 10 day;  

# 对已有用户设置 永不过期:
mysql> alter user dba@localhost password expire never; 

默认密码过期时间受变量default_password_lifetime控制,为0表示默认永不过期

mysql> set global  default_password_lifetime=0;                           
Query OK, 0 rows affected (0.00 sec)

密码安全策略

为防止用户设置过简单的密码,mysql在5.6开始就已经支持了密码安全策略的插件。

开启密码安全策略,2种方法:

① 在配置文件里修改:

[mysqld]
plugin-load=validate_password.so
validate-password=FORCE_PLUS_PERMANENT

② 在线修改

mysql> INSTALL PLUGIN validate_password SONAME \'validate_password.so\';
Query OK, 0 rows affected (0.01 sec)

开启安全策略的时候,不能为用户设置一个简单的密码:

mysql> grant all on *.* to dba@localhost identified by \'123\';
ERROR 1819 (HY000): Your password does not satisfy the current policy requirements

密码要求的强度手参数:validate_password_policy 的影响。validate_password_policy的值有:

  • 0 or LOW:仅需需符合密码长度(由参数validate_password_length指定,默认为8)
  • 1 or MEDIUM:满足LOW策略,同时还需满足至少有1个数字,小写字母,大写字母和特殊字符,默认。
  • 2 or STRONG:满足MEDIUM策略,同时密码不能存在字典文件(dictionary file)中

相关参数:

  • validate_password_dictionary_file:在STRONG模式下还能设置字典文件,字典中存在的密码不得使用。可以通过该参数来设置字典文件。
  • validate_password_length:设置密码的最小长度,默认值为8。
  • validate_password_mixed_case_count:小写和大写字符的最小数目,如果密码策略是MEDIUM或STRONG的,有validate_password插件检查,默认1。
  • validate_password_number_count:数字字符的最小数目,如果密码策略是MEDIUM或STRONG的,有validate_password插件检查,默认1。
  • validate_password_special_char_count:非字母字符(特殊字符)的最小数目,如果密码策略是MEDIUM或STRONG的,有validate_password插件检查,默认1。

根据上面的参数,按照自己想要的密码复杂度,进行设置。

对普通用户进行lock

锁定用户:
mysql> alter user admin@localhost account lock;

登陆报错:
ERROR 3118 (HY000): Access denied for user \'admin\'@\'localhost\'. Account is locked.

解锁用户:
mysql> alter user admin@localhost account unlock;

初始化方式

高版本的MySQL,逐步废弃mysql_install_db的初始化方式

在5.7中,推荐使用bin/mysqld –-initialize对数据库进行初始化,初始化过程会创建带随机密码的 root@localhost 账号并不再创建test 库,初始化输出如下:

[Note] A temporary password is generated for root@localhost: KJ1foE6BFX;3

在初始化时如果使用–initial-insecure,则会创建空密码的 root@localhost 账号

新初始化的 root@localhost 账号,第一次登录时,需要修改新的密码才能正常使用

SSL 特性

MySQL 5.7版本提供了更为简单SSL安全访问配置,并且默认连接就采用SSL的加密方式

姜承尧文章中的测试案例显示 开启SSL 性能开销在25% 左右

2、新支持

原生支持JSON

5.7版本之前,只能在varchar或是text等字符类型的列中存储json类型的字符串,并通过程序解析使用json字符串。这种做法当然有其缺陷:必须自行确认/解析数据、解决更新中的困难、或在执行插入操作时忍受较慢的速度。

5.7版本:增加了json列类型以及json_开头的函数,如json_type(),json_object(),json_merge()等。

从MySQL5.7.8之后,由于原生支持JSON,处理JSON文件就非常简单。现在执行插入与更新操作时可以自动确认了,而且效率很高;使用新定制的一系列功能访问对象与数组成员的速度也更快了。

举个栗子:

创建表json_test:

CREATE TABLE json_test(
  id INT(11) AUTO_INCREMENT PRIMARY KEY,
  person_desc JSON
)ENGINE INNODB;

插入一条记录:

INSERT INTO json_test(person_desc) VALUES (\'{  
    "programmers": [{  
        "firstName": "Brett",  
        "lastName": "McLaughlin",  
        "email": "aaaa"  
    }, {  
        "firstName": "Jason",  
        "lastName": "Hunter",  
        "email": "bbbb"  
    }, {  
        "firstName": "Elliotte",  
        "lastName": "Harold",  
        "email": "cccc"  
    }],  
    "authors": [{  
        "firstName": "Isaac",  
        "lastName": "Asimov",  
        "genre": "sciencefiction"  
    }, {  
        "firstName": "Tad",  
        "lastName": "Williams",  
        "genre": "fantasy"  
    }, {  
        "firstName": "Frank",  
        "lastName": "Peretti",  
        "genre": "christianfiction"  
    }],  
    "musicians": [{  
        "firstName": "Eric",  
        "lastName": "Clapton",  
        "instrument": "guitar"  
    }, {  
        "firstName": "Sergei",  
        "lastName": "Rachmaninoff",  
        "instrument": "piano"  
    }]  
}\');

查看插入的这行JSON数据有哪些KEY:

mysql> SELECT id,json_keys(person_desc) as "keys" FROM json_test\G  
*************************** 1. row ***************************  
  id: 1  
keys: ["authors", "musicians", "programmers"]  
1 row in set (0.00 sec)

可以看到里面有三个KEY,分别为authors,musicians,programmers。

又例如:

# 转换为json对象
mysql> select json_object(\'name\',\'tom\',\'age\',20) ; 
+------------------------------------+
| json_object(\'name\',\'tom\',\'age\',20) |
+------------------------------------+
| {"age": 20, "name": "tom"}         |
+------------------------------------+
1 row in set (0.00 sec)
# 转换为json数组
mysql> select json_array(\'a\',\'b\',now()) ;
+------------------------------------------+
| json_array(\'a\',\'b\',now())                |
+------------------------------------------+
| ["a", "b", "2019-01-08 13:40:21.000000"] |
+------------------------------------------+
1 row in set (0.00 sec)

支持空间数据类型

空间数据类型常用于处理地理空间信息,它们描述了几何对象的真实坐标与形状。在MySQL中,可以使用像Point、LineString或Polygon之类的几何对象代表,还有一些很有用的空间函数k。

支持为表计算列

所谓计算列,就是通过其他列计算得到的值。

5.7之前版本实现计算列一般通过触发器实现。如下:​
mysql> create trigger insr_tig before insert on t1 for each row set new.c3=new.c1+new.c2;
Query OK, 0 rows affected (0.09 sec)

mysql> create trigger upd_tig before update on t1 for each row set new.c3=new.c1+new.c2;
Query OK, 0 rows affected (0.01 sec)

5.7版本实现计算列只需要在建表/修改表时添加列的as参数就可以了,如下:

mysql> create table t2(id int auto_increment not null,c1 int ,c2 int ,c3 int as(c1+c2),primary key(id));
Query OK, 0 rows affected (0.03 sec)

mysql> insert into t2(c1,c2) values(2,3);
Query OK, 1 row affected (0.01 sec)

mysql> select * from t2;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |    2 |    3 |    5 |
+----+------+------+------+
1 row in set (0.00 sec)

mysql> update t2 set c1=10 where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t2;
+----+------+------+------+
| id | c1   | c2   | c3   |
+----+------+------+------+
|  1 |   10 |    3 |   13 |
+----+------+------+------+
1 row in set (0.00 sec)

Online rename index name

alter table ttt1 rename index idx to idxx;

mysql> show create table ttt1 ;        
+-------+--------------------------------------------------------------------------------------+
| Table | Create Table                                                                         |
+-------+--------------------------------------------------------------------------------------+
| ttt1  | CREATE TABLE `ttt1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `person_desc` json DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx` (`id`)
) /*!50100 TABLESPACE `tb_space1` */ ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+--------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> alter table ttt1 rename index idx to idxx;             
Query OK, 0 rows affected (0.05 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> show create table ttt1 ;                
+-------+--------------------------------------------------------------------------------------+
| Table | Create Table                                                                         |
+-------+--------------------------------------------------------------------------------------+
| ttt1  | CREATE TABLE `ttt1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `person_desc` json DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idxx` (`id`)
) /*!50100 TABLESPACE `tb_space1` */ ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-------+--------------------------------------------------------------------------------------+
1 row in set (0.00 sec)

动态修改varchar 长度大小

可以通过ALTER TABLE 语句以in place方式修改varchar的大小且无需table-copy

但存在限制:表示 varchar 长度的字节数不能变化(如果变更前使用1个字节表示长度,变更后也必须使用1个字节表示),即只支持0~255内的或者255以上的范围变更(增大),如果字段的长度从254增到256时就不能使用in-place算法,必须使用copy算法,否侧报错,这个原理就是varchar会在头部存储一个长度,如果小于255就是一个BYTES,8位;如果大于255当然就需要两个BYTES了。头部都变了,自然要重新copy table了。

需要注意的是 减小 varchar(N)长度的大小必须使用copy类型

举个栗子:

# varchar(20) -- varchar(300),只能使用copy算法
mysql> create table testtb2 (id int , vvv varchar(20)) ;  
Query OK, 0 rows affected (0.02 sec)
mysql> alter table testtb2 change column vvv vvv varchar(300),algorithm=inplace;
ERROR 1846 (0A000): ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.
mysql> alter table testtb2 change column vvv vvv varchar(300),algorithm=copy;   
Query OK, 0 rows affected (0.32 sec)
Records: 0  Duplicates: 0  Warnings: 0

新增临时表空间

为所有非压缩的innodb临时表提供一个独立的表空间,默认的临时表空间文件为ibtmp1,位于数据目录。我们可通过innodb_temp_data_file_path参数指定临时表空间的路径和大小

mysql> show global variables like \'innodb_temp_data_file_path\';
+----------------------------+-----------------------+
| Variable_name              | Value                 |
+----------------------------+-----------------------+
| innodb_temp_data_file_path | ibtmp1:12M:autoextend |
+----------------------------+-----------------------+
1 row in set (0.01 sec)

MySQL每次重新启动时,会重新创建临时表空间

**注意 **:

从5.7.5开始,新增一个系统选项 internal_tmp_disk_storage_engine 可定义OnDisk临时表的引擎类型为 InnoDB,而在这以前,只能使用 MyISAM。(HEAP临时表,内部临时表有两种类型:HEAP临时表和OnDisk临时表)

而在5.6.3以后新增的参数default_tmp_storage_engine是控制create temporary table创建的外部临时表的存储引擎,在以前默认是MEMORY。(外部临时表:临时表只对当前用户可见,当前会话结束的时候,该临时表会自动关闭)

mysql> show global variables like \'%_storage_engine\';           
+----------------------------------+--------+
| Variable_name                    | Value  |
+----------------------------------+--------+
| default_storage_engine           | InnoDB |
| default_tmp_storage_engine       | InnoDB |
| enforce_storage_engine           |        |
| internal_tmp_disk_storage_engine | InnoDB |
+----------------------------------+--------+
4 rows in set (0.01 sec)

sys schema

MySQL 5.7 版本新增了sys 数据库,该库通过视图的形式把information_schema 和performance_schema结合起来,查询出更加令人容易理解的数据,帮助DBA快速获取数据库系统的各种纬度的元数据信息,帮助DBA和开发快速定位性能瓶颈。

mysql client

旧版本的mysql客户端在执行Control+C,如果有SQL在运行会中断SQL,没有会退出mysql客户端,新版本也会中断SQL,但是不会退出。

3、InnoDB增强

在线调整InnoDB缓冲池大小

MySql5.7之前:要变更innodb_buffer_pool大小必须更改my.cnf文件后重启数据库服务器方生效

MySql5.7之后:变为动态参数,可以在线调整大小

  • nnodb_buffer_pool_size 缓池区大小
  • innodb_buffer_pool_chunk_size 缓池区块的大小  默认128M
  • innodb_buffer_pool_instances 缓池区实例的个数

innodb_buffer_pool_size  必须是 innodb_buffer_pool_chunk_size * innodb_buffer_pool_instances 倍数,如果不是mysql也会自动取整为倍数。

修改缓冲池的大小,会对运行的事务有影响,尽量在少操作的情况下修改。

mysql> show global status where variable_name=\'InnoDB_buffer_pool_resize_status\';
+----------------------------------+----------------------------------------------------------------------+
| Variable_name                    | Value                                                                |
+----------------------------------+----------------------------------------------------------------------+
| Innodb_buffer_pool_resize_status | Size did not change (old size = new size = 134217728. Nothing to do. |
+----------------------------------+----------------------------------------------------------------------+
1 row in set (0.01 sec)

mysql> set global innodb_buffer_pool_size=268435456 ;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW STATUS WHERE Variable_name=\'InnoDB_buffer_pool_resize_status\';
+----------------------------------+----------------------------------------------------+
| Variable_name                    | Value                                              |
+----------------------------------+----------------------------------------------------+
| Innodb_buffer_pool_resize_status | Completed resizing buffer pool at 190108 16:24:05. |
+----------------------------------+----------------------------------------------------+
1 row in set (0.00 sec)

支持为Innodb建立表空间

MySql5.7之前:具有系统共享表空间和为每个表建立的独立表空间

MySql5.7之后:支持create tablespace语法为一个表或者多个表建立公用表空间

举个栗子:

mysql> create tablespace tb_space1 add datafile \'tb_space11.ibd\' engine=innodb;       
Query OK, 0 rows affected (0.30 sec)

mysql> create table ttt1 (id INT(11) AUTO_INCREMENT PRIMARY KEY,person_desc JSON) tablespace tb_space1;
Query OK, 0 rows affected (0.06 sec)

mysql> create table ttt2 (id INT(11) AUTO_INCREMENT PRIMARY KEY,person_desc JSON) tablespace tb_space1; 
Query OK, 0 rows affected (0.06 sec)

mysql> show create table ttt3 ;
+-------+-----------------------------------------------------------------------------------+
| Table | Create Table                                                                      |
+-------+-----------------------------------------------------------------------------------+
| ttt2  | CREATE TABLE `ttt2` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `person_desc` json DEFAULT NULL,
  PRIMARY KEY (`id`)
) /*!50100 TABLESPACE `tb_space1` */ ENGINE=InnoDB DEFAULT CHARSET=utf8                     |
+-------+-----------------------------------------------------------------------------------+
1 row in set (0.00 sec)

tb_space11.ibd表空间文件被创建在数据目录下

InnoDB缓冲池导入导出

增加以下参数控制InnoDB缓冲池的导入导出:

  • innodb_buffer_pool_filename   如果开启InnoDB预热功能,停服务时,MySQL将InnoDB缓冲池中的热数据保存到数据目录中,默认文件名为ib_buffer_pool
  • innodb_buffer_pool_dump_pct     导出缓存池的百分比,默认25%
  • innodb_buffer_pool_dump_now   用手工方式立刻做一次把热数据dump到本地磁盘。
  • innodb_buffer_pool_dump_at_shutdown   正常停止服务时,InnoDB将InnoDB缓冲池中的热数据保存到本地硬盘,默认为OFF
  • innodb_buffer_pool_load_now  停止MySQL服务时,以手动方式立刻做一次将InnoDB缓存池中的热数据保存到本地硬盘,默认为OFF
  • innodb_buffer_pool_load_abort  如果开启该参数,即便开启InnoDB预热功能,启动服务时,MySQL也不会将本地硬盘的热数据加载到InnoDB缓冲池中,默认为OFF
  • innodb_buffer_pool_load_at_startup   如果开启该参数,启动MySQL服务时,MySQL将本地热数据加载到InnoDB缓冲池中,默认为OFF

支持多线程刷脏页

5.6.2版本中,MySQL将刷脏页的线程从master线程独立出来,5.7.4版本之后,MySQL系统支持多线程刷脏页,进程的数量由innodb_page_cleaners参数控制,该参数不能动态修改,最小值为1 ,最大值支持64,5.7.7以及之前默认值是1 ,5.7.8版本之后修改默认参数为4。

当启用多线程刷脏页,系统将innodb buffer instance脏页分配到各个空闲的刷脏页线程上,如果设置的innodb_page_cleaners>innodb_buffer_pool_instances,系统会自动重置为innodb_buffer_pool_instances大小。

4、复制增强

MySQL5.7在主从复制上面相对之前版本多了一些新特性,包括多源复制、基于组提交的并行复制、在线修改Replication Filter、GTID增强、半同步复制增强等

多源复制、基于组提交的并行复制、在线修改Replication Filter 的内容这里先略去

MySql5.7之前,要把基于日志点的复制方式变为基于GTID的复制方式或者把基于GTID的复制方式变为基于日志点的复制方式必须要重启master服务器。MySql5.7之后可以在线变更,不需要重启服务器。

5、弃用

以下特性在5.7里已经弃用,在后续的版本可能会移除。

–skip-innodb–innodb=OFF, –disable-innodb 弃用了
因为5.7innodb是不能禁用的。

系统变量storage_engine 用 default_storage_engine代替

mysql.user表中的password字段被弃用 ,改为authentication_string