MySQL-08 MySQL8.0新特性


性能

MySQL 8.0 在一定的用戶訪問條件下,速度要比 MySQL 5.7 快 2 倍。MySQL 8.0 在以下方面帶來了更好的性能:讀/寫工作負載、IO 密集型工作負載、以及高競爭("hot spot"熱點競爭問題)工作負載。

 

NoSQL的支持

MySQL 從 5.7 版本開始提供 NoSQL 存儲功能,在 8.0 版本中這部分功能也得到了更大的改進。該項功能消除了對獨立的 NoSQL 文檔數據庫的需求,而 MySQL 文檔存儲也為 schema-less 模式的 JSON 文檔提供了多文檔事務支持和完整的 ACID 合規性。

'

X Protocol訪問:支持常規的TCP協議以及unix sockets訪問數據庫,提高了用戶安全性。

 

 

默認字符集:utf8mb4

說明

  • 8.0之前的版本,默認字符集為latin1,通常為了避免客戶端和數據交互造成字符亂碼,需要設置客戶端和mysql數據的字符集為utf8。實際上utf8能夠存儲3個字節的字符,即utf8指向的是utf8mb3。
  • 8.0版本默認字符集為utf8mb4,utf8默認指向的是utf8mb4。
  • utf8mb3和utf8mb4的區別:utf8mb3只支持BMP字符集;utf8mb4除了支持BMP字符集,還支持BMP之外的字符集,例如emoji編碼符號。

 

查看字符集設置

查看全局字符集設置:

SHOW global variables LIKE '%character_set%';

使用默認配置創建的數據庫字符集:

USE myschool;

SHOW variables LIKE '%character_set%';

 工程中應用

  •  utf8mb4 存儲會消耗存儲空間。
  • 如果有使用到emoji的表可以設置為utf8mb4字符集。
  • 表字段排序:tf8_unicode_ci比較准確,utf8_general_ci速度較快。 通常創建數據庫的時候使用utf8mb4_general_ci或者 utf8mb4_unicode_ci。

 

MySQL8默認數據表引擎為:InnoDB

說明

MySQL8創建數據庫默認的數據表引擎為InnoDB類型,之前的版本默認為MyISAM類型。

MyISAM查詢速度快,如果需要在mysql8中創建MyISAM表需要手動指定。

查看某表的數據表引擎命令:

show create table 表名

  

例如:

 

mysql8支持的數據表引擎

 

自增變量持久化

自增主鍵重啟重置問題

8.0之前的mysql數據庫重啟或者斷電后,innodb表的自增字段的值會被重置。原因:auto_increment計數值存儲在內存中,斷電導致計數值丟失。當重啟mysql服務,mysql會讀取表中最大的值並加1放入auto_increment的計數值中。

如果存在同時操作刪除數據和添加數據的情況:例如刪除數據的主鍵id為1000,插入數據的id應該為1001;如果刪除成功后故障導致自增id計數值丟失,插入數據的id將會變為1000,若該id是表記錄的業務主鍵,就會導致沖突。

mysql8.0的解決方案

mysql8對AUTO_INCREMENT值進行持久化(例如存儲到硬盤),MySQL重啟后,該值將不會改變。

 

 

DDL事務支持

MySQL8之前的版本只有ninnodb表支持DML語句的事務處理。 

MySQL8支持數據表級別的DDL事務完處理。例如,在8.0之前的版本中,加入數據庫中只有一張表table1,如果執行以下語句:

drop table table1, table2;

  

執行報錯,但是table1還是會被刪除;在mysql8.0中執行報錯,但是table1不會被刪除。

參數修改持久化

MySQL 8.0版本支持在線修改全局參數並持久化,通過加上PERSIST關鍵字,可以將修改的參數持久化到新的配置文件(mysqld-auto.cnf)中,重啟MySQL時,可以從該配置文件獲取到最新的配置參數。
例如執行:

系統會在數據目錄下生成一個包含json格式的 mysqld-auto.cnf 的文件,格式化后如下所示,當 my.cnf 和 mysqld-auto.cnf 同時存在時,后者具有更高優先級。

文件目錄:

D:\MySQL8\data\Data\mysqld-auto.cnf

生成內容:

 

{ "Version" : 1 , "mysql_server" : { "binlog_expire_logs_seconds" : { "Value" : "8640000" , "Metadata" : { "Timestamp" : 1546569025389875 , "User" : "root" , "Host" : "localhost" } } } }

  

 新增降序索引

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, 0 rows affected (0.03 sec)
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
1 row in set (0.00 sec)

  

 # MySQL 8.0
 mysql> create table t1(c1 int,c2 int,index idx_c1_c2(c1,c2 desc)); 
Query OK, 0 rows affected (0.06 sec) 
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 
1 row in set (0.00 sec) 

   

再來看看降序索引在執行計划中的表現,在t1表插入10萬條隨機數據,查看select * from t1 order by c1 , c2 desc;的執行計划。從執行計划上可以看出,5.7的掃描數100113遠遠大於8.0的5行,並且使用了filesort。

DELIMITER ;;
CREATE PROCEDURE test_insert ()
BEGIN
DECLARE i INT DEFAULT 1;
WHILE i<100000
DO
insert into t1 select rand()*100000, rand()*100000;
SET i=i+1;
END WHILE ;
commit;
END;;
DELIMITER ;
CALL test_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 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)
 # 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 | Using index |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

  

降序索引只是對查詢中特定的排序順序有效,如果使用不當,反而查詢效率更低,比如上述查詢排序條件改為 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 | Using index |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.01 sec)

  

# 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 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+-----------+---------+------+--------+----------+-----------------------------+
1 row in set, 1 warning (0.01 sec)

  

 

group by 不再隱式排序

mysql 8.0 對於group by 字段不再隱式排序,如需要排序,必須顯式加上order by 子句。

# 表結構
mysql> show create table tb1\G
*************************** 1. row ***************************
       Table: tb1
Create Table: CREATE TABLE `tb1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `group_own` int(11) DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC
1 row in set (0.00 sec)

  

# 表數據
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 |
+----+------+-----------+
7 rows in set (0.00 sec)

  

# 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 |
+-----------+-----------+
3 rows in set (0.00 sec)

  

# MySQL 8.0.13
mysql> select count(id), group_own from tb1 group by group_own;
+-----------+-----------+
| count(id) | group_own |
+-----------+-----------+
|         4 |         0 |
|         2 |         5 |
|         1 |         1 |
+-----------+-----------+
3 rows in set (0.00 sec)

  

# 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 |
+-----------+-----------+
3 rows in set (0.00 sec)

  

JSON特性增強

MySQL 8 大幅改進了對 JSON 的支持,添加了基於路徑查詢參數從 JSON 字段中抽取數據的 JSON_EXTRACT() 函數,以及用於將數據分別組合到 JSON 數組和對象中的 JSON_ARRAYAGG() 和 JSON_OBJECTAGG() 聚合函數。

在主從復制中,新增參數 binlog_row_value_options,控制JSON數據的傳輸方式,允許對於Json類型部分修改,在binlog中只記錄修改的部分,減少json大數據在只有少量修改的情況下,對資源的占用。

 

redo & undo 日志加密

增加以下兩個參數,用於控制redo、undo日志的加密。
innodb_undo_log_encrypt
innodb_undo_log_encrypt

 

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 * from t1 where c1 = 2 for update;
+------+-------+
| c1   | c2    |
+------+-------+
|    2 | 60530 |
|    2 | 24678 |
+------+-------+
2 rows in set (0.00 sec)

  

# session2:
mysql> select * from t1 where c1 = 2 for update nowait;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired  immediately and NOWAIT is set.
mysql> select * from t1 where c1 = 2 for update skip locked;
Empty set (0.00 sec)

  

增加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);

  

示例代碼:

select /*+SET_VAR(sort_buffer_size = 16M)*/  studentno,studentname from student order by studentno desc ;  ##調整緩沖區

INSERT /*+ SET_VAR(foreign_key_checks=OFF) */ INTO student VALUES(80000,'GuoJing','郭靖2','男',5,'02088762106','1987-09-08','天津市河西區','GuoJing@sohu.com','1111112'); ##關閉外鍵約束

  

支持不可見索引

使用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;

  

通過隱藏索引可以了解該索引是否對性能有影響。如果隱藏了某個索引,優化器運行后性能沒有索引,該索引即可進行刪除或者其他變更操作。


支持直方圖

優化器會利用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 32 buckets;
+--------+-----------+----------+-----------------------------------------------+
| Table  | Op        | Msg_type | Msg_text                                      |
+--------+-----------+----------+-----------------------------------------------+
| db.t1 | histogram | status   | Histogram statistics created for column 'c1'. |
| db.t1 | histogram | status   | Histogram statistics created for column 'c2'. |
+--------+-----------+----------+-----------------------------------------------+
2 rows in set (2.57 sec)
 
# 刪除直方圖
mysql> analyze table t1 drop histogram on c1, c2;
+--------+-----------+----------+-----------------------------------------------+
| Table  | Op        | Msg_type | Msg_text                                      |
+--------+-----------+----------+-----------------------------------------------+
| db.t1 | histogram | status   | Histogram statistics removed for column 'c1'. |
| db.t1 | histogram | status   | Histogram statistics removed for column 'c2'. |
+--------+-----------+----------+-----------------------------------------------+
2 rows in set (0.13 sec)

  

新增innodb_dedicated_server參數

能夠讓InnoDB根據服務器上檢測到的內存大小自動配置innodb_buffer_pool_size,innodb_log_file_size,innodb_flush_method三個參數。

 

日志分類更詳細

在錯誤信息中添加了錯誤信息編號[MY-010311]和錯誤所屬子系統[Server]

# MySQL 5.7
2018-06-08T09:07:20.114585+08:00 0 [Warning] 'proxies_priv' entry '@ root@localhost' ignored in --skip-name-resolve mode.
2018-06-08T09:07:20.117848+08:00 0 [Warning] 'tables_priv' entry 'user mysql.session@localhost' ignored in --skip-name-resolve mode.
2018-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
2018-06-21T17:53:13.040295+08:00 28 [Warning] [MY-010311] [Server] 'proxies_priv'  entry '@ root@localhost' ignored in --skip-name-resolve mode.
2018-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.
2018-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.

  

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表空間超過這個值,該表空間被標記為可回收。

 

增加資源組

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=USER vcpu=0,1 thread_priority=5;
Query OK, 0 rows affected (0.03 sec)

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 |
+---------------------+---------------------+------------------------+----------+-----------------+
3 rows in set (0.00 sec)

# 把線程id為60的線程加入到資源組test_resouce_group中,線程id可通過Performance_Schema.threads獲取
mysql> SET RESOURCE GROUP test_resouce_group FOR 60;
Query OK, 0 rows affected (0.00 sec)

# 資源組里有線程時,刪除資源組報錯
mysql> drop resource group test_resouce_group;
ERROR 3656 (HY000): Resource group test_resouce_group is busy.

# 修改資源組
mysql> alter resource group test_resouce_group vcpu = 2,3 THREAD_PRIORITY = 8;
Query OK, 0 rows affected (0.10 sec)
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 |
+---------------------+---------------------+------------------------+----------+-----------------+
3 rows in set (0.00 sec)

# 把資源組里的線程移出到默認資源組USR_default
mysql> SET RESOURCE GROUP USR_default FOR 60;
Query OK, 0 rows affected (0.00 sec)

# 刪除資源組
mysql> drop resource group test_resouce_group;
Query OK, 0 rows affected (0.04 sec)

  

增加角色管理

角色可以認為是一些權限的集合,為用戶賦予統一的角色,權限的修改直接通過角色來進行,無需為每個用戶單獨授權。

# 創建角色
mysql> create role role_test;
Query OK, 0 rows affected (0.03 sec)
 
# 給角色授予權限
mysql> grant select on db.* to 'role_test';
Query OK, 0 rows affected (0.10 sec)
 
# 創建用戶
mysql> create user 'read_user'@'%' identified by '123456';
Query OK, 0 rows affected (0.09 sec)
 
# 給用戶賦予角色
mysql> grant 'role_test' to 'read_user'@'%';
Query OK, 0 rows affected (0.02 sec)
 
# 給角色role_test增加insert權限
mysql> grant insert on db.* to 'role_test';
Query OK, 0 rows affected (0.08 sec)
 
# 給角色role_test刪除insert權限
mysql> revoke insert on db.* from 'role_test';
Query OK, 0 rows affected (0.10 sec)
 
# 查看默認角色信息
mysql> select * from mysql.default_roles;
+------+-----------+-------------------+-------------------+
| HOST | USER      | DEFAULT_ROLE_HOST | DEFAULT_ROLE_USER |
+------+-----------+-------------------+-------------------+
| %    | read_user | %                 | role_test         |
+------+-----------+-------------------+-------------------+
1 row in set (0.00 sec)
 
# 查看角色與用戶關系
mysql> select * from mysql.role_edges;
+-----------+-----------+---------+-----------+-------------------+
| FROM_HOST | FROM_USER | TO_HOST | TO_USER   | WITH_ADMIN_OPTION |
+-----------+-----------+---------+-----------+-------------------+
| %         | role_test | %       | read_user | N                 |
+-----------+-----------+---------+-----------+-------------------+
1 row in set (0.00 sec)
 
# 刪除角色
mysql> drop role role_test;
Query OK, 0 rows affected (0.06 sec)

  

 

 

參考資料

官方開發手冊:https://dev.mysql.com/doc/refman/8.0/en/set-transaction.html

偏執的工匠:https://www.jianshu.com/p/be29467c2b0c

我俗人:https://blog.csdn.net/qq_32448349/article/details/81701355

菜鳥教程:mysql教程

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM