MySQL8.0新特性【轉】


Server層,選項持久化

mysql> show variables like '%max_connections%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| max_connections        | 512   |
| mysqlx_max_connections | 100   |
+------------------------+-------+
2 rows in set (0.00 sec)
mysql> set persist max_connections=8000;
Query OK, 0 rows affected (0.00 sec) 
mysql> show variables like '%max_connections%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| max_connections        | 8000  |
| mysqlx_max_connections | 100   |
+------------------------+-------+
2 rows in set (0.00 sec)
[root@mydb1 ~]# cat /app/mysqldata/3306/data/mysqld-auto.cnf
{ "Version" : 1 , "mysql_server" : { "max_connections" : { "Value" : "8000" , "Metadata" : { "Timestamp" : 1570677819639469 , "User" : "dba_user" , "Host" : "localhost" } } } }

[root@mydb1 ~]# cat /app/mysqldata/3306/my.cnf | grep max_connections
max_connections = 512

查看配置文件,仍然是之前的配置max_connections = 512

mysql> restart; 

mysql> show variables like '%max_connections%';
+------------------------+-------+
| Variable_name          | Value |
+------------------------+-------+
| max_connections        | 8000  |
| mysqlx_max_connections | 100   |
+------------------------+-------+
2 rows in set (0.01 sec)

 

set persist更改運行時變量值,將變量設置寫入mysqld-auto.cnf數據目錄中指定的選項文件 。數據庫啟動時,會首先讀取其它配置文件my.cnf,最后才讀取mysqld-auto.cnf文件。

不建議手動修改該文件,其有可能導致數據庫在啟動過程中因解析錯誤而失敗。如果出現這種情況,可手動刪除mysqld-auto.cnf文件或將persisted_globals_load變量設置為off來避免該文件的加載
對於已經持久化了變量,可通過reset persist命令取消持久
注意,其只是清空mysqld-auto.cnf和performance_schema.persisted_variables中的內容,對於已經修改了的變量的值,不會產生任何影響。

但是對於read only 的參數,修改參數后需要重啟才能生效
修改read only的變量需要額外的特權:
SYSTEM_VARIABLES_ADMIN
PERSIST_RO_VARIABLES_ADMIN

mysql> show variables like 'innodb_log_file_size';
+----------------------+------------+
| Variable_name        | Value      |
+----------------------+------------+
| innodb_log_file_size | 1147483648 |
+----------------------+------------+
1 row in set (0.00 sec)
mysql> set persist innodb_log_file_size=2147483648;
ERROR 1238 (HY000): Variable 'innodb_log_file_size' is a read only variable
mysql> set persist_only innodb_log_file_size=2147483648;
Query OK, 0 rows affected (0.00 sec)
mysql> restart;
Query OK, 0 rows affected (0.00 sec) 

mysql> show variables like 'innodb_log_file_size';
+----------------------+------------+
| Variable_name        | Value      |
+----------------------+------------+
| innodb_log_file_size | 2147483648 |
+----------------------+------------+
1 row in set (0.00 sec)

[root@mydb1 ~]# cat /app/mysqldata/3306/data/mysqld-auto.cnf
{ "Version" : 1 , "mysql_server" : { "max_connections" : { "Value" : "8000" , "Metadata" : { "Timestamp" : 1570677819639469 , "User" : "dba_user" , "Host" : "localhost" } } , "mysql_server_static_options" : { "innodb_log_file_size" : { "Value" : "2147483648" , "Metadata" : { "Timestamp" : 1570679652100887 , "User" : "dba_user" , "Host" : "localhost" } } } } }

 mysql> select * from performance_schema.variables_info where variable_source like 'PERSISTED'\G
*************************** 1. row ***************************
  VARIABLE_NAME: innodb_log_file_size
VARIABLE_SOURCE: PERSISTED
  VARIABLE_PATH: /app/mysqldata/3306/data/mysqld-auto.cnf
      MIN_VALUE: 4194304
      MAX_VALUE: 18446744073709551615
       SET_TIME: 2019-10-10 11:54:12.100887
       SET_USER: dba_user
       SET_HOST: localhost
*************************** 2. row ***************************
  VARIABLE_NAME: max_connections
VARIABLE_SOURCE: PERSISTED
  VARIABLE_PATH: /app/mysqldata/3306/data/mysqld-auto.cnf
      MIN_VALUE: 1
      MAX_VALUE: 100000
       SET_TIME: 2019-10-10 11:23:39.639469
       SET_USER: dba_user
       SET_HOST: localhost
2 rows in set (0.01 sec)

 

 

數據字典

(1)新版本之前的數據字典

數據字典是數據庫重要的組成部分之一,那么什么是數據字典?數據字典包含哪些內容呢?數據字典是對數據庫中的數據、庫對象、表對象等的元信息的集合。在MySQL中,數據字典信息內容就包括表結構、數據庫名或表名、字段的數據類型、視圖、索引、表字段信息、存儲過程、觸發器等內容。MySQL INFORMATION_SCHEMA庫提供了對數據局元數據、統計信息、以及有關MySQL server的訪問信息(例如:數據庫名或表名,字段的數據類型和訪問權限等)。該庫中保存的信息也可以稱為MySQL的數據字典。 

在MySQL8.0之前,MySQL的數據字典信息,並沒有全部存放在系統數據庫表中,部分數據庫數據字典信息存放於文件中,其余的數據字典信息存放於數據字典庫中(INFORMATION_SCHEMA,mysql,sys)。例如表結構信息存放在.frm文件中,數據庫表字段信息存放於INFORMATION_SCHEMA下的COLUMNS表中。早期,5.6版本之前,MyISAM是MySQL的默認存儲引擎,而作為MyISAM存儲引擎,它是沒有數據字典的。只有表結構信息記錄在.frm文件中。MySQL5.6版本之后,將InnoDB存儲引擎作為默認的存儲引擎。在InnoDB存儲引擎中,添加了一些數據字典文件用於存放數據字典元信息,例如:.opt文件,記錄了每個庫的一些基本信息,包括庫的字符集等信息,.TRN.TRG文件用於存放觸發器的信息內容。

(2)新版本數據字典的改進

最新的MySQL 8.0 發布之后,對數據庫數據字典方面做了較大的改進。
首先是,將所有原先存放於數據字典文件中的信息,全部存放到數據庫系統表中,即將之前版本的.frm,.opt,.par,.TRN,.TRG,.isl文件都移除了,不再通過文件的方式存儲數據字典信息。
其次是對INFORMATION_SCHEM,mysql,sys系統庫中的存儲引擎做了改進,原先使用MyISAM存儲引擎的數據字典表都改為使用InnoDB存儲引擎存放。從不支持事務的MyISAM存儲引擎轉變到支持事務的InnoDB存儲引擎,為原子DDL的實現,提供了可能性。

新數據字典帶來的影響

(1)INFORMATION_SCHEMA性能提升
8.0中對數據字典進行改進之后,很大程度上提高了對INFORMATIONS_SCHEMA的查詢性能,通過可以通過查表快速的獲得想要查詢的數據,原因是:
數據庫在查詢INFORMATION_SCHEMA的表時,不再一定需要創建一張臨時表,可以直接查詢數據字典表。在之前版本中,數據字典信息不一定是存放於表中,所以在獲取數據字典信息時候,不僅僅是查表操作。例如讀取數據庫表結構信息,底層其實是讀取.frm文件來獲得,是一個文件打開讀取的操作。而在新版本中,數據字典信息都可以通過直接查表的方式獲取,替代那些獲取信息慢的方式。
對存儲引擎的改進之后,在查詢INFORMATIONS_SCHEMA表時,如果表上有索引,優化器會合理的利用索引。
對於INFORMATION_SCHEMA下的STATISTICS表和TABLES表中的信息,8.0中通過緩存的方式,以提高查詢的性能。可以通過設置information_schema_stats_expiry參數設置緩存數據的過期時間,默認是86400秒。查詢這兩張表的數據的時候,首先是到緩存中進行查詢,緩存中沒有緩存數據,或者緩存數據過期了,查詢會從存儲引擎中獲取最新的數據。如果需要獲取最新的數據,可以通過設置information_schema_stats_expiry參數為0或者ANALYZE TABLE操作。

(2)原子DDL
MySQL8.0開始支持原子DDL操作,一個原子DDL操作,具體的操作內容包括:數據字典更新,存儲引擎層的操作,在binlog中記錄DDL操作。並且這些操作都是原子性的,表示中間過程出現錯誤的時候,是可以完整回退的。這在之前版本的DDL操作中是不支持的。之前數據庫版本中一直沒有支持原子DDL的特性,是有原因的,因為在早期的數據庫版本中,數據庫元信息存放於元信息文件中、非事務性表中以及特定存儲引擎的數據字典中。這些都無法保證DDL操作內容在一個事務當中,無法保證原子性。具體的原子DDL,后續會有專門的文章。

(3)innodb_read_only對所有存儲引擎生效
在8.0之前版本中,innodb_read_only參數可以阻止對InnoDB存儲引擎表的create和drop等更新操作。但是在MySQL8.0中,開啟innodb_read_only參數阻止了所有存儲引擎的這些操作。create或者drop表的操作都需要更新數據字典表,8.0中這個數據字典表都改為了InnoDB存儲引擎,所以對於數據字典表的更新會失敗,從而導致各存儲引擎create和drop表失敗。同樣的像ANALYZE TABLE和ALTER TABLE tbl_name ENGINE=engine_name這種操作也會失敗,因為這些操作都要去更新數據字典表。

(4)mysqldump mysqlpump導出的內容影響
MySQL8.0之后,在使用mysqldump和mysqlpump導出數據時候,與之前有了一些不同,主要是以下幾點:
之前版本的mysqldump和mysqlpump可以導出mysql系統庫中的所有表的內容,8.0之后,只能導出mysql系統庫中沒有數據的數據字典表。
之前版本當使用 --all-databases 參數導出數據的時候,不加 --routines和 --events選項也可以導出觸發器、存儲過程等信息,因為這些信息都存放於proc和event表中,導出所有表即可導出這些信息。但是在8.0中,proc表和event表都不再使用,並且定義觸發器、存儲過程的數據字典表不會被導出,所以在8.0中使用mysqldump、mysqlpump導出數據的時候,如果需要導出觸發器、存儲過程等內容,一定需要加上 --routines和 --events選項。
之前版本中 --routines選項導出的時候,備份賬戶需要有proc表的SELECT權限,在8.0中需要對所有表的SELECT權限
之前版本中,導出觸發器、存儲過程可以同時導出觸發器、存儲過程的創建和修改的時間戳,8.0中不再支持。

(5)新數據字典的局限性
MySQL8.0數據字典的改進有很多方便的特性,例如帶來了原子DDL,提升了INFORMATION_SCHEMA的查詢性能等,但是它並不是完美的,新版數據字典還是存在一些局限性:
通過手動mkdir的方式在數據目錄下創建庫目錄,這種方式是不會被數據庫所識別到。DDL操作會花費更長的時間,因為之前的DDL操作是直接對.frm文件進行更改操作,只要寫一個文件,現在是需要更新數據字典表,代表着需要將數據寫到存儲引擎、read log、undo log中

 

auto-inc持久化

自增主鍵沒有持久化是個比較早的bug,歷史悠久且臭名昭著。

首先,直觀的重現下。

mysql> create table t1(id int auto_increment primary key);
Query OK, 0 rows affected (0.01 sec)
mysql> insert into t1 values(null),(null),(null);
Query OK, 3 rows affected (0.01 sec)
Records: 3 Duplicates: 0 Warnings: 0
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
rows in set (0.00 sec)
mysql> delete from t1 where id=3;
Query OK, 1 row affected (0.36 sec)
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.35 sec)
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 4 |
+----+
rows in set (0.01 sec)

 

雖然id為3的記錄刪除了,但再次插入null值時,並沒有重用被刪除的3,而是分配了4。

刪除id為4的記錄,重啟數據庫,重新插入一個null值。

mysql> delete from t1 where id=4;
# service mysqld restart
mysql> insert into t1 values(null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from t1;
+----+
| id |
+----+
| 1 |
| 2 |
| 3 |
+----+
rows in set (0.00 sec)

 

可以看到,新插入的null值分配的是3,按照重啟前的操作邏輯,此處應該分配5啊。

這就是自增主鍵沒有持久化的bug。究其原因,在於自增主鍵的分配,是由InnoDB數據字典內部一個計數器來決定的,而該計數器只在內存中維護,並不會持久化到磁盤中。當數據庫重啟時,該計數器會通過下面這種方式初始化。

SELECT MAX(ai_col) FROM table_name FOR UPDATE;

MySQL 8.0的解決思路

將自增主鍵的計數器持久化到redo log中。每次計數器發生改變,都會將其寫入到redo log中。如果數據庫發生重啟,InnoDB會根據redo log中的計數器信息來初始化其內存值。為了盡量減小對系統性能的影響,計數器寫入到redo log中,並不會馬上刷新。

 

窗口函數、通用表達式

對於窗口函數,比如row_number(),rank(),dense_rank(),NTILE(),PERCENT_RANK()等等,在MSSQL和Oracle以及PostgreSQL,使用的語法和表達的邏輯,基本上完全一致。 在MySQL 8.0之后就放心的用吧。

測試case,簡單模擬一個訂單表,字段分別是訂單號,用戶編號,金額,創建時間 

 create table order_info
(
    order_id int primary key,
    user_no varchar(10),
    amount int,
    create_date datetime
);
insert into order_info values (1,'u0001',100,'2018-1-1');
insert into order_info values (2,'u0001',300,'2018-1-2');
insert into order_info values (3,'u0001',300,'2018-1-2');
insert into order_info values (4,'u0001',800,'2018-1-10');
insert into order_info values (5,'u0001',900,'2018-1-20');
insert into order_info values (6,'u0002',500,'2018-1-5');
insert into order_info values (7,'u0002',600,'2018-1-6');
insert into order_info values (8,'u0002',300,'2018-1-10');
insert into order_info values (9,'u0002',800,'2018-1-16');
insert into order_info values (10,'u0002',800,'2018-1-22');

 

采用新的窗口函數的方法,就是使用row_number() over (partition by user_no order by create_date desc) as row_num 給原始記錄編一個號,然后取第一個編號的數據,自然就是“用戶的最新的一條訂單”,實現邏輯上清晰了很多,代碼也簡潔,可讀了很多。 

 需要注意的是,MySQL中的使用窗口函數的時候,是不允許使用*的,必須顯式指定每一個字段。

row_number()

(分組)排序編號,正如上面的例子, row_number()over(partition by user_no order by create_date desc) as row_num,按照用戶分組,按照create_date排序,對已有數據生成一個編號。
當然也可以不分組,對整體進行排序。任何一個窗口函數,都可以分組統計或者不分組統計(也即可以不要partition by ***都可以,看你的需求了)

rank()

類似於 row_number(),也是排序功能,但是rank()有什么不一樣?新的事物的出現必然是為了解決潛在的問題。
如果再往測試表中寫入一條數據:insert into order_info values (11,'u0002',800,'2018-1-22');
對於測試表中的U002用戶來說,有兩條create_date完全一樣的數據(假設有這樣的數據),那么在row_number()編號的時候,這兩條數據卻被編了兩個不同的號
理論上講,這兩條的數據的排名是並列最新的。因此rank()就是為了解決這個問題的,也即:排序條件一樣的情況下,其編號也一樣。

dense_rank()

dense_rank()的出現是為了解決rank()編號存在的問題的,
rank()編號的時候存在跳號的問題,如果有兩個並列第1,那么下一個名次的編號就是3,結果就是沒有編號為2的數據。
如果不想跳號,可以使用dense_rank()替代。

avg,sum等聚合函數在窗口函數中的的增強

可以在聚合函數中使用窗口功能,比如sum(amount)over(partition by user_no order by create_date) as sum_amont,達到一個累積計算sum的功能
這種需求在沒有窗口函數的情況下,用純sql寫起來,也夠蛋疼的了,就不舉例了。

 

NTILE(N) 將數據按照某些排序分成N組

舉個簡單的例子,按照分數線的倒序排列,將學生成績分成上中下3組,可以得到哪個程序數據上中下三個組中哪一部分,就可以使用NTILE(3) 來實現。這種需求倒是用的不是非常多。
如下還是使用上面的表,按照時間將user_no = 'u0002'的訂單按照時間的緯度,划分為3組,看每一行數據數據哪一組。

first_value(column_name) and last_value(column_name)

first_value和last_value基本上見名知意了,就是取某一組數據,按照某種方式排序的,最早的和最新的某一個字段的值。
看結果體會一下。

nth_value(column_name,n)

從排序的第n行還是返回nth_value字段中的值,這個函數用的不多,要表達的這種邏輯,說實話,很難用語言表達出來,看個例子體會一下就行。

n = 3

n = 4

cume_dist

在某種排序條件下,小於等於當前行值的行數/總行數,得到的是數據在某一個緯度的分布百分比情況。
比如如下示例
第1行數據的日期(create_date)是2018-01-05 00:00:00,小於等於2018-01-05 00:00:00的數據是1行,計算方式是:1/6 = 0.166666666
第2行數據的日期(create_date)是2018-01-06 00:00:00,小於等於2018-01-06 00:00:00的數據是2行,計算方式是:2/6 = 0.333333333
依次類推
第4行數據的日期(create_date)是2018-01-16 00:00:00,小於等於2018-01-16 00:00:00的數據是4行,計算方式是:4/6 = 0.6666666666
第一行數據的0.6666666666 意味着,小於第四行日期(create_date)的數據占了符合條件數據的66.66666666666%

percent_rank()

同樣是數據分布的計算方式,只不過算法變成了:當前RANK值-1/總行數-1 。
具體算法不細說,這個實際中用的也不多。

lag以及lead

lag(column,n)獲取當前數據行按照某種排序規則的上n行數據的某個字段,lead(column,n)獲取當前數據行按照某種排序規則的下n行數據的某個字段,確實很拗口。
舉個實際例子,按照時間排序,獲取當前訂單的上一筆訂單發生時間和下一筆訂單發生時間,(可以計算訂單的時間上的間隔度或者說買買買的頻繁程度)

select order_id,
         user_no,
         amount,
         create_date,
       lag(create_date,1) over (partition by user_no order by create_date asc) 'last_transaction_time',
       lead(create_date,1) over (partition by user_no order by create_date asc) 'next_transaction_time'
from order_info ; 

CTE 通用表表達式

CTE有兩種用法,非遞歸的CTE和遞歸的CTE。
非遞歸的CTE可以用來增加代碼的可讀性,增加邏輯的結構化表達。
平時我們比較痛恨一句sql幾十行甚至上上百行,根本不知道其要表達什么,難以理解,對於這種SQL,可以使用CTE分段解決,
比如邏輯塊A做成一個CTE,邏輯塊B做成一個CTE,然后在邏輯塊A和邏輯塊B的基礎上繼續進行查詢,這樣與直接一句代碼實現整個查詢,邏輯上就變得相對清晰直觀。
舉個簡單的例子,當然這里也不足以說明問題,比如還是第一個需求,查詢每個用戶的最新一條訂單
第一步是對用戶的訂單按照時間排序編號,做成一個CTE,第二步對上面的CTE查詢,取行號等於1的數據。

另外一種是遞歸的CTE,遞歸的話,應用的場景也比較多,比如查詢大部門下的子部門,每一個子部門下面的子部門等等,就需要使用遞歸的方式。
這里不做細節演示,僅演示一種遞歸的用法,用遞歸的方式生成連續日期。

當然遞歸不會無限下去,不同的數據庫有不同的遞歸限制,MySQL 8.0中默認限制的最大遞歸次數是1000。
超過最大低估次數會報錯:Recursive query aborted after 1001 iterations. Try increasing @@cte_max_recursion_depth to a larger value.
由參數@@cte_max_recursion_depth決定。

關於CTE的限制,跟其他數據庫並無太大差異,比如CTE內部的查詢結果都要有字段名稱,不允許連續對一個CTE多次查詢等等,相信熟悉CTE的老司機都很清楚。

窗口函數和CTE的增加,簡化了SQL代碼的編寫和邏輯的實現,並不是說沒有這些新的特性,這些功能都無法實現,只是新特性的增加,可以用更優雅和可讀性的方式來寫SQL。
不過這都是在MySQL 8.0中實現的新功能,在8.0之前,還是老老實實按照較為復雜的方式實現吧。

 

Primary key restrict

參數sql_require_primary_key控制

普通表和臨時表都會被限制

刪除當前主鍵報錯(除非同時新建主鍵),即便已有NOT NULL UK也報錯

導入無主鍵表報錯 

 

並行復制writeset機制

5.7的並行復制效率,取決於事務在主庫上的並發度。如果主庫上並發度不高,或者有大事務,則從庫延遲依然比較嚴重

8.0的writeset模式完美解決了這個難題:即便在主庫是串行提交,但只要事務間不沖突,在從庫依然可以並行回放

MySQL 8.0 中引入參數 binlog_transaction_depandency_tracking 用於控制如何決定事務的依賴關系。該值有三個選項:默認的 COMMIT_ORDERE表示繼續使用5.7中的基於組提交的方式決定事務的依賴關系;WRITESET 表示使用寫集合來決定事務的依賴關系,基於主鍵的並發策略,可以並發的執行同一個session內的事務;還有一個選項 WRITESET_SESSION 表示使用 WriteSet 來決定事務的依賴關系,基於主鍵的並發策略,但是同一個Session內的事務不會有相同的 last_committed 值,不可以並發執行同一個session內的事務。  

WriteSet 是通過檢測兩個事務是否更新了相同的記錄來判斷事務能否並行回放的,因此需要在運行時保存已經提交的事務信息以記錄歷史事務更新了哪些行。記錄歷史事務的參數為 binlog_transaction_dependency_history_size. 該值越大可以記錄更多的已經提交的事務信息,不過需要注意的是,這個值並非指事務大小,而是指追蹤的事務更新信息的數量。

從 MySQL Hight Availability 的測試中可以看到,開啟了基於 WriteSet 的事務依賴后,對Slave上RelayLog回放速度提升顯著。Slave上的 RelayLog 回放速度將不再依賴於 Master 上提交時的並行程度,使得Slave上可以發揮其最大的吞吐能力, 這個特性在Slave上復制停止一段時間后恢復復制時尤其有效。

這個特性使得 Slave 上可能擁有比 Master 上更大的吞吐量,同時可能在保證事務依賴關系的情況下,在 Slave 上產生 Master 上沒有產生過的提交場景,事務的提交順序可能會在 Slave 上發生改變。 雖然在5.7 的並行復制中就可能發生這種情況,不過在8.0中由於 Slave 上更高的並發能力,會使該場景更加常見。 通常情況下這不是什么大問題,不過如果在 Slave 上做基於 Binlog 的增量備份,可能就需要保證在 Slave 上與Master 上一致的提交順序,這種情況下可以開啟 slave_preserve_commit_order 這是一個 5.7 就引入的參數,可以保證 Slave 上並行回放的線程按 RelayLog 中寫入的順序 Commit。

 

8.0.14后新特性

雙密碼機制

從MySQL8.0.14開始,允許用戶賬戶擁有雙密碼,指定為主密碼和輔助密碼

mysql>create user root@'%' identified by '123456'; 
mysql>grant all privileges on *.* to root@'%'; 
創建新密碼
mysql>alter user root@'%' identified by 'root' RETAIN CURRENT PASSWORD; 
丟棄舊密碼: 
mysql>alter user root@'%' DISCARD OLD PASSWORD;

 

Binary log 加密機制,屬於安全機制方面

redo & undo 日志加密

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

log_slow_extra

mysql>  SET GLOBAL log_slow_extra=1;

log_slow_extra 慢日志參數,提供了更詳細的內容

admin_port

使用的端口默認為33062, 由admin_port來設置 

mysql> show variables like 'admin_%';
+---------------+---------------+
| Variable_name | Value         |
+---------------+---------------+
| admin_address | 192.168.1.101 |
| admin_port    | 33062         |
+---------------+---------------+
2 rows in set (0.00 sec)

 

默認字符集由latin1變為utf8mb4

在8.0版本之前,默認字符集為latin1,utf8指向的是utf8mb3,8.0版本默認字符集為utf8mb4,utf8默認指向的也是utf8mb4 

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.11
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大數據在只有少量修改的情況下,對資源的占用。

 

8.0幾個特殊參數

log_error_verbosity=3
innodb_print_ddl_logs=1
binlog_expire_logs_seconds=86400
innodb-undo-tablespaces=10
innodb-undo-directory=undolog

 

轉自

MySQL8.0新特性實驗1 - AllenHU320 - 博客園
https://www.cnblogs.com/allenhu320/p/11551010.html


免責聲明!

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



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