Mysql8.0新特性【詳細版本】


1.  賬戶與安全

  • 用戶創建與授權

   之前:創建用戶並授權

1 grant all privileges on *.* to 'myuser'@'%' identified by '3edc#EDC';
2 select user, host form mysql.user;

   之后:創建用戶和授權必須分開

1 create user 'myuser'@'%' identified by '3edc#EDC';
2 grant all privileges on *.* to 'myuser'@'%';
3 select user, host form mysql.user;
  • 認證插件更新
1 show variables like 'default_authentication%';
2 select user, host, plugin from mysql.user;

   之前:mysql_native_password

   之后:caching_sha2_password

1 #修改為之前的認證插件
2 #方法一 修改配置文件
3 default-authentication-plugin=mysql_native_password
4 #方法二 修改用戶密碼指定認證插件
5 alter user 'myuser'@'%' identified with mysql_native_password by '3edc#EDC';
  • 密碼管理

   【新增】允許限制使用之前的密碼。

   password_history=3 #不能和最近3天的密碼相同

   password_reuse_interval=90 #不能同90天內使用過得密碼相同

   password_require_current=on #修改密碼時需要輸入當前密碼

 1 show variables like 'password%';
 2 
 3 #修改全局密碼策略-按天設置
 4 #password_history 與 password_reuse_interval設置方法相同
 5 #方法一 添加配置文件
 6 password_history=3
 7 
 8 #方法二 持久化參數設置
 9 set persist password_history=3;
10 
11 #方法三 通過用戶設置
12 alter user 'myuser'@'%' password history 5;
13 select user, hostm password_reuse_histtory from mysql.user;
14 
15 #修改全局密碼策略-輸入密碼設置
16 #只針對普通用戶有效,針對root等具有修改mysql.user表權限的用戶無效
17 set persist password_require_current=on;
18 alert user user() identified by 'newpassword' replace 'oldpassword';
  • 角色管理

   【新增】根據角色設置用戶權限

 1 #創建角色
 2 creaye role 'role_1_wirte';
 3 #角色即用戶
 4 select user, host, authentication_string from mysql.user;
 5 #給角色授權
 6 grant insert, update, delete on test_db.* to 'role_1_wirte';
 7 #給用戶賦予角色
 8 grant 'role_1_wirte' on 'myuser';
 9 #查詢用戶權限
10 show grant for 'myuser';
11 show grant for 'myuser' using 'role_1_wirte';
12 #用戶啟用角色(普通用戶登錄)
13 set role 'role_1_wirte';
14 #設置默認角色(root用戶)
15 set default role all to 'myuser';
16 select * from mysql.default_roles;
17 select * from mysql.role_edges;
18 #撤銷角色
19 revoke insert, update, delete, select on test_db from 'role_1_wirte';
20 show grant for 'role_1_wirte';
21 show grant for 'myuser' using 'role_1_wirte';

2.  優化器索引

  • 隱藏索引(invisible index)

   【新增】不會被優化器使用,但仍然需要維護。

   應用場景:軟刪除,灰度發布。

 1 #創建數據庫、表
 2 create database test_db;
 3 use test_db;
 4 create table test1 (id int(11), parent_id int(11));
 5 #創建普通索引和隱藏索引
 6 create index id_idx on test1(id);
 7 create index parent_id_idx on test1(parent_id) invisible;
 8 #查看索引
 9 show index from test1\G
10 #查詢優化器
11 explain select * from test1 where id = 1;
12 explain select * from test1 where parent_id = 1;
13 #當前會話測試隱藏索引
14 set session optimizer_switch="use_incisible_indexes=on";
15 select @@optimizer_switch\G
16 explain select * from test1 where parent_id = 1;
17 #設置隱藏索引可見於隱藏
18 alter table test1 alter index parent_id visible;
19 alter table test1 alter index parent_id invisible;
20 #注意:主鍵不能設置隱藏索引
  • 降序索引(descending index)

   之前:雖然可指定降序索引,實為升序索引。

   之后:支持降序索引。

   進InnoDB存儲引擎支持降序索引,並且只支持BTree降序索引。

   group by不在對結果隱式排序,需要使用order by進行排序。

 1 #Mysql5.7創建降序索引
 2 create table test2 (read_num int(5), wirte_num int(5), index read_wirte_idx(read_num asc, wirte_num desc));
 3 show create table test2\G
 4 #Mysql8.0創建降序索引
 5 create table test2 (read_num int(5), wirte_num int(5), index read_wirte_idx(read_num asc, wirte_num desc));
 6 show create table test2\G
 7 insert into test2 values(100, 2),(200, 4),(300, 6);
 8 #Mysql5.7和Mysql8.0上分別測試
 9 explain select * from test2 order by read_num, wirte_num desc;
10 explain select * from test2 order by read_num desc, wirte_num;
11 #Mysql5.7和Mysql8.0上分別測試group by
12 select count(*) as cnt, wirte_num from test2 group by wirte_num;
13 select count(*) as cnt, wirte_num from test2 group by wirte_num order by wirte_num;
  • 函數索引

   之前:虛擬列創建索引。

   之后:支持索引中使用函數的值;支持降序索引;支持JSON數據索引;

   原理:基於虛擬列功能實現。

 1 #創建表和索引
 2 create table test3 ( id varchar(10), login_code varchar(20));
 3 create index login_code_func_idx on test3((upper(login_code)));
 4 show create table test3\G
 5 #測試函數索引
 6 explain select * from test3 where upper(id);
 7 explain select * from test3 where upper(login_code);
 8 #JSON索引
 9 create table test4 ( result_data json, index((cast(result_data->>'$.code' as char(3)))));
10 show create table test4\G
11 explain select * from test4 where cast(result_data->>'$.code' as char(3)) = '200';
12 #Mysql5.7虛擬列實現
13 create table test5 ( id varchar(10), login_code varchar(20));
14 alter table test5 add column username varchar(20) generated always as (upper(login_code));
15 insert into test5(id, login_code) values ('A001', 'alan');
16 create index login_code_idx on test3((upper(login_code)));
17 create index username_idx on test5(username);
18 explain select * from test5 where upper(login_code) = 'ALAN';

3.  通用表表達式

  • 非遞歸

   【新增】支持通用表達式,及WITH子句。

1 #派生語句
2 select a.* from (select 1) as a;
3 #通用表達式
4 with b as (select 1) select b.* from b;
  • 遞歸

   【新增】遞歸查詢使用recursive關鍵字。

1 #遞歸查詢組織上級組織機構
2 create table org (id int(5), parent_id int(5), org_name varchar(20));
3 insert into org values (0, null, '總公司'),(1, 0, '研發部'),(2, 1, '開發部');
4 with recursive org_paths(id, parent_id, org_name, paths) as (
5 select id, parent_id, org_name, cast(id as char(5)) as path from org where parent_id is null
6 union all 
7 select o.id, o.parent_id, o.org_name, concat(op.paths, '/', o.id) from org o join org_paths op on op.id = o.parent_id 
8 ) select * from org_paths where org_name = '開發部';
  • 遞歸限制

   【新增】遞歸查詢必須指定終止條件。

 1 #Mysql8.0提供兩個參數避免用戶未指定終止條件
 2 #① cte_max_recursion_depth
 3 #默認1000
 4 show variables like 'cte_max%';
 5 #測試-死循環
 6 with recursive cte(n) as (select 1 union all select (n+1) as n from cte) select * from cte;
 7 #當前會話/持久化設置cte_max_recursion_depth 
 8 set session cte_max_recursion_depth=10;
 9 set persist cte_max_recursion_depth=10;
10 #② max_execution_time
11 #默認無限制,單位毫秒
12 show variables like 'max_execution_time%';
13 #當前會話/持久化設置max_execution_time為1秒
14 set session max_execution_time=1000;
15 set persist max_execution_time=1000;
16 #使用遞歸生成100以內的斐波那切數列
17 with recursive cte (a, b) as ( select 0, 1 union all select b, a + b from cte where b < 100 ) select a from cte;

4.  窗口函數

  • 基本概念

   【新增】窗口函數(window function),也成為分析函數。窗口函數和分組

   聚合函數類似,但是每一行數據都會生成一個結果。

   聚合窗口函數:sum、avg、count、max、min......

1 create table sales (id int(5), item_type varchar(20), brand varchar(20), sale_value int(10));
2 insert into sales values (1, '手機', '華為', 3999),(2, '手機', '小米', 2999),(3, '手機', 'OPPO', 1999),(4, '電腦', '聯想', 7999),(5, '電腦', '戴爾', 5499),(6, '電腦', '華碩', 6899),(7, '耳機', '索尼', 120),(7, '耳機', '三星', 70);
3 #聚合函數-按商品分類統計總銷售額
4 select item_type, sum(sale_value) as total_value from sales group by item_type order by total_value desc;
5 #分析函數-按商品分類統計總銷售額
6 select id, item_type, brand, sum(sale_value) over (partition by item_type) as total_value from sales order by total_value desc;
  • 專用窗口函數
 1 create table test6(id int(2));
 2 insert into test6 values (1),(3),(4),(4),(1),(6),(2),(7),(7),(8),(9),(0),(1
 3 #增加序號列
 4 select row_number() over (order by id) as row_num, id from test6;
 5 #返回排序后的第一名
 6 select id, first_value(id) over (order by id) as first_val from test6;
 7 #返回排序后的最后一名
 8 select id, last_value(id) over (order by id) as last_val from test6;
 9 #返回每一行的后n名數據
10 select id, lead(id, 1) over (order by id) as lead_1 from test6;
11 select id, lead(id, 2) over (order by id) as lead_2 from test6;
12 #返回每一行的前n名數據
13 select id, lag(id, 1) over (order by id) as lag_1 from test6;
14 select id, lag(id, 2) over (order by id) as lag_2 from test6;
15 #查詢排序后每一行數據占據總排行榜的百分位(若為4,則為四個扇區)
16 select id, ntile(3) over (order by id) as ntile_4 from test6;
  • 窗口定義

   【新增】定義:

   window_function(expr) over (

     partition by xxx       #分組,類似於group by

     order by xxx           #排序

     frame_clause xxx   #限制窗口函數,只在當前分組有效

   )

1 #動態統計分組內的總和
2 select id, item_type, brand, sale_value, sum(sale_value) over (partition by item_type order by sale_value rows unbounded preceding) as dynamic_sum from sales order by item_type, sale_value;
3 #動態統計分組內的前一行和后一行和自己的平均值
4 select id, item_type, brand, sale_value, avg(sale_value) over (partition by item_type order by sale_value rows between 1 preceding and 1 following) as dynamic_sum from sales order by item_type, sale_value;
5 #動態統計第一名和最后一名,簡化窗口函數定義
6 select id, item_type, brand, sale_value, first_value(sale_value) over w as first_val, last_value(sale_value) over w as last_val from sales window w as (partition by item_type order by sale_value rows unbounded preceding) order by item_type, sale_value;

5.  InnoDB增強

  • 集成數據字典

   【優化】簡化information_schema表,提高訪問性能。

   提供了序列化字典信息(SDI)以及ibd2sdi工具。

1 #執行Shell
2 cd /var/lib/mysql
3 cd test_db/
4 ls
5 ibd2sdi test1.ibd > test1.sdi
6 #查看.sdi文件
7 cat test.sdi

   innodb_read_only影響所有存儲引擎;

1 show global variables like 'innodb_read_only%';
  • 原子DDL操作

   【新增】支持原子DDL操作。

   注意:與表相關的原子DDL只支持InnoDB存儲引擎。

   一個原子DDL操作包括:更新數據字典表、存儲引擎層操作、在binlog(二進制日志)中記錄DDL操作。

   支持表相關的DDL:數據庫、表空間、表、索引的create、alter、drop,以及truncate table(刪除表中所有記錄);

   支持其他的DDL:存儲過程、觸發器、視圖、UDF(自定義函數)的create、alter、drop;

   支持管理賬戶相關的DDL:用戶角色的create、alter、drop,以及適用的rename(重命名),還有grant(授權)和revoke(撤銷授權)語句。

1 create table test7 (id int(5));
2 #Mysql5.7
3 drop table test7, test77;
4 show tables;
5 #Mysql8.0
6 drop table test7, test77;
7 show tables;
8 drop table if exists test7, test77;
9 show tables; 
  • 自增列持久化

   之前:自增列計數器(auto_increment)的值只存儲在內存中。

   之后:自增列計數器的最大值寫入redo log,同時每次檢查點將其寫入引擎私有的系統表,從而解決了自增列字段值重復的bug。

 1 create table test8(id int auto_increment primary key, val varchar(5));
 2 insert into test8(val) values ('a'),('b'),('c');
 3 delete from test8 where id = 3;
 4 select * from test8;
 5 #重啟Mysql,# systemstl restart mysqld
 6 insert into test8(val) values ('d');
 7 update test8 set id = 5 where val = 'a';
 8 insert into test8(val) values ('e');
 9 
10 #查詢Mysql自增列設置
11 show variables like 'innodb_autoinc%';

   Mysql8.0之前使用innodb_autoinc_lock_mode模式為1,及每次查詢都會加鎖,同時執行2個insert語句每個10條,會保證每次插入數據的自增列的連續性,

   Mysql8.0之后使用的模式為2,及使用交叉鎖,執行相同的insert語句,不能保證自增列的連續性,但可以並發保存。

  • 死鎖檢查控制

   【新增】增量變量innodb_deadlock_detect,用於控制系統是否執行InnoDB死鎖檢查。

   高並發系統禁止死鎖檢查可能會提高性能。

 1 show variables like 'innodb_deadlock_detect';
 2 #關閉死鎖檢查
 3 set global innodb_deadlock_detect=off;
 4 #設置死鎖默認等待時長,單位為秒,默認50
 5 show variables like 'innodb_lock_wait%';
 6 set global innodb_lock_wait_timeout=5;
 7 #模擬死鎖
 8 create table test9(id int);
 9 insert into test9 values(1);
10 #窗口1
11 #開始事務
12 start transaction;
13 #開啟共享鎖
14 select * from test9 where id = 1 for share;
15 #窗口2
16 #開始事務
17 start transaction;
18 delete from test9 where id = 1;
19 #窗口1
20 delete from test9 where id = 1;
  • 鎖定語句選項

   【新增】針對於select * from t for share和select * from t for update增加nowait和skip locked行級鎖的限制。nowait表示不等待鎖,若想獲取被鎖住的數據,則立即返回不可訪問異常;skip locked表示跳過等待鎖,若想獲取被鎖住的數據,則不返回該數據。

 1 #窗口1
 2 #開啟是我
 3 start transaction;
 4 update test9 set id = 0 where id = 1;
 5 #窗口2
 6 #開啟事務
 7 start transaction;
 8 select * from test9 where id = 1 for update;
 9 #不等待鎖
10 select * from test9 where id = 1 for update nowait;
11 #跳過鎖
12 select * from test9 for update skip locked;
  • 其他
    • 刪除了之前版本的元數據文件,例如:.frm、.opt等;
    • 默認字符集由latin1變為utf8mb4;
    • 將系統表(mysql數據庫)和數據字典由之前的MyISAM存儲引擎改為InnoDB存儲引擎。支持快速DDL,alter table ... algorithm =instant;
    • InnoDB臨時表使用共享的臨時表空間ibtmp1;
    • 新增靜態變量innodb_dedicated_server,會自動配置InnoDB內存參數:innodb_buffer_pool_size、innodb_log_file_size大小。
    • 新增表information_schema.innodb_cache_indexes顯示每個索引緩存在InnoDB緩沖池中的索引頁數。
    • 新增視圖information_schema.innodb_tablespace_brief,為InnoDB表空間提供相關元數據信息。
    • 支持alter tablespace ... rename to... ,重命名通用表空間。
    • 默認創建2個undo表空間,不在使用系統表空間。
    • 支持innod_directories選項在服務器停止時將表空間文件移動到新的位置。
    • InnoDB表空間加密特性支持重做日志和撤銷日志。
    • redo & undo 日志加密,增加以下兩個參數(innodb_undo_log_encrypt、innodb_undo_log_truncate),用於控制redo、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表空間超過這個值,該表空間被標記為可回收。
    • 在sql語法中增加SET_VAR語法,動態調整部分參數,有利於提升語句性能。
1 select /*+ set_var(sort_buffer_size = 16M) */ id  from test8 order by id;
2 insert /*+ set_var(foreign_key_checks=OFF) */ into test8 (id) values(1);

6.  JSON增強

  • 內聯路徑操作符

   之前:json_unquote(column -> path) 或json_unquote(json_extract(column, path))

   之后:column ->> path

 1 with cte(data) as (select json_object('id','01','name','zhangsan')) select json_unquote(data -> '$.name') from cte;
 2 with cte(data) as (select json_object('id','01','name','zhangsan')) select json_unquote(json_extract(data, '$.name')) from cte;
 3 #使用內聯路徑操作符
 4 with cte(data) as (select json_object('id','01','name','zhangsan')) select data ->> '$.name' from cte;
 5 #區間查詢-查詢下標為1的值
 6 select json_extract('["a", "b", "c", "d", "e", "f"]', '$[1]');
 7 #區間查詢-查詢下標從0到3的值
 8 select json_extract('["a", "b", "c", "d", "e", "f"]', '$[0 to 3]');
 9 #區間查詢-查詢下標從最后3位到最后一個位的值
10 select json_extract('["a", "b", "c", "d", "e", "f"]', '$[last - 2 to last]');
  • JSON聚合函數

   【新增】Mysql8.0(Mysql5.7.22)增加了2個聚合函數:json_arrayagg()用於生產json數組,json_objectagg()用於生產json對象。

1 create table goods(id int(5), attribute varchar(10), data_value varchar(10));
2 insert into goods values (1, 'color', 'red'),(1, 'size', '10'),(2, 'color', 'green'),(2, 'size', '12');
3 #生成json數組
4 select id, json_arrayagg(attribute) as attribute_json from goods group by id;
5 #生產json對象
6 select id, json_objectagg(attribute, data_value) as attribute_json from goods group by id;
7 #對重復值處理
8 insert into goods values (2, 'color', 'white');
9 select id, json_objectagg(attribute, data_value) as attribute_json from goods group by id;
  • JSON實用函數

   【新增】Mysql8.0(Mysql5.7.22)增加了json_pretty()用於格式化json,增加了json_storage_size()用於查詢json占用空間大小;

   【新增】json_storage_free()用於查詢更新列后釋放的存儲空間。

 1 create table test10 (jdata json);
 2 insert into test10 values ('{"id" : 1, "name" : "zhangsan", "age" : 18}');
 3 #格式化json
 4 select json_pretty(jdata) from test10;
 5 #查詢json字段占用大小
 6 select json_storage_size(jdata) from test10;
 7 #更新json
 8 update test10 set jdata=json_set(jdata, "$.id", 2, "$.name", "lisi", "$.age", 4);
 9 select json_storage_size(jdata) from test10;
10 #查詢json字段更新后釋放的大小
11 select json_storage_free(jdata) from test10;
  • JSON合並函數

   【新增】Mysql8.0(Mysql5.7.22)增加了json_merge_patch()和json_merge_preserve(),用於合並json數據,區別在於前者重復屬性會使用最新的屬性值,后者會保留所有的屬性值。並且廢棄了json_merge()函數。

1 #會覆蓋舊值
2 select json_merge_patch('{"a" : 1 , "b" : 2}', '{"a" : 3, "c" : 4}');
3 #會保留所有值
4 select json_merge_preserve('{"a" : 1 , "b" : 2}', '{"a" : 3, "c" : 4}');
5 #json_merge()
6 select json_merge('{"a" : 1 , "b" : 2}', '{"a" : 3, "c" : 4}');
7 #查看警告
8 show warnings\G
  • JSON表函數

   【新增】json_table()格式化json為關系表。

 1 select
 2     *
 3 from
 4     json_table (
 5         '[{"id" : "001"}, {"id" : "002"}, {"name" : "zhangsan"}, {"id" : "003"}, {"id" : [1, 2]}]',
 6         "$[*]" columns (
 7             row_num for ordinality,
 8             uid varchar (20) path "$.id" default '999' on error default '111' on empty,
 9             user_details json path "$.name" default '{}' on empty,
10             is_exists_name int exists path "$.name"
11         )
12     ) as t;


免責聲明!

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



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