【Mysql】Mysq8.0新特性

一.MySQL8.0簡介mysql

 

  mysql8.0如今已經發布,2016-09-12第一個DM(development milestone)版本8.0.0發佈。新的版本帶來不少新功能和新特性,對性能也獲得了很大對提高。官方表示 MySQL 8 比以前mysql版本有很大提高,它的速度是 MySQL 5.7 2 倍,以下圖對比所示算法

  mysql8.0官方文檔: https://dev.mysql.com/doc/refman/8.0/en/ sql

 

二.MySQL8.0新增的特性docker

  mysql8.0新增的特性主要有如下幾個方面:數據庫

  1.帳戶與安全express

    1)用戶建立和受權是分開的,並修改了默認的認證插件。編程

    2)增長了密碼重用策略,支持修改密碼時要求用戶輸入當前密碼。json

    3)支持角色功能。數組

      提升了用戶和密碼管理的安全性,方便了權限的管理。緩存

  2.優化器索引

    三種新的索引方式

    1)支持隱藏索引,方便索引的維護和性能調試。

    2)支持降序索引,提升了特定場景的查詢性能。

    3)支持函數索引,擴展了索引支持的數據類型,能夠對更多的數據類型進行索引。

  3.通用表表達式(Common Table Expressions:CTE)

    1)非遞歸CTE,提升查詢的性能和代碼的可讀性。

    2)遞歸CTE,支持經過對數據遍歷和遞歸的實現完成SQL實現強大複雜的功能。

  4.窗口函數(Window Functions)

    是一種新的查詢方式。窗口函數有兩類,一類上傳統的聚合函數做爲窗口函數使用,另外一類是專用的窗口函數。能夠實現複雜的數據分析能力。

  5.InnoDB存儲引擎加強

    1)新的數據字典能夠對元數據統一的管理,同時也提升了更好的查詢性能和可靠性。

    2)原子DDL的操做,提供了更加可靠的管理。

    3)自增列的持久化,解決了長久以來自增列重複值的bug。

    4)死鎖檢查控制,能夠選擇在高併發的場景中關閉,提升對高併發場景的性能。

    5)鎖定語句選項,能夠根據不一樣業務需求來選擇鎖定語句級別。

  6.JSON加強

     新的運算符及JSON相關函數。

  mysql8.0新特性更多能夠查看這篇:https://mysqlserverteam.com/whats-new-in-mysql-8-0-generally-available/

 

二.本機操做環境

  先看下本機mysql環境和狀態

mysql> show variables like '%%version%';
+--------------------------+------------------------------+ | Variable_name | Value | +--------------------------+------------------------------+ | immediate_server_version | 999999 | | innodb_version | 8.0.16 | | original_server_version | 999999 | | protocol_version | 10 | | slave_type_conversions | | | tls_version | TLSv1,TLSv1.1,TLSv1.2 | | version | 8.0.16 | | version_comment | MySQL Community Server - GPL | | version_compile_machine | x86_64 | | version_compile_os | Linux | | version_compile_zlib | 1.2.11 | +--------------------------+------------------------------+

 查看狀態

mysql80>status
--------------
mysql  Ver 14.14 Distrib 5.7.26, for Linux (x86_64) using  EditLine wrapper

Connection id:        2
Current database:    
Current user:        root@localhost
SSL:            Not in use
Current pager:        stdout
Using outfile:        ''
Using delimiter:    ;
Server version:        5.7.26 MySQL Community Server (GPL)
Protocol version:    10
Connection:        Localhost via UNIX socket
Server characterset:    latin1
Db     characterset:    latin1
Client characterset:    latin1
Conn.  characterset:    latin1
UNIX socket:        /var/run/mysqld/mysqld.sock
Uptime:            27 min 38 sec

 

三.MySQL8.0新特性

   帳戶與安全變動:增長新的安全策略,增長角色功能。

       1.建立用戶和用戶受權的命令是分開執行

    先看下mysql5.7是如何建立用戶和受權的。

    mysql5.7中查詢默認用戶,如下是mysql5.7中的默認的三個用戶。

mysql5.7> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+

    mysq5.7grant能夠完成用戶建立和受權同時操做。

mysql> grant all privileges on *.* to 'song'@'%' identified by 'song@2019';    #建立新的用戶並賦予在全部主機登錄及密碼
mysql> select user,host from mysql.user;
+---------------+-----------+
| user          | host      |
+---------------+-----------+
| root          | %         |
| song          | %         |
| mysql.session | localhost |
| mysql.sys     | localhost |
| root          | localhost |
+---------------+-----------+

 

    mysql8.0建立用戶和受權命令以下,分兩步進行。

create user 'song'@'%' identified by 'Song@2019'; //建立用戶 grant all privileges on *.* to 'song'@'%'; //受權

    mysql8.0

mysql> select host,user from mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| localhost | mysql.infoschema |
| localhost | mysql.session    |
| localhost | mysql.sys        |
| localhost | root             |
+-----------+------------------+

    建立用戶

mysql> create user 'song'@'%' identified by 'song@2019';
mysql> select host,user from mysql.user;
+-----------+------------------+
| host      | user             |
+-----------+------------------+
| %         | song             |
| localhost | mysql.infoschema |
| localhost | mysql.session    |
| localhost | mysql.sys        |
| localhost | root             |

    受權 

mysql> grant all privileges on *.* to 'song'@'%';                              

    這樣分兩次的好處是語句的語義更加清晰點。

 

   2.認證的插件更新

     mysql8.0中默認的身份認證插件是caching_sha2_password,替代了以前的mysql_navtive_password,這個新的認證會更加安全。

   經過系統變量查詢,下面這是mysql5.7的,發現mysql5.7仍是使用mysql_native_password這個插件。
mysql> show variables like 'default_authentication%';       
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | mysql_native_password |
+-------------------------------+-----------------------+

   看下mysq8.0

mysql> show variables like 'default_authentication%';
+-------------------------------+-----------------------+
| Variable_name                 | Value                 |
+-------------------------------+-----------------------+
| default_authentication_plugin | caching_sha2_password |
+-------------------------------+-----------------------+

  也能夠經過用戶表user查看plugin這一列。

mysql> select user,host,plugin from mysql.user;
+------------------+-----------+-----------------------+
| user             | host      | plugin                |
+------------------+-----------+-----------------------+
| root             | %         | caching_sha2_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session    | localhost | caching_sha2_password |
| mysql.sys        | localhost | caching_sha2_password |
| root             | localhost | caching_sha2_password |
+------------------+-----------+-----------------------+

 

   不過若是鏈接客戶端比較老舊沒有升級,在鏈接mysql8.0時候可能會認證錯誤。若是想要使用以前老的認證方式能夠在配置文件裏將default-authentication-plugin這段開啓,而後重啓數據庫。

   

  若是想對某個用戶使用老的認證方式,可使用下面語句

alter user 'song'@'%' identified with mysql_native_password by 'Songpasswd';

   with後面能夠跟新的認證插件也能夠是老的認證插件。

  

  3.密碼管理策略加強

    mysql8.0開始容許限制重複使用之前的密碼。也就是說在修改密碼的時候不能改成之前使用過的密碼。

    mysql8.0中有幾個系統變量來實現控制密碼修改策略。

      1)password_history:該參數數值用於設置歷史密碼能夠再次使用以前須要進行密碼修改的次數。好比password_history = 3 就是表明新密碼不能和最近使用過3次的密碼相同。設置爲0則不會對歷史密碼是否能夠重用進行限制。

      2)password_reuse_interval:按照日期指定來限制,好比 password_reuse_interval = 60 表示新密碼不能和60天以內的密碼相同,默認值爲0,設置爲0則不會對歷史密碼重用進行時間間隔設置。

      3)password_require_current:默認值是OFF,當值爲ON時候用戶修改密碼時候是否須要提供當前密碼。

 查看變量,都是以password開頭的。

mysql> show variables like 'password%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| password_history         | 0     |
| password_require_current | OFF   |
| password_reuse_interval  | 0     |
+--------------------------+-------+

    默認狀況下password_historypassword_reuse_interval的值是0,表示不作限制,而password_require_current的值是off,也就是說默認狀況下這些值都是沒有啓用的。

    設置方式,在以前mysql版本中若是給運行中mysql修改參數只能在當前mysql進程中設置,可是mysql重啓後就會失效,二若是寫入配置文件my.cnf裏則須要重啓服務,這兩種方法都不太方便,而在mysql8.0增長了新特性就是在線修改系統變量,並將修改後的持久化到磁盤,重啓服務依然有效。它在mysql目錄下增長了一個配置文件mysqld-auto.cnf。

mysql> set persist password_history=6;
mysql> show variables like 'password%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| password_history         | 6     |
| password_require_current | OFF   |
| password_reuse_interval  | 0     |
+--------------------------+-------+

     查看mysqld-auto.cnf,這是一個json格式的配置文件。mysql服務器在重啓的時候就會讀取這個文件。

root@f488b1c2586a:/# cat /var/lib/mysql/mysqld-auto.cnf 
{ "Version" : 1 , "mysql_server" : { "password_history" : { "Value" : "6" , "Metadata" : { "Timestamp" : 1563796829915492 , "User" : "root" , "Host" : "localhost" } } } }

     對於的修改也能夠針對用戶去修改。

mysql> select user,host,Password_reuse_history from mysql.user;   #先查看
+------------------+-----------+------------------------+
| user             | host      | Password_reuse_history |
+------------------+-----------+------------------------+
| root             | %         |                   NULL |
| song             | %         |                   NULL |
| mysql.infoschema | localhost |                   NULL |
| mysql.session    | localhost |                   NULL |
| mysql.sys        | localhost |                   NULL |
| root             | localhost |                   NULL |
+------------------+-----------+------------------------+

mysql> alter user 'song'@'%' password history 10;                 #設置10

mysql> select user,host,Password_reuse_history from mysql.user;   #查看設置成功
+------------------+-----------+------------------------+
| user             | host      | Password_reuse_history |
+------------------+-----------+------------------------+
| root             | %         |                   NULL |
| song             | %         |                     10 |
| mysql.infoschema | localhost |                   NULL |
| mysql.session    | localhost |                   NULL |
| mysql.sys        | localhost |                   NULL |
| root             | localhost |                   NULL |
+------------------+-----------+------------------------+

    設置成功能夠測試下,發現密碼不可修改並報錯。

mysql> alter user 'song'@'%' identified by 'song_passwd';
ERROR 3689 (HY000): Cannot use these credentials for 'song'@'%' because they contradict the password history policy

 

  4.角色管理

    mysql8.0提供了角色管理新功能,角色是一組權限的集合。

    在以前的mysql版本中,要給某些用戶分配權限須要一個個分配。若是用戶比較多,角色也比較多,手動分配管理起來就比較麻煩。

    

    新的版本有了角色功能以後,在權限和用戶之間加了一層角色。能夠將一組定義好的權限賦予某個角色,能夠在將角色分配給須要的用戶。這樣能夠簡化用戶權限的管理。

 

    步驟:

      1.先建立角色

      2.給這個角色賦予事先定義好的權限。

      3.給角色受權給某個用戶。

 

    操做流程:

操做步驟 說明
mysql> create database roleDB ; 建立一個數據庫
create table roleDB.table_auth(id int); 建立一張表
create role 'write_role'; 建立一個角色
mysql> select host,user,authentication_string from mysql.user;
+-----------+------------------+------------------------------------------------------------------------+
| host      | user             | authentication_string                                                  |
+-----------+------------------+------------------------------------------------------------------------+
| %         | root             | $A$005$OI6M7iPSa8RTaSQ4NXvRjLWQ2Qf3JUMlS1NrQTPdvhEUh/bfIIdBj. |
| %         | song             | $A$005$GAy/g`mMyQa.gojqBMnFSqaTpD6DZFZPExMVjFmxVDU45RkiAvsH4qFb9Y9 |
| %         | write_role       |                                                                        |
| localhost | mysql.infoschema | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.session    | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | mysql.sys        | $A$005$THISISACOMBINATIONOFINVALIDSALTANDPASSWORDTHATMUSTNEVERBRBEUSED |
| localhost | root             | $A$005$rX oqug@
~HH%H XLsY.hAnb2p8G5JXazsp/2qDxaSLEZpDVVfRnSKrre6 |
+-----------+------------------+------------------------------------------------------------------------+

查看用戶信息表,

這裏write_role是一個沒有密碼的用戶,

能夠看出mysql裏的角色實際上是一個用戶。

是用用戶來模擬角色的效果。

mysql> grant select,insert,update,delete on roleDB.* to 'write_role';
Query OK, 0 rows affected (0.01 sec)

受權,授予roleDB庫上的增刪改查權限,

這裏對角色和用戶的受權語法都是

同樣的。

mysql> create user 'yonhu_role1' identified by 'password123';
Query OK, 0 rows affected (0.01 sec)

建立用戶並賦予密碼

mysql> grant 'write_role' to 'yonhu_role1';
Query OK, 0 rows affected (0.00 sec)

將角色授予用戶

mysql> show grants for 'yonhu_role1';
+---------------------------------------------+
| Grants for yonhu_role1@%                    |
+---------------------------------------------+
| GRANT USAGE ON *.* TO `yonhu_role1`@`%`     |
| GRANT `write_role`@`%` TO `yonhu_role1`@`%` |
+---------------------------------------------+

顯示用戶的權限

第一條是默認使用權限

第二條就是剛剛賦予的角色

mysql> show grants for 'yonhu_role1' using 'write_role';
+-----------------------------------------------------------------+
| Grants for yonhu_role1@%                                        |
+-----------------------------------------------------------------+
| GRANT USAGE ON *.* TO `yonhu_role1`@`%`                         |
| GRANT SELECT,INSERT, UPDATE, DELETE ON `roleDB`.* TO `yonhu_role1`@`%` |
| GRANT `write_role`@`%` TO `yonhu_role1`@`%`                     |
+-----------------------------------------------------------------+

具體查看用戶角色擁有的權限

exit

退出

root@f488b1c2586a:/# mysql -uyonhu_role1 -p

mysql> select user();
+-----------------------+
| user()                |
+-----------------------+
| yonhu_role1@localhost |
+-----------------------+

用yonhu_role1用戶登錄


mysql> select * from roleDB.table_auth;
ERROR 1142 (42000): SELECT command denied to user 'yonhu_role1'@'localhost' for table 'table_auth'

實際table_auth表上存在的,也

擁有權限去查詢。

mysql> select current_role();
+----------------+
| current_role() |
+----------------+
| NONE           |
+----------------+

查看當前角色,默認沒有激活

這就是無法查詢緣由。

 

mysql> set role 'write_role';
Query OK, 0 rows affected (0.01 sec)

mysql> select current_role();
+------------------+
| current_role()   |
+------------------+
| `write_role`@`%` |
+------------------+

mysql> select * from roleDB.table_auth;
Empty set (0.01 sec)

設置角色,再次查詢就能夠

root@f488b1c2586a:/# mysql -uroot -p

mysql> set default role 'write_role' to 'yonhu_role1';
Query OK, 0 rows affected (0.01 sec)

爲每一個用戶設置默認角色

mysql> select * from mysql.default_roles;
+------+-------------+-------------------+-------------------+
| HOST | USER        | DEFAULT_ROLE_HOST | DEFAULT_ROLE_USER |
+------+-------------+-------------------+-------------------+
| %    | yonhu_role1 | %                 | write_role        |
+------+-------------+-------------------+-------------------+

mysql> select * from mysql.role_edges;
+-----------+------------+---------+-------------+-------------------+
| FROM_HOST | FROM_USER  | TO_HOST | TO_USER     | WITH_ADMIN_OPTION |
+-----------+------------+---------+-------------+-------------------+
| %         | write_role | %       | yonhu_role1 | N                 |
+-----------+------------+---------+-------------+-------------------+

查看用戶角色信息,這個是mysql8

新增長的表。

下面是用戶鎖設計到角色的信息。

     也能夠撤銷角色

mysql> revoke insert,update,delete on roleDB.* from 'write_role';

mysql> show grants for 'write_role';
+------------------------------------------------+
| Grants for write_role@%                        |
+------------------------------------------------+
| GRANT USAGE ON *.* TO `write_role`@`%`         |
| GRANT SELECT ON `roleDB`.* TO `write_role`@`%` |
+------------------------------------------------+
2 rows in set (0.00 sec)

mysql> show grants for yonhu_role1;
+---------------------------------------------+
| Grants for yonhu_role1@%                    |
+---------------------------------------------+
| GRANT USAGE ON *.* TO `yonhu_role1`@`%`     |
| GRANT `write_role`@`%` TO `yonhu_role1`@`%` |

 

 

  優化器索引

        mysq8.0增長了三種新的索引方式,降序索引,影藏索引,函數索引。

    1.隱藏索引(invisiable index):也叫作不可見索引,它不會被優化器使用,也就是對優化器不可見,可是但仍然須要維護。

      應用場景:

        1)軟刪除:能夠先隱藏索引,查詢優化器不會使用該索引,可是索引仍是在維護,當最終確認刪除後系統不受影響,就能夠完全刪除索引)。

        2)灰度發佈:測試一些索引功能,在線上測試,查詢不會影響,確認索引有效,某些功能受能用到的,在將索引可見)。

        3)新索引替換老索引

mysql> create table user(i int,j int);
mysql> create index i_index on user(i);
mysql> create index j_index on user(j) invisible;

  顯示索引信息

mysql> show index from user\G;
*************************** 1. row ***************************
        Table: user
   Non_unique: 1
     Key_name: i_index
 Seq_in_index: 1
  Column_name: i
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: user
   Non_unique: 1
     Key_name: j_index
 Seq_in_index: 1
  Column_name: j
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: NO
   Expression: NULL
2 rows in set (0.06 sec)

  查看執行計劃任務

mysql> explain select * from user where i=1;
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | user  | NULL       | ref  | user_index    | i_index | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+

mysql> explain select * from user where j=1;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | user  | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

   查看查詢優化器開關

mysql> select @@optimizer_switch\G;
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,
engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,
materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,
use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=off,skip_scan=on 1 row in set (0.00 sec)

  在會話級別打開它

mysql> set session optimizer_switch="use_invisible_indexes=on";

mysql> select @@optimizer_switch\G;
*************************** 1. row ***************************
@@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,
engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,
materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,
use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,use_invisible_indexes=on,skip_scan=on

  設置成功,查詢發現已經打開.

  在此查看,可使用不可見索引

mysql> explain select * from user where j=1;
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key     | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | user  | NULL       | ref  | j_index       | j_index | 5       | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+---------+---------+-------+------+----------+-------+

  咱們能夠在某個特定的會話中,打開開關測試語句。

  修改可見/不可見屬性

mysql> alter table user alter index i_index visible;

       注意

    主鍵不能夠設置不可見。由於也沒啥意義。

 

  2.降序索引(descending index)

    1)mysql8.0開始真正支持降序索引,在以前的mysql版本中也支持這種降序(DESC)索語法定義,但實際上mysql server會忽略這個定義,建立的仍是升序索引(ASC)。

      咱們一般使用下面的語句來建立一個索引:

      create index idx_t1_bcd on t1(b,c,d);

      上面sql的意思是在t1表中,針對b,c,d三個字段建立一個聯合索引。

      可是你們不知道的是,上面這個sql實際上和下面的這個sql是等價的:

      create index idx_t1_bcd on t1(b asc,c asc,d asc);

    2)目前只有innodb存儲引擎支持降序索引,只支持BTREE降序索引。

    3)因爲降序索引引入,mysql8.0再也不對group by 操做進行隱式排序,若是須要進行order by指明處理。

    4)降序索引帶來了性能的改進。

 

 mysql5.7中

mysql> create table tablename1 (a int , b int, index idx1 (a asc,b desc));
Query OK, 0 rows affected (0.02 sec)

mysql> show create table tablename1;
+------------+----------------------------------------------------+
| Table      | Create Table                                       |
+------------+----------------------------------------------------+
| tablename1 | CREATE TABLE `tablename1` (
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  KEY `idx1` (`a`,`b`)                        #雖然在語句中指定來a升序,b字段降序,可是這裏都是默認升序
) ENGINE=InnoDB DEFAULT CHARSET=latin1 |
+------------+----------------------------------------------------+
1 row in set (0.00 sec)

 

mysql8.0

mysql8> create table user2(a1 int,a2 int,index(a1 asc,a2 desc));

mysql> show create table user2\G;
*************************** 1. row ***************************
       Table: user2
Create Table: CREATE TABLE `user2` (
  `a1` int(11) DEFAULT NULL,
  `a2` int(11) DEFAULT NULL,
  KEY `a1` (`a1`,`a2` DESC) #a2 後面有個desc 是真正的降序
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

 插入一些數據

mysql8> insert into user2(a1,a2) values(1,100),(2,200),(3,150),(4,50);
Query OK, 4 rows affected (0.02 sec)
Records: 4  Duplicates: 0  Warnings: 0

mysql> select * from user2;
+------+------+
| a1   | a2   |
+------+------+
|    1 |  100 |
|    2 |  200 |
|    3 |  150 |
|    4 |   50 |
+------+------+

 

執行優化器,查詢使用a1升序,a2降序,查看索引使用狀況。

mysql8> explain select * from user2 order by a1,a2 desc;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | user2 | NULL       | index | NULL          | a1   | 10      | NULL |    4 |   100.00 | Using index |    組合排序仍然可使用到索引a1
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+

 

可使用到索引

mysql5.7

mysql> explain select * from user2 order by a1,a2 desc;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                       |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+
|  1 | SIMPLE      | user2 | NULL       | index | NULL          | a1   | 10      | NULL |    4 |   100.00 | Using index; Using filesort |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------------+
1 row in set, 1 warning (0.00 sec)

 

 mysql5.7中雖然使用到了索引,可是還須要額外的排序操做,不能直接經過索引來獲得咱們鎖須要的順序。

當在mysql8.0執行相反查詢的時候。

mysql> explain select * from user2 order by a1 desc ,a2 ;
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                            |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------+
|  1 | SIMPLE      | user2 | NULL       | index | NULL          | a1   | 10      | NULL |    4 |   100.00 | Backward index scan; Using index | #從大到小的掃描
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+----------------------------------+

 

不只用到了索引,還用到反向索引掃描。

上面就是新的降序索引帶來的性能的改進。

另外對group by不會默認的排序。隨機返回。

mysql8> select count(*) , a2 from user2 group by a2;
+----------+------+
| count(*) | a2   |
+----------+------+
|        1 |  100 |
|        1 |  200 |
|        1 |  150 |
|        1 |   50 |
+----------+------+
4 rows in set (0.00 sec)

 mysql8增長order by纔有排序效果

 

mysql5.7默認增長order by排序

mysql5.7> select count(*) , a2 from user2 group by a2;
+----------+------+
| count(*) | a2   |
+----------+------+
|        1 |   50 |
|        1 |  100 |
|        1 |  150 |
|        1 |  200 |
+----------+------+

 

mysql8 增長order by 就和mysql5.7同樣,有排序的效果。

mysql8> select count(*) , a2 from user2 group by a2 order by a2;
+----------+------+
| count(*) | a2   |
+----------+------+
|        1 |   50 |
|        1 |  100 |
|        1 |  150 |
|        1 |  200 |
+----------+------+

 

   3.函數索引

    mysql8.0.13開始支持在索引中使用函數(表達式)的值,以前是使用列值,如今可使用函數表達式的值使用索引,同時也支持降序索引,json數據的索引。以前版本的數據庫是無法對json裏各個節點的數據索引,函數索引是基於虛擬計算列功能來實現的。能夠方便對json格式數據的查詢。

mysql> create table user3(c1 varchar(10),c2 varchar(10));
mysql> create index index1 on user3(c1);
mysql> create index func_index on user3( (UPPER(c2)) );   #函數索引用大括號包起來

查看索引狀況

mysql> show index from user3\G;
*************************** 1. row ***************************
        Table: user3
   Non_unique: 1
     Key_name: index1
 Seq_in_index: 1
  Column_name: c1
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: NULL
*************************** 2. row ***************************
        Table: user3
   Non_unique: 1
     Key_name: func_index
 Seq_in_index: 1
  Column_name: NULL
    Collation: A
  Cardinality: 0
     Sub_part: NULL
       Packed: NULL
         Null: YES
   Index_type: BTREE
      Comment:
Index_comment:
      Visible: YES
   Expression: upper(`c2`) 2 rows in set (0.11 sec)

 

mysql> explain select * from user3 where upper(c1)='ABC';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | user3 | NULL       | ALL  | NULL          | NULL | NULL    | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

mysql> explain select * from user3 where upper(c2)='ABC';
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key        | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | user3 | NULL       | ref  | func_index    | func_index | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------------+---------+-------+------+----------+-------+

 

 分析:雖然有c1索引,可是仍是全表掃描

 

 針對json節點的索引

mysql> create table table_json (data json , index ((CAST(data->>'$.name' as char(30)) )));

mysql> show index from table_json;
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+---------------------------------------------------------------------------------------+
| Table      | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible | Expression                                                                            |
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+---------------------------------------------------------------------------------------+
| table_json |          1 | functional_index |            1 | NULL        | A         |           0 |     NULL |   NULL | YES  | BTREE      |         |               | YES     | cast(json_unquote(json_extract(`data`,_latin1\'$.name\')) as char(30) charset latin1) |
+------------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+---------------------------------------------------------------------------------------+

 

cast函數做爲類型轉換 成char(30)  ->>是新的json運算符,就是去name的值

mysql> explain select * from table_json where CAST(data->>'$.name' as char(30)) = 'aaa';
+----+-------------+------------+------------+------+------------------+------------------+---------+-------+------+----------+-------+
| id | select_type | table      | partitions | type | possible_keys    | key              | key_len | ref   | rows | filtered | Extra |
+----+-------------+------------+------------+------+------------------+------------------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | table_json | NULL       | ref  | functional_index | functional_index | 33      | const |    1 |   100.00 | NULL  |
+----+-------------+------------+------------+------+------------------+------------------+---------+-------+------+----------+-------+

 

函數計算列

mysql> create table user3 (a1 varchar(10),a2 varchar(10));

mysql> desc user3;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a1    | varchar(10) | YES  |     | NULL    |       |
| a2    | varchar(10) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+

添加數據

mysql> alter table user3 add column a3 varchar(10) generated always as (upper(a1));
Query OK, 0 rows affected (0.03 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> insert into user3(a1,a2) values ('abc','abc');
Query OK, 1 row affected (0.01 sec)

mysql> select * from user3;
+------+------+------+
| a1   | a2   | a3   |
+------+------+------+
| abc  | abc  | ABC  |
+------+------+------+

 

c3列是基於c1列大寫的形式計算出來的。

mysql> create index idx3 on user3(a3);
Query OK, 0 rows affected (0.04 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain select * from user3 where upper(a1) = 'ABC';
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | user3 | NULL       | ref  | idx3          | idx3 | 43      | const |    1 |   100.00 | NULL       |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+

 

達到了與函數索引同樣的效果

 

 

通用表表達式(CTE)

  即with子句,是sql語句的加強,通用表達式在sql2003標準(https://en.wikipedia.org/wiki/SQL:2003)中就引入了,不少主流數據庫都有該功能,mysql8.0也是擁有了該功能。

  1.非遞歸CTE

    派生表:select * from (select 1) as dt;

    通用表表達式:with cte as (select 1)select * from cte;就至關於一個變量,在後面語句中使用。

mysql> select * from (select 1) as dt;
+---+
| 1 |
+---+
| 1 |
+---+

mysql> with dt as (select 1)
    -> select * from dt;
+---+
| 1 |
+---+
| 1 |
+---+

寫法更加清晰

mysql> with cte1(id) as (select 1),
    -> cte2(id) as (select id+1 from cte1)
    -> select * from cte1 join cte2;
+----+----+
| id | id |
+----+----+
|  1 |  2 |
+----+----+

 

   2.遞歸CTE

    在查詢中引用本身的定義,使用RECURSIVE表示。和編程語言中的遞歸函數調用差很少。生成一些模擬數據也比較方便

mysql> with recursive cte (n) as
    -> (
    -> select 1
    -> union all
    -> select n + 1 from cte where n <10
    -> )
    -> select * from cte;
+------+
| n    |
+------+
|    1 |
|    2 |
|    3 |
|    4 |
|    5 |
|    6 |
|    7 |
|    8 |
|    9 |
|   10 |
+------+

 

 無限級分類表

mysql> create table employee (id int,name varchar(20),manager_id int);
mysql> insert into employee values(29,'song',198),(72,'lucy',29),(123,'adil',692),(198,'join',333),(333,'yaml',NULL),(692,'cady',333),(700,'sarac',29);
mysql> select * from employee;
+------+-------+------------+
| id   | name  | manager_id |
+------+-------+------------+
|   29 | song  |        198 |
|   72 | lucy  |         29 |
|  123 | adil  |        692 |
|  198 | join  |        333 |
|  333 | yaml  |       NULL |
|  692 | cady  |        333 |
|  700 | sarac |         29 |
+------+-------+------------+

 

 實例

mysql> with recursive employee_paths(id,name,path) as
    -> (
    -> select id,name,cast(id as char(200))
    -> from employee
    -> where manager_id is null
    -> union all
    -> select e.id,e.name,concat(ep.path,',',e.id)
    -> from employee_paths as ep join employee as e
    -> on ep.id = e.manager_id
    -> )
    -> select * from employee_paths order by path;
+------+-------+----------------+
| id   | name  | path           |
+------+-------+----------------+
|  333 | yaml  | 333            |
|  198 | join  | 333,198        |
|   29 | song  | 333,198,29     |
|  700 | sarac | 333,198,29,700 |
|   72 | lucy  | 333,198,29,72  |
|  692 | cady  | 333,692        |
|  123 | adil  | 333,692,123    |
+------+-------+----------------+

 

 遞歸cte注意次數限制,遞歸表達式要包含一個終止遞歸的條件,避免死循環。

 mysql8.0提供了參數cte_max_recursion_depth:最大遞歸深度,  max_execution_time:sql語句最大執行時間。

mysql> with recursive cte(n) as
    -> (
    -> select 1
    -> union all
    -> select n+1 from cte
    -> )
    -> select * from cte;
ERROR 3636 (HY000): Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.

 在第1001次阻斷

mysql> show variables like 'cte_max%';
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| cte_max_recursion_depth | 1000  |
+-------------------------+-------+

mysql> set session cte_max_recursion_depth=10;

 

0表示無限制  1000毫秒=1秒

 通用表表達式和派生表很相似,就像語句級別的臨時表和試圖,用派生表的地方就能夠用通用表表達式,語意更加清晰點。

  cte能夠在查詢中屢次引用,也能夠引用其餘的cte

  cte支持select/insert/update/delete等語句

 

  好比使用遞歸CTE生成斐波那契數列。

 

   窗口函數(window function)

   也稱呼爲分析函數,爲sql語句提供強大的數據分析功能,能夠經過sql語句作一些數據分析。

      窗口函數與分組聚合函數相似,可是每一行數據都生成一個結果,就是主要對數據進行分組group by操做,而後對每個組聚合產生一個結果,好比組內的平均數,組內的組合等等。窗口函數與之類似也能夠分組,不一樣的地方在於,針對分組內的每個行都會生成相應的一個結果,因此結果和行數上相同的。

 

       窗口函數定義

        

      over是關鍵字,用來指定函數執行的窗口範圍,內部能夠指定三個選項,第一個是先對數據進行分組,第二個是對分組的數據進行排序,第三個進一步操做。

 

常見聚合窗口函數:SUM / AVG / COUNT / MAX / MIN 等等。

mysql> insert into sales values (2000,'Finland','Computer',1500),(2001,'USA','Phone',1200),(2001,'Finland','Phone',10),(2000,'India','Calculator',75),
(2001,'USA','TV',150),(2000,'India','Computer',1200),(2000,'USA','Calculator',5),(2000,'USA','Computer',1500),(2000,'Finland','Phone',100),
(2001,'USA','Calculator',50),(2001,'USA ',' TV',100); mysql> select * from sales; +------+---------+------------+--------+ | year | country | product | profit | +------+---------+------------+--------+ | 2000 | Finland | Computer | 1500 | | 2001 | USA | Phone | 1200 | | 2001 | Finland | Phone | 10 | | 2000 | India | Calculator | 75 | | 2001 | USA | TV | 150 | | 2000 | India | Computer | 1200 | | 2000 | USA | Calculator | 5 | | 2000 | USA | Computer | 1500 | | 2000 | Finland | Phone | 100 | | 2001 | USA | Calculator | 50 | | 2001 | USA | Computer | 1500 | | 2000 | India | Calculator | 75 | | 2001 | USA | TV | 100 | +------+---------+------------+--------+

 

mysql> select country,sum(profit) as country_profit
    -> from sales
    -> group by country
    -> order by country;
+---------+----------------+
| country | country_profit |
+---------+----------------+
| Finland |           1610 |
| India   |           1350 |
| USA     |           4505 |

 

mysql> select year,country,product,profit,
    -> sum(profit) OVER (partition by country) as country_profit
    -> from sales
    -> order by country,year,product,profit;
+------+---------+------------+--------+----------------+
| year | country | product    | profit | country_profit |
+------+---------+------------+--------+----------------+
| 2000 | Finland | Computer   |   1500 |           1610 |
| 2000 | Finland | Phone      |    100 |           1610 |
| 2001 | Finland | Phone      |     10 |           1610 |
| 2000 | India   | Calculator |     75 |           1350 |
| 2000 | India   | Calculator |     75 |           1350 |
| 2000 | India   | Computer   |   1200 |           1350 |
| 2000 | USA     | Calculator |      5 |           4505 |
| 2000 | USA     | Computer   |   1500 |           4505 |
| 2001 | USA     | Calculator |     50 |           4505 |
| 2001 | USA     | Computer   |   1500 |           4505 |
| 2001 | USA     | Phone      |   1200 |           4505 |
| 2001 | USA     | TV         |    100 |           4505 |
| 2001 | USA     | TV         |    150 |           4505 |
+------+---------+------------+--------+----------------+

 

使用窗口函數,每一行都出現,保留了原來的數據結構,在原來基礎上增長一些分析出來結果列,而不像分組聚合函數那樣。分析數據可使用

 前四列是原始數據

 窗口函數不須要在加group by了。

 

專用窗口函數

   獲取排名函數

   ROW_NUMBER() / RANK() /DENSE_RANK() / PERCENT_RANK()

   FIRST_VALUE() / LAST_VALUE() / LEAD() / LAG()

   CUME_DIST() / NTH_VALUE() / NTILE()

   

mysql> insert into numbers values (1),(1),(2),(3),(3),(3),(3),(4),(4),(5);
Query OK, 10 rows affected (0.01 sec)
Records: 10  Duplicates: 0  Warnings: 0

mysql> select * from numbers;
+------+
| nums |
+------+
|    1 |
|    1 |
|    2 |
|    3 |
|    3 |
|    3 |
|    3 |
|    4 |
|    4 |
|    5 |
+------+

 

排名

mysql> select nums , row_number() OVER (order by nums) as 'row_number' from numbers;
+------+------------+
| nums | row_number |
+------+------------+
|    1 |          1 |
|    1 |          2 |
|    2 |          3 |
|    3 |          4 |
|    3 |          5 |
|    3 |          6 |
|    3 |          7 |
|    4 |          8 |
|    4 |          9 |
|    5 |         10 |
+------+------------+

 

mysql> select nums,
    -> first_value(nums) over (order by nums) as 'first',
    -> lead(nums,1) over (order by nums) as 'lead'
    -> from numbers;
+------+-------+------+
| nums | first | lead |
+------+-------+------+
|    1 |     1 |    1 |
|    1 |     1 |    2 |
|    2 |     1 |    3 |
|    3 |     1 |    3 |
|    3 |     1 |    3 |
|    3 |     1 |    3 |
|    3 |     1 |    4 |
|    4 |     1 |    4 |
|    4 |     1 |    5 |
|    5 |     1 | NULL |
+------+-------+------+

 

 

Innodb存儲引擎改進

  Innodb存儲引擎成爲mysql默認存儲引擎後,功能一直在改進,mysql8.0中innodb的功能也獲得加強。

    1.集成數據字典

    mysql8.0從新重構了數據字典

      1)刪除了以前元數據文件關於數據庫等信息,例如.frm .opt等基於文件等數據庫信息。

      mysql5.7

root@4a68d9279589:/# cd /var/lib/mysql
root@4a68d9279589:/var/lib/mysql# ls
auto.cnf    client-cert.pem  ib_logfile0  ibtmp1          private_key.pem  server-key.pem
ca-key.pem  client-key.pem   ib_logfile1  mysql              public_key.pem   sys
ca.pem        ib_buffer_pool   ibdata1      performance_schema  server-cert.pem  testDB
root@4a68d9279589:/var/lib/mysql# ls mysql
columns_priv.MYD   gtid_executed.ibd       proc.MYI             slow_log.CSV
columns_priv.MYI   help_category.frm       proc.frm             slow_log.frm
columns_priv.frm   help_category.ibd       procs_priv.MYD         tables_priv.MYD
db.MYD           help_keyword.frm       procs_priv.MYI         tables_priv.MYI
db.MYI           help_keyword.ibd       procs_priv.frm         tables_priv.frm
db.frm           help_relation.frm       proxies_priv.MYD         time_zone.frm
db.opt           help_relation.ibd       proxies_priv.MYI         time_zone.ibd
engine_cost.frm    help_topic.frm       proxies_priv.frm         time_zone_leap_second.frm
engine_cost.ibd    help_topic.ibd       server_cost.frm         time_zone_leap_second.ibd
event.MYD       innodb_index_stats.frm  server_cost.ibd         time_zone_name.frm
event.MYI       innodb_index_stats.ibd  servers.frm             time_zone_name.ibd
event.frm       innodb_table_stats.frm  servers.ibd             time_zone_transition.frm
func.MYD       innodb_table_stats.ibd  slave_master_info.frm     time_zone_transition.ibd
func.MYI       ndb_binlog_index.MYD    slave_master_info.ibd     time_zone_transition_type.frm
func.frm       ndb_binlog_index.MYI    slave_relay_log_info.frm  time_zone_transition_type.ibd
general_log.CSM    ndb_binlog_index.frm    slave_relay_log_info.ibd  user.MYD
general_log.CSV    plugin.frm           slave_worker_info.frm     user.MYI
general_log.frm    plugin.ibd           slave_worker_info.ibd     user.frm
gtid_executed.frm  proc.MYD           slow_log.CSM

  mysql8.0

root@8de6e5139f7d:/# cd /var/lib/mysql/
root@8de6e5139f7d:/var/lib/mysql# ls mysql
general_log.CSM  general_log.CSV  general_log_197.sdi  slow_log.CSM  slow_log.CSV  slow_log_198.sdi
root@8de6e5139f7d:/var/lib/mysql# ls -l mysql
total 28
-rw-r----- 1 mysql mysql    35 Jul 15 11:19 general_log.CSM
-rw-r----- 1 mysql mysql     0 Jul 15 11:19 general_log.CSV
-rw-r----- 1 mysql mysql  5561 Jul 15 11:19 general_log_197.sdi
-rw-r----- 1 mysql mysql    35 Jul 15 11:19 slow_log.CSM
-rw-r----- 1 mysql mysql     0 Jul 15 11:19 slow_log.CSV
-rw-r----- 1 mysql mysql 11786 Jul 15 11:19 slow_log_198.sdi

mysql8.0主要存放在這個目錄下

root@8de6e5139f7d:/var/lib/mysql# ls
#innodb_temp   binlog.000003  ca-key.pem       ib_buffer_pool  ibtmp1              private_key.pem  sys
auto.cnf       binlog.000004  ca.pem           ib_logfile0     mysql               public_key.pem   testDB
binlog.000001  binlog.000005  client-cert.pem  ib_logfile1     mysql.ibd           server-cert.pem  undo_001
binlog.000002  binlog.index   client-key.pem   ibdata1         performance_schema  server-key.pem   undo_002
root@8de6e5139f7d:/var/lib/mysql# ls -l mysql.ibd -rw-r----- 1 mysql mysql 31457280 Jul 15 12:50 mysql.ibd

 

 mysql8將系統表(mysql)和數據字典所有改成innodb。

  2.原子ddl操做,基於innodb事務特性。

    因爲採用了新的數據字典, MySQL 8.0 如今支持原子數據定義語句 (Atomic DDLs)。 這意味着執行 DDL 時,數據字典更新,存儲引擎操做以及二進制日誌文件中的寫入操做會合併到單個原子事務中,該事務要麼徹底執行,要麼根本不執行。這提升了 DDL 的穩定性保證未完成的 DDL 不會留下任何不完整的數據。

 

    mysql8.0開始支持原子DDL操做,原子DDL操做又不少種,但其中與表相關的原子DDL只支持Innodb存儲引擎,好比建立表,刪除表。一個原子DDL操做包括:更新數據字典,存儲引擎層的操做,在binlog二進制日誌中記錄DDL操做,

    支持與表相關的DDL:數據庫,表空間,表,索引的create,alter,drop以及truncate table。

    支持的其餘DDL:存儲過程,觸發器,視圖,UDF(用戶定義函數)的create,drop以及alter語句。

    支持帳戶管理相關DDL:用戶和角色的create,alter,drop以及適用的rename,以及GRANT(受權)和REVOKE(撤銷受權)語句。

mysql> show tables;
+------------------+
| Tables_in_testDB |
+------------------+
| table1           |
+------------------+
1 row in set (0.00 sec)

mysql> drop table table1,table2;
ERROR 1051 (42S02): Unknown table 'testDB.table2'
mysql> show tables;
Empty set (0.00 sec)

 

雖然錯誤,可是t1表已經被刪除了,因此這個操做不具備原子性。

在mysql8.0進行相同操做

mysql> show tables;
+------------------+
| Tables_in_testDB |
+------------------+
| employee         |
| user             |
| user2            |
| user3            |
+------------------+
4 rows in set (0.00 sec)

mysql> drop table user3,user4;
ERROR 1051 (42S02): Unknown table 'testDB.user4'
mysql> show tables;
+------------------+
| Tables_in_testDB |
+------------------+
| employee         |
| user             |
| user2            |     
| user3            |   表user3依然存在
+------------------+

 

新版本功能對複製的影響:

  主從複製時候,主節點上mysql5.7,從節點上mysql8.0,因爲實現原理不同,主節點drop語句有可能成功一部分,而mysql8.0會所有失敗,能夠經過判斷drop if exists t1,t2。

 

  3.自增列持久化

    mysql5.7及早期版本,Innodb自增列計數器(AUTH_INCREMENT)的只值存儲在內存中,它值的更新只會在內存中更新,當系統出現故障或者重啓,它須要從新去掃描表中的自增列,找到當前最大列,而後基於這個值在自增,在某些狀況下它這個值有多是以前使用過的值,也就是說會出現重複的值,對於主鍵來講是不容許有重複的值。

    基於以上緣由mysql8.0作了修改,mysql8.0每次變化時將自增計數器的最大值寫入redo log,同時每次在檢查點將其寫入引擎私有的系統表。系統在下次重啓或者恢復時候能夠找到曾經使用過的最大值,避免新生成的值和之前的值重複的狀況。

mysql57> create table table1(id int auto_increment primary key, name varchar(10)); 
Query OK, 0 rows affected (0.02 sec)

mysql57> insert into table1(name) values('tom'),('lucy'),('make');
Query OK, 3 rows affected (0.02 sec)
Records: 3  Duplicates: 0  Warnings: 0

mysql57> select * from table1;
+----+------+
| id | name |
+----+------+
|  1 | tom  |
|  2 | lucy |
|  3 | make |
+----+------+
3 rows in set (0.00 sec)

mysql57> delete from table1 where id=3;
Query OK, 1 row affected (0.02 sec)

mysql57> select * from table1;
+----+------+
| id | name |
+----+------+
|  1 | tom  |
|  2 | lucy |
+----+------+
2 rows in set (0.01 sec)

    刪除並重啓

songguojundeMBP:~ songguojun$ docker stop song-mysql57
song-mysql57
songguojundeMBP:~ songguojun$ docker start song-mysql57
song-mysql57
songguojundeMBP:~ songguojun$ docker exec -it song-mysql57 /bin/bash

 

mysql> select * from table1;
+----+------+
| id | name |
+----+------+
|  1 | tom  |
|  2 | lucy |
+----+------+
2 rows in set (0.00 sec)

mysql> insert into table1(name) values('salary');
Query OK, 1 row affected (0.00 sec)

mysql> select * from table1;
+----+--------+
| id | name   |
+----+--------+
|  1 | tom    |
|  2 | lucy   |
|  3 | salary |
+----+--------+
3 rows in set (0.00 sec)

mysql> update table1 set id=5 where name = 'tom';
Query OK, 1 row affected (0.01 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from table1;
+----+--------+
| id | name   |
+----+--------+
|  2 | lucy   |
|  3 | salary |
|  5 | tom    |
+----+--------+
3 rows in set (0.00 sec)

mysql> insert into table1(name) values ('song');
Query OK, 1 row affected (0.01 sec)

mysql> select * from table1;
+----+--------+
| id | name   |
+----+--------+
|  2 | lucy   |
|  3 | salary |
|  4 | song   |
|  5 | tom    |
+----+--------+
4 rows in set (0.00 sec)

mysql> insert into table1(name) values ('song2');
ERROR 1062 (23000): Duplicate entry '5' for key 'PRIMARY'

 

接下來看mysql8.0是如何解決這個問題的

按照上面的步驟操做便可

mysql> show variables like 'innodb_autoinc%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_autoinc_lock_mode | 2     |
+--------------------------+-------+

 

參數解釋:

  mysql8.0這個值默認是2   mysql5.7這個默認值是1, 2是交叉模式,這個鎖是交叉生成的,1表示連續模式,這兩個值差異在於複製的時候,好比說以前 複製說基於語句的複製,好比一條語句生成10條記錄,在這條語句中生成的記錄都是順序的,若是從主節點複製到從節點也要保證說順序的話就要使用這個值爲1,能夠保證語句級別的增加都是連續的,最新的複製模式改成行的複製模式,意味着將行的實際數據值複製,因此不關心自增列是怎麼生成的,也不能保證生成的id一致性,由於不像以前版本加上鎖,這樣的好處能夠支持更高的併發和擴展。若是還想要以前那樣基於語句就要注意這個參數設置下。

   4.死鎖檢查控制

    死鎖:有兩個事務都須要對數據進行修改,修改的過程當中都須要等待對方釋放資源,因爲互相沒有感知,在沒有外界的介入下它們會一直等待下去,就造成了死鎖。mysql後臺有個死鎖檢測程序,在後臺發現了會讓一個事務失敗,讓另外一個事務進行下去,固然死鎖檢測須要必定的代價,須要佔用必定的系統資源。

    mysql8.0及mysql5.7.15增長了一個新的動態變量,用於控制系統是否執行Innodb的死鎖檢測。

    innodb_deadlock_detect 默認狀況說打開的,會進行死鎖檢測。

    對於高併發的系統,死鎖檢測會佔用系統資源,因此禁用死鎖檢測可能會帶來性能的提升。

mysql8> show variables like 'innodb_deadlock_detect';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_deadlock_detect | ON    |
+------------------------+-------+

 下面開啓兩個事務,而後在兩個事務之間互相鎖定各自的資源,來等待對方的鎖。

 先建立一張表

mysql> create table table_t1 (i int);
Query OK, 0 rows affected (0.03 sec)

mysql> insert into table_t1(i) values(1);
Query OK, 1 row affected (0.00 sec)

 

 

事務1 說明 事務2 說明

mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from table_t1 where i=1 for share;
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
for share獲取記錄上的一個共享鎖 mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from table_t1 where i=1;
刪除須要排它鎖 ,因爲前面一個會話已經佔用了一個共享鎖,這時候在等待資源的釋放。
mysql> delete from table_t1 where i=1;
Query OK, 1 row affected (0.01 sec)

第二個窗口 刪除時候也須要排它鎖,這個時候它也須要第二個會話事務釋放鎖才能進行下去,發現了死鎖 。

由於系統發現了死鎖並解除死鎖,這裏能夠進行下去。

mysql> delete from table_t1 where i=1;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
死鎖被發現,系統將它會滾掉,讓第一個事務進行下去
mysql> select * from table_t1;
Empty set (0.00 sec)

數據被刪除

   

 以上是innodb_deadlock_detect默認打開狀況下掉行爲。

 

那麼咱們將這個參數關閉測試看看如何處理死鎖的

mysql> set global innodb_deadlock_detect = off;    #關閉死鎖檢測
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like 'innodb_deadlock_detect';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| innodb_deadlock_detect | OFF   |
+------------------------+-------+

 

還有一個參數 鎖等待超時 這個參數會影響實驗

mysql> show variables like 'innodb_lock_wait%';
+--------------------------+-------+
| Variable_name            | Value |
+--------------------------+-------+
| innodb_lock_wait_timeout | 50    |     #默認是50秒
+--------------------------+-------+
1 row in set (0.00 sec)

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

 

50秒設置爲5秒

 

事務1 說明 事務2 說明
mysql> start transaction;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from table_t1 where i=1 for share;
+------+
| i    |
+------+
|    1 |
+------+
1 row in set (0.00 sec)
 

mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

 

 
   

mysql> delete from table_t1 where i=1;

執行刪除操做,在等待中
mysql> delete from table_t1 where i=1;
Query OK, 1 row affected (31.99 sec)

這個事務也在等待中,

若是死鎖檢測打開,就會提示死鎖錯誤信息,可是這裏沒有提示

   
    ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction 經過超時來回滾事務,讓事務二失敗

 

注意:

  1.死鎖檢測關閉的前提是咱們系統不會發生死鎖的狀況,因此在咱們寫代碼寫sql語句要注意點死鎖的發生。

  2.鎖等待超時時間不要設置太長,防止對系統的影響。

 

5.鎖定語句選項

  mysql裏面有兩種爲查詢語句加鎖的語句

    1.  select....... for update  

    2.  select ....... for share

    這兩個語句分別是爲咱們查詢出來的語句加上共享鎖和排它鎖,若是查出來的數據在其餘事物中以及佔用了相應的鎖,那麼咱們的語句須要進行相應的等待直到響應的事務釋放鎖直到超時。

    mysql8.0爲這兩個語句增長了兩個新的選項。

      1) NOWAIT:若是請求的行被其餘事物鎖定,語句當即返回,不等待。

      2)SKIP LOCKED:從返回的結果中移除鎖定的行,只返回沒有被鎖定的行。應用場景,好比在線票務系統,有不少併發請求,若是票被其餘線程佔用,這時候能夠選擇不等待,返回可使用的票。

mysql> create table table6 (i int ,primary key(i));

mysql> insert into table6 values (1),(2),(3);

 

 

事務1 說明 事務2 說明
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> update table6 set i=0 where i=2;
加上排它鎖,不進行提交    
   

start transaction;

select * from table6 where i=2 for update;

ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction

因爲前面會話佔用了鎖,會一直等待直到語句超時
    mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from table6 where i=2 for update nowait;
ERROR 3572 (HY000): Statement aborted because lock(s) could not be acquired immediately and NOWAIT is set.

若是加上nowait選項選擇不等待鎖會返回一個錯誤,相應數據被佔用,直接返回錯誤。
    mysql> select * from table6  for update skip locked;
+---+
| i |
+---+
| 1 |
| 3 |
+---+
2 rows in set (0.00 sec)
加上skip locked選項選擇跳過鎖定的數據,返回別的沒被鎖定的數據。

注意:

  1.這兩個參數鎖針對行級鎖。

  2.這兩個鎖針對行級鎖,對每一條行記錄起做用。

    主從複製,主從當時運行環境狀況的各不同,致使數據的不肯定性,對於語句級別會帶來不一致性問題。

 

  3.簡化了INFORMATION_SCHEMA的實現,提升了訪問性能。

  4.針對innodb存儲引擎提供了序列化字典信息(SDL)的支持,以及ibd2sdi工具。SDI是一個文本文件,存儲了數據字典信息。ibd2sdi工具能夠將innodb相關表信息導出成文本信息。

 

root@f488b1c2586a:/# cd /var/lib/mysql/
root@f488b1c2586a:/var/lib/mysql# ls 
#innodb_temp   ca.pem        ibdata1            private_key.pem  undo_001
auto.cnf       client-cert.pem    ibtmp1            public_key.pem   undo_002
binlog.000001  client-key.pem    mysql            server-cert.pem
binlog.000002  ib_buffer_pool    mysql.ibd        server-key.pem
binlog.index   ib_logfile0    mysqld-auto.cnf     sys
ca-key.pem     ib_logfile1    performance_schema  testDB
root@f488b1c2586a:/var/lib/mysql# cd testDB/
root@f488b1c2586a:/var/lib/mysql/testDB# ls
numbers.ibd  sales.ibd    table_json.ibd    user2.ibd  user3.ibd

 

 

root@f488b1c2586a:/var/lib/mysql/testDB# ibd2sdi table_json.ibd > sales.ibd 
root@f488b1c2586a:/var/lib/mysql/testDB# ls
numbers.ibd  sales.ibd    table_json.ibd    user2.ibd  user3.ibd
root@f488b1c2586a:/var/lib/mysql/testDB# cat sales.ibd 
["ibd2sdi"
,
{
    "type": 1,
    "id": 342,
    "object":
        {
    "mysqld_version_id": 80016,
    "dd_version": 80016,
    "sdi_version": 80016,
    "dd_object_type": "Table",
    "dd_object": {
        "name": "table_json",
        "mysql_version_id": 80016,
        "created": 20190722122718,
        "last_altered": 20190722122718,
        "hidden": 1,
        "options": "avg_row_length=0;encrypt_type=N;key_block_size=0;keys_disabled=0;pack_record=1;stats_auto_recalc=0;stats_sample_pages=0;",
        "columns": [
            {
                "name": "data",
                "type": 31,
                "is_nullable": true,
                "is_zerofill": false,
                "is_unsigned": false,
                "is_auto_increment": false,
                "is_virtual": false,
                "hidden": 1,
                "ordinal_position": 1,
                "char_length": 4294967295,
                "numeric_precision": 0,
                "numeric_scale": 0,
                "numeric_scale_null": true,
                "datetime_precision": 0,
                "datetime_precision_null": 1,
                "has_no_default": false,
                "default_value_null": true,
                "srs_id_null": true,
                "srs_id": 0,
                "default_value": "",
                "default_value_utf8_null": true,
                "default_value_utf8": "",
                "default_option": "",
                "update_option": "",
                "comment": "",
                "generation_expression": "",
                "generation_expression_utf8": "",
                "options": "interval_count=0;",
                "se_private_data": "table_id=1066;",
                "column_key": 1,
                "column_type_utf8": "json",
                "elements": [],
                "collation_id": 63,
                "is_explicit_collation": true
            },

 

好比當數據表損壞的時候能夠用這些文本信息恢復。

因爲新的數據字典的引入,會致使以前使用上的差別,例如innodb_read_only影響全部全部的存儲引擎。數據字典不可見,不能直接修改和查詢。

 

6.索引跳躍掃描(index skip scan)

  MySQL從8.0.13版本開始支持一種新的range scan方式,稱爲Loose Skip Scan。該特性由Facebook貢獻。咱們知道在以前的版本中,若是要使用到索引進行掃描,條件必須知足索引前綴列,好比索引idx(col1,col2), 若是where條件只包含col2的話,是沒法有效的使用idx的, 它須要掃描索引上全部的行,而後再根據col2上的條件過濾。
  新的優化能夠避免全量索引掃描,而是根據每一個col1上的值+col2上的條件,啓動屢次range scan。每次range scan根據構建的key值直接在索引上定位,直接忽略了那些不知足條件的記錄。
mysql> CREATE TABLE table_scan (i1 int, i2 int , PRIMARY KEY(i1, i2));
mysql> INSERT INTO table_scan VALUES (1,1), (1,2), (1,3), (1,4), (1,5),(2,1), (2,2), (2,3), (2,4), (2,5);
mysql> INSERT INTO table_scan SELECT i1, i2 + 5 FROM table_scan;
mysql> INSERT INTO table_scan SELECT i1, i2 + 10 FROM table_scan;
mysql> INSERT INTO table_scan SELECT i1, i2 + 20 FROM table_scan;
mysql> INSERT INTO table_scan SELECT i1, i2 + 40 FROM table_scan;

mysql> EXPLAIN SELECT i1, i2 FROM table_scan WHERE i2 > 40;
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                    |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
|  1 | SIMPLE      | table_scan | NULL       | index | PRIMARY       | PRIMARY | 8       | NULL |  160 |    33.33 | Using where; Using index |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+mysql> ANALYZE TABLE table_scan;
+-------------------+---------+----------+----------+
| Table             | Op      | Msg_type | Msg_text |
+-------------------+---------+----------+----------+
| testDB.table_scan | analyze | status   | OK       |
+-------------------+---------+----------+----------+

mysql> EXPLAIN SELECT i1, i2 FROM table_scan WHERE i2 > 40;
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------+
| id | select_type | table      | partitions | type  | possible_keys | key     | key_len | ref  | rows | filtered | Extra                                  |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------+
|  1 | SIMPLE      | table_scan | NULL       | range | PRIMARY       | PRIMARY | 8       | NULL |   53 |   100.00 | Using where; Using index for skip scan |
+----+-------------+------------+------------+-------+---------------+---------+---------+------+------+----------+----------------------------------------+

 

mysql> show variables like 'optimizer_trace%';
+------------------------------+----------------------------------------------------------------------------+
| Variable_name                | Value                                                                      |
+------------------------------+----------------------------------------------------------------------------+
| optimizer_trace              | enabled=off,one_line=off                                                   |
| optimizer_trace_features     | greedy_search=on,range_optimizer=on,dynamic_range=on,repeated_subselect=on |
| optimizer_trace_limit        | 1                                                                          |
| optimizer_trace_max_mem_size | 1048576                                                                    |
| optimizer_trace_offset       | -1                                                                         |
+------------------------------+----------------------------------------------------------------------------+

 開啓 optimizer_trace

SET optimizer_trace='enabled=on';

  執行須要執行的 sql

SELECT i1, i2 FROM table_scan WHERE i2 > 40;

 能夠從optimizer trace裏看到如何選擇的skip scan

mysql> select trace from `information_schema`.`optimizer_trace`\G;
*************************** 1. row ***************************
trace: {
  "steps": [
    {
      "join_preparation": {
        "select#": 1,
        "steps": [
          {
            "expanded_query": "/* select#1 */ select `table_scan`.`i1` AS `i1`,`table_scan`.`i2` AS `i2` from `table_scan` where (`table_scan`.`i2` > 40)"
          }
        ]
      }
    },
    {
    #此處省略.....
"group_index_range": { "chosen": false, "cause": "not_group_by_or_distinct" }, "skip_scan_range": { "potential_skip_scan_indexes": [ { "index": "PRIMARY", "tree_travel_cost": 0.4, "num_groups": 3, "rows": 53, "cost": 10.625 } ] }, "best_skip_scan_summary": { "type": "skip_scan", "index": "PRIMARY", "key_parts_used_for_access": [ "i1", "i2" ], "range": [ "40 < i2" ], "chosen": true }, "rows_for_plan": 53, "cost_for_plan": 10.625, "chosen": true } } } ]
#此處省略.....
      }
    },
    {
      "join_execution": {
        "select#": 1,
        "steps": [
        ]
      }
    }
  ]
}
1 row in set (0.00 sec)

 

 

mysql> show variables like 'optimizer_switch%';
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Variable_name    | Value                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
+------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| optimizer_switch | index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,
index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,
firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on,
use_invisible_indexes=off,skip_scan=on | +------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

innodb其餘的改進

    1)支持部門快速DDL  alter table .......ALGORITHM=INSTANT

    好比快速增長某一列,可使用INSTANT這種算法。就是修改相應數據字典的信息,而不是像之前從新建立一張表進行數據複製,這個比之前快不少,尤爲線上系統很是實用。(這個功能鎖騰訊開發合併到主分支上)

    2)innodb臨時表使用的共享臨時表空間ibtmp1,改變以前使用分散的表空間的問題,存儲在ibtmp1。臨時表使用完就刪除了,如今統一放在ibtmp1,統一的維護。

    3)新增靜態變量innodb_dedicated_server,若是有一臺服務器是專門用於mysql數據庫的,能夠打開這個配置變量,系統會自動配置innodb相關等內存配置參數,  自動配置Innodb內存參數:innodb_buffer_pool_size/innodb_log_file_size等,儘可能合理佔用系統資源來提升系統等利用率。

    4)新增表INFORMATION_SCHEMA.INNODB_CACHED_INDEXES顯示每一個索引緩存在innodb緩衝池中的索引頁數,經過這個參數也能夠了解索引緩存使用狀況。

    5)新增視圖INFORMATION_SCHEMA.INNODB_TABLESPACES_BRIEF,爲innodb表空間提供相關元數據信息。

    6)mysql8.0默認建立2個undo表空間,再也不使用系統表空間。之前undo表空間會佔用系統表空間資源,單獨存儲會是系統表空間獨立點。

    7)支持alter tablespace......rename to重命名通用表空間。

    8)支持使用innodb_directories選項在服務器中止時將表空間文件移動到新的位置。這個參數是表空間文件所在的路徑,經過修改參數

    9)innodb表空間加密特性支持重作日誌和撤銷日誌,innodb_undo_log_encryptinnodb_undo_log_encrypt參數。加密會更加安全。

 

JSON加強

  json數據格式和關係型數據庫的數據格式是不同的,它是一個結構不固定的數據結構方式,也算是屬於nosql範疇,mysql針對json不斷的加強。mysql8.0關於json有了一些加強,主要是增長了一些內置的運算符和數據處理函數。

   1.內聯路徑操做符

    主要用於獲取json對象在某一些節點或者某些路徑上的數據。

    內聯操做符的表達式:

      column->>path  等價於JSON_UNQUOTE( column -> path)      JSON_UNQUOTE(JSON_EXTRACT(column,path))

    示例演示  

mysql> with doc(data) as     
    -> ( select json_object('id','1','name','tom'))      #建立一個json對象 有兩個字段 id  name
    -> select json_unquote(data->'$.name') from doc;   #得到節點name的值

+------------------------------+
| json_unquote(data->'$.name') |
+------------------------------+
| tom                          |
+------------------------------+

 

  還有一種方式也是以前版本支持的,這裏實用另一個函數json_extract

mysql> with doc(data) as  
  -> ( select json_object('id','1','name','tom'))
  -> select json_unquote(json_extract(data,'$.name')) from doc; +-------------------------------------------+ | json_unquote(json_extract(data,'$.name')) | +-------------------------------------------+ | tom | +-------------------------------------------+

 

以上是mysql8以前寫法

下面看mysql8.0內聯路徑操做符的寫法

mysql> with doc(data) as  ( select json_object('id','1','name','tom')) select data->>'$.name' from doc;
+-----------------+
| data->>'$.name' |
+-----------------+
| tom             |
+-----------------+

mysql8.0還擴展了這個路徑表達式的語法,能夠支持範圍的操做。

mysql> select json_extract('["a","b","c"]','$[1]');
+--------------------------------------+
| json_extract('["a","b","c"]','$[1]') |
+--------------------------------------+
| "b"                                  |
+--------------------------------------+

mysql> select json_extract('["a","b","c"]','$[1 to 3]');   #這個是新版本寫法 支持範圍查找
+-------------------------------------------+
| json_extract('["a","b","c"]','$[1 to 3]') |
+-------------------------------------------+
| ["b", "c"]                                |
+-------------------------------------------+

 

  2.json聚合函數

    能夠將表中列的數據聚合成對應的json數組或者json對象。

    mysql8.0增長了兩個聚合函數,mysql5.7.22也增長了相同的函數。

      1)JSON_ARRAYAGG() ,用於將多行數據組合生成JSON數組。

      2) JSON_OBJECTAGG(),用於生成json對象。

   示例演示

mysql> create table jsontable(i int,attribute varchar(100),value varchar(100));
mysql> insert into jsontable values(2,'color','red'),(2,'fabric','silk'),(3,'color','green'),(3,'shape','square');

 

json聚合函數和普通聚合函數是同樣的。  

先看數組聚合函數

mysql> select i,json_arrayagg(attribute) as attributes  from jsontable group by i;
+------+---------------------+
| i    | attributes          |
+------+---------------------+
|    2 | ["color", "fabric"] |
|    3 | ["color", "shape"]  |
+------+---------------------+

 

json_objectagg支持多個列

mysql> select i,json_objectagg(attribute,value) as attributes  from jsontable group by i;
+------+---------------------------------------+
| i    | attributes                            |
+------+---------------------------------------+
|    2 | {"color": "red", "fabric": "silk"}    |
|    3 | {"color": "green", "shape": "square"} |
+------+---------------------------------------+

 

  若是存在重複值是如何處理的

mysql> insert into jsontable values(3,'color','yellow');

mysql> select * from jsontable;
+------+-----------+--------+
| i    | attribute | value  |
+------+-----------+--------+
|    2 | color     | red    |
|    2 | fabric    | silk   |
|    3 | color     | green  |
|    3 | shape     | square |
|    3 | color     | yellow |
+------+-----------+--------+

mysql> select i,json_objectagg(attribute,value) as attributes  from jsontable group by i;
+------+----------------------------------------+
| i    | attributes                             |
+------+----------------------------------------+
|    2 | {"color": "red", "fabric": "silk"}     |
|    3 | {"color": "yellow", "shape": "square"} |       #最後面的值覆蓋前面的值
+------+----------------------------------------+       

 

  3.json實用函數

    用於對json對象的輸出或者獲取json所佔用的存儲空間。

    mysql8.0 (mysql5.7.22)增長了JSON_PRETTY()。這個函數用於在輸出json對象內容的時候進行格式化或者美化的輸出。

    mysql8.0 (mysql5.7.22)增長了JSON_STORAGE_SIZE(),返回json數據所佔用的空間大小。

    JSON_STORAGE_FREE(),用於更新某些json列以後,相應的一些字段它可能釋放的存儲空間。

 

mysql> select json_object('id','1','name','jack');       #先構造一個json對象
+-------------------------------------+
| json_object('id','1','name','jack') |
+-------------------------------------+
| {"id": "1", "name": "jack"}         |
+-------------------------------------+
1 row in set (0.00 sec)

mysql> select json_pretty(json_object('id','1','name','jack'));    #內容同樣,格式被處理了  
+--------------------------------------------------+
| json_pretty(json_object('id','1','name','jack')) |
+--------------------------------------------------+
| {
  "id": "1",
  "name": "jack"
}                |

 

mysql> create table json_table2 (j_field varchar(200));

mysql> insert into json_table2 values('{"a":1000,"b":"aaa","c":"[1,2,3,4,5,6]"}');

mysql> select * from json_table2;
+------------------------------------------+
| j_field                                  |
+------------------------------------------+
| {"a":1000,"b":"aaa","c":"[1,2,3,4,5,6]"} |
+------------------------------------------+
1 row in set (0.00 sec)

mysql> select j_field , json_storage_size(j_field) from json_table2;         #查看空間大小
+------------------------------------------+----------------------------+
| j_field                                  | json_storage_size(j_field) |
+------------------------------------------+----------------------------+
| {"a":1000,"b":"aaa","c":"[1,2,3,4,5,6]"} |                         47 |   #47個字節
+------------------------------------------+----------------------------+

 

mysql> select j_field , json_storage_free(j_field) from json_table2;
+------------------------------------------+----------------------------+
| j_field                                  | json_storage_free(j_field) |
+------------------------------------------+----------------------------+
| {"a":1000,"b":"aaa","c":"[1,2,3,4,5,6]"} |                          0 |    #默認上面表數據沒有更新 因此這裏數據顯示釋放的空間爲0
+------------------------------------------+----------------------------+

 

mysql> update json_table2  set j_field = json_set(j_field,"$.a",10,"$.b","bb","$.c",1);

 

  4.json合併函數

    主要是將兩個json對象合併成一個。

  5.json表函數

    和json聚合函數執行相反的操做。將這種json對象擴展成關係型數據錶行和列組織的數據形式。

 

 四.mysql8.0其它的新的特性

  1. 默認字符集由latin1變爲utf8mb4。

    2. 統計直方圖,是一種統計信息,統計表中字段各值的分佈狀況。因爲有時候查詢優化器會走不到最優的執行計劃,因此利用統計直方圖,用戶能夠對一張表的一列作數據分佈的統計,尤爲是針對沒有索引的字段。這能夠幫助查詢優化器找到更優的執行計劃。統計直方圖的主要使用場景是用來計算字段選擇性。

   3.新增mysql-auto.cnf文件,比my.cnf具備更高優先權。

 

 

五.mysql8.0去掉的特性

  有增長的新特性,也會有去掉不適用老的功能

  1.取消 Query Cache

    如今性能審計中第一件事就是禁用 Query Cache ,由於他給數據庫設計帶來不少麻煩。 MySQL QC 形成的問題比他解決問題要多得多。 所以咱們決定在 MySQL 8.0 中取消他,由於你們就不該該使用它。 若是你工做中須要使用 Query Cache,你應該用  ProxySQL as Query Cache 替代 Query Cache。

    可是大多數狀況下我會建議你不要使用查詢緩存,爲何呢?由於查詢緩存每每弊大於利。

    查詢緩存的失效很是頻繁,只要有對一個表的更新,這個表上全部的查詢緩存都會被清空。所以極可能你費勁地把結果存起來,還沒使用呢,就被一個更新全清空了。對於更新壓力大的數據庫來講,查詢緩存的命中率會很是低。除非你的業務就是有一張靜態表,很長時間纔會更新一次。好比,一個系統配置表,那這張表上的查詢才適合使用查詢緩存。

好在MySQL也提供了這種「按需使用」的方式。你能夠將參數query_cache_type設置成DEMAND,這樣對於默認的SQL語句都不使用查詢緩存。而對於你肯定要使用查詢緩存的語句,能夠用SQL_CACHE顯式指定,像下面這個語句同樣:

mysql> select SQL_CACHE * from T where ID=10;

須要注意的是,MySQL 8.0版本直接將查詢緩存的整塊功能刪掉了,也就是說8.0開始完全沒有這個功能了。

 mysql5.7 mysql8都是默認關閉的

mysql> show variables like '%query_cache%' ;
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| have_query_cache | NO    |
+------------------+-------+

  2.取消默認MyISAM系統表:併發程度低,資源利用率低。

  3.移除PASSWORD()函數,沒法再用SET PASSWORD=PASSWORD(密碼)去加密。

相關文章
相關標籤/搜索