背景:
繼上次介紹 初識 MySQL 5.6 新功能、參數完之后,剛好MySQL 5.7又GA了,在官方測試里看到,MySQL5.7在功能、性能、可用性、安全和監控上又提升了很高。現在看看和MySQL5.6對比,之前介紹了新增配置參數和安全相關特性。本文來說明MySQL5.7關於功能和性能提升的方面(持續更新)。
1,功能性能上的提升
1.1:復制功能的提升。
①支持並行復制。slave-parallel-type
5.6開始支持基於庫(database)的並行復制,對於只有一個庫的,效果不好。5.7開始支持基於組提交(LOGICAL_CLOCK)的並行復制,提高復制的可用性。
②支持多源復制,通過channel支持一個從庫復制多個主庫。
③支持在線修改REPLICATION FILTER:REPLICATE_DO_DB、REPLICATE_IGNORE_DB。通過change replicate filter,需要停止SQL thread,修改完成以后,啟動SQL thread。可以參考這篇文章。
由於篇幅的原因,后面會另起一篇文章介紹上面功能的細節。
1.2:mysqlpump,並行版 mysqldump,也是替換原生 mysqldump 和 mydumper 的。--watch-progress 查看dump進度,--compress-ouptut 壓縮,也支持 SSL。 大致的優勢如下:(后面會起一篇文章來說明mysqlpump的使用)
- 支持基於表的並行導出功能(參數–default-parallelism,默認為2,參數–parallel-schemas,控制並行導出的庫)
- 導出的時候帶有進度條(參數–watch-progress,默認開啟)
- 支持直接壓縮導出導入(參數–compress-output,支持ZLIB和LZ4)
1.3:online alter table。在初識 MySQL 5.6 新功能、參數里介紹的online ddl的基礎上又增加了:
①:在線加主鍵:當主鍵列為null字段的時候,5.6建主鍵需要復制表,5.7可以inplace:
5.6: >create table test(id int); Query OK, 0 rows affected (0.00 sec) >insert into test values(1),(2),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 >alter table test add primary key(id); Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 ###copy 5.7: >create table test(id int); Query OK, 0 rows affected (0.01 sec) >insert into test values(1),(2),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 >alter table test add primary key(id); Query OK, 0 rows affected (0.03 sec) ###inplace Records: 0 Duplicates: 0 Warnings: 0
②:varchar長度變更(加大)支持inplace,需要注意的是有一個限制,即用於表示varchar字段長度的字節數不能發生變化,也就是支持比如varchar的字節長度在255(Latin1)以下變更或者255以上的范圍進行變更,因為從小於255變更到大於255,其size的字節需要從1個增加到2個,另一個注意的是不允許inplace字段長度變小:
>show create table test\G *************************** 1. row *************************** Table: test Create Table: CREATE TABLE `test` ( `id` int(11) NOT NULL, `name` varchar(10) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) >alter table test modify name varchar(64); ##inplace modify Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 >alter table test modify name varchar(128); ##inplace modify Query OK, 0 rows affected (0.00 sec) Records: 0 Duplicates: 0 Warnings: 0 >alter table test modify name varchar(255); ##inplace modify Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 >alter table test modify name varchar(256); ##copy modify,超過了255 Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0 >alter table test modify name varchar(64); ##copy modify,長度變小 Query OK, 3 rows affected (0.01 sec) Records: 3 Duplicates: 0 Warnings: 0
③:支持online rename index操作:
>show create table test\G *************************** 1. row *************************** Table: test Create Table: CREATE TABLE `test` ( `id` int(11) NOT NULL, `name` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`), KEY `name` (`name`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 1 row in set (0.00 sec) >alter table test rename index name to idx_name;
...
1.4:Undo Log日志的在線回收。innodb undo log占用共享表空間並且無法回收,在5.6的時候可以把undo log分離到獨立的表空間,並放到單獨的文件目錄下,但是其文件大小也不會回收。5.7之后可以在線收縮undo log:需要開啟innodb_undo_log_truncate、innodb_undo_tablespaces和innodb_undo_directory參數,當大小超過innodb_max_undo_log_size的大小則會被undo會被標記為可truncate。具體的原理可以看這篇文章。undo log 在整個事務未提交前,undo page是必須強占內存,這會讓buffer pool size 收到污染,可以看這個例子說明。
1.5:新增json類型。關於json類型操作的函數參考官方文檔和MySQL5.7 JSON類型使用介紹,原理介紹見MySQL5.7的JSON 實現。
MySQL對支持JSON的做法是在server層提供了一堆便於操作JSON的函數,簡單地將JSON編碼成BLOB,然后交由存儲引擎層進行處理。MySQL 5.7的JSON支持與存儲引擎沒有關系,MyISAM 存儲引擎也支持JSON 格式。MySQL對JSON的支持,至少有兩點能夠完勝MongoDB:可以混合存儲結構化數據和非結構化數據,同時擁有關系型數據庫和非關系型數據庫的優點;能夠提供完整的事務支持。
1.6:generate column。一列由其他列計算而得,可生成索引的虛擬化列。
mysql> create table t(id int,score int,score_ss int as (score*33)); Query OK, 0 rows affected (0.25 sec) mysql> select * from t; Empty set (0.00 sec) mysql> select * from t; Empty set (0.00 sec) mysql> insert into t(id,score) values(1,10); Query OK, 1 row affected (0.03 sec) mysql> select * from t; +------+-------+----------+ | id | score | score_ss | +------+-------+----------+ | 1 | 10 | 330 | +------+-------+----------+ 建表標准的語法: CREATE TABLE `t` ( `id` int(11) DEFAULT NULL, `score` int(11) DEFAULT NULL, `score_ss` int(11) GENERATED ALWAYS AS ((`score` * 33)) VIRTUAL/STORED, KEY `idx_score_ss` (`score_ss`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8
MySQL5.7支持兩種generated column,即virtual generated column和stored generated column,前者只將generated column保存在數據字典中(表的元數據),並不會將這一列數據持久化到磁盤上;后者會將generated column持久化到磁盤上,而不是每次讀取的時候計算所得。很明顯,后者存放了可以通過已有數據計算而得的數據,需要更多的磁盤空間,與virtual column相比並沒有優勢。因此,在不指定generated column的類型時,默認是virtual column,並且為generate column創建索引可以提高性能。
1.7:InnoDB 全文索引的加強:支持中文分詞。InnoDB默認的全文索引parser非常合適於Latin,因為Latin是通過空格來分詞的。可以看這篇文章的介紹,但對於像中文,日文和韓文來說,沒有這樣的分隔符。一個詞可以由多個字來組成,所以我們需要用不同的方式來處理。在MySQL 5.7.6中我們能使用一個新的全文索引插件來處理它們:n-gram parser。關於n-gram的介紹和使用可以看這篇文章。
在全文索引中,n-gram就是一段文字里面連續的n個字的序列。例如,用n-gram來對”信息系統”來進行分詞,得到的結果如下:
1
2
3
4
|
N=1 : '信', '息', '系', '統'
N=2 : '信息', '息系', '系統';
N=3 : '信息系', '息系統';
N=4 : '信息系統';
|
其中N是有參數ngram_token_size控制,即分詞的大小,默認是2。這里簡單說明一下:
mysql> CREATE TABLE t_fulltext( -> `id` int(11) DEFAULT NULL, -> `name` varchar(512) DEFAULT NULL, -> `content` text, -> FULLTEXT KEY idx_name(name), -> FULLTEXT KEY idx_content(content) WITH PARSER ngram -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8; Query OK, 0 rows affected (0.07 sec) 或則建好表后添加: alter table t_fulltext add fulltext idx_content(content) WITH PARSER ngram; mysql> INSERT INTO t_fulltext (id,name,content) VALUES (1,'信息系統','自然科學'); Query OK, 1 row affected (0.00 sec) mysql> SELECT * FROM t_fulltext WHERE MATCH (name) AGAINST ('信息系統'); ###普通的全文檢索必須要整個詞才能檢索到。 +------+--------------+--------------+ | id | name | content | +------+--------------+--------------+ | 1 | 信息系統 | 自然科學 | +------+--------------+--------------+ 1 row in set (0.01 sec) mysql> SELECT * FROM t_fulltext WHERE MATCH (name) AGAINST ('信息'); ###拿里面的出來檢索不出來 Empty set (0.01 sec) mysql> SELECT * FROM t_fulltext WHERE MATCH (content) AGAINST ('自然'); ###新的全文檢索功能可以檢索到任意2個組合 +------+--------------+--------------+ | id | name | content | +------+--------------+--------------+ | 1 | 信息系統 | 自然科學 | +------+--------------+--------------+ 1 row in set (0.00 sec) mysql> SELECT * FROM t_fulltext WHERE MATCH (content) AGAINST ('然科'); ###新的全文檢索功能可以檢索到任意2個組合 +------+--------------+--------------+ | id | name | content | +------+--------------+--------------+ | 1 | 信息系統 | 自然科學 | +------+--------------+--------------+ 1 row in set (0.01 sec)
這里可以查看分詞的信息:
mysql> INSERT INTO articles (title) VALUES ('信息系統'); Query OK, 1 row affected (0.01 sec) mysql> SET GLOBAL innodb_ft_aux_table="test/articles"; Query OK, 0 rows affected (0.00 sec) mysql> SELECT * FROM INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHE; +--------+--------------+-------------+-----------+--------+----------+ | WORD | FIRST_DOC_ID | LAST_DOC_ID | DOC_COUNT | DOC_ID | POSITION | +--------+--------------+-------------+-----------+--------+----------+ | 信息 | 1 | 1 | 1 | 1 | 0 | | 息系 | 1 | 1 | 1 | 1 | 3 | | 系統 | 1 | 1 | 1 | 1 | 6 | +--------+--------------+-------------+-----------+--------+----------+ 3 rows in set (0.00 sec)
關於全文檢索的進一步測試,包括停止詞語會另起一篇文章說明。
1.8:動態修改InnoDB Buffer Pool Size。mysql> show variables like '%innodb_buffer_pool_size%'; #當前BP的大小512M +-------------------------+-----------+ | Variable_name | Value | +-------------------------+-----------+ | innodb_buffer_pool_size | 536870912 | +-------------------------+-----------+ 1 row in set (0.00 sec) mysql> show variables like 'innodb_buffer_pool_instances'; #BP實例1個,因為BP小於1G +------------------------------+-------+ | Variable_name | Value | +------------------------------+-------+ | innodb_buffer_pool_instances | 1 | +------------------------------+-------+ 1 row in set (0.00 sec) mysql> set global innodb_buffer_pool_size=1048576000; #設置BP的大小為1000M Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> show warnings;#設置1000M報warnings,原因是它不是innodb_buffer_pool_chunk_size* innodb_buffer_pool_instances的倍數,即128M的倍數。 +---------+------+-----------------------------------------------------------------+ | Level | Code | Message | +---------+------+-----------------------------------------------------------------+ | Warning | 1292 | Truncated incorrect innodb_buffer_pool_size value: '1048576000' | +---------+------+-----------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> show global status like 'Innodb_buffer_pool_resize_status'; #查看進度 +----------------------------------+----------------------------------------------------+ | Variable_name | Value | +----------------------------------+----------------------------------------------------+ | Innodb_buffer_pool_resize_status | Completed resizing buffer pool at 160708 18:20:15. | +----------------------------------+----------------------------------------------------+ 1 row in set (0.00 sec) mysql> show variables like '%innodb_buffer_pool_size%'; #被設置成了1024M,因為1024是128的整數倍,出現了BP比配置文件里指定的size還大。 +-------------------------+------------+ | Variable_name | Value | +-------------------------+------------+ | innodb_buffer_pool_size | 1073741824 | +-------------------------+------------+ 1 row in set (0.00 sec)
在線調整BP的日志:
2016-07-08T18:20:15.278753+08:00 3 [Note] InnoDB: Requested to resize buffer pool. (new size: 1073741824 bytes) #調整的BP大小。 2016-07-08T18:20:15.278786+08:00 0 [Note] InnoDB: Resizing buffer pool from 536870912 to 1073741824 (unit=134217728).#從多大到多大,單位多少 2016-07-08T18:20:15.278845+08:00 0 [Note] InnoDB: Disabling adaptive hash index. #禁用AHI,清理所有的索引緩存 2016-07-08T18:20:15.280839+08:00 0 [Note] InnoDB: disabled adaptive hash index. 2016-07-08T18:20:15.280864+08:00 0 [Note] InnoDB: Withdrawing blocks to be shrunken.#回收空閑的block 2016-07-08T18:20:15.280876+08:00 0 [Note] InnoDB: Latching whole of buffer pool. #鎖住整個BP 2016-07-08T18:20:15.280896+08:00 0 [Note] InnoDB: buffer pool 0 : resizing with chunks 4 to 8. #大小從4個chunks變成8個chunks 2016-07-08T18:20:15.295961+08:00 0 [Note] InnoDB: buffer pool 0 : 4 chunks (32764 blocks) were added. 2016-07-08T18:20:15.296015+08:00 0 [Note] InnoDB: Completed to resize buffer pool from 536870912 to 1073741824. #設置新值完成 2016-07-08T18:20:15.296031+08:00 0 [Note] InnoDB: Re-enabled adaptive hash index. #開啟AHI 2016-07-08T18:20:15.296048+08:00 0 [Note] InnoDB: Completed resizing buffer pool at 160708 18:20:15. #調整完成
1.9:多線程臟頁刷寫
innodb_page_cleaners,表示刷寫BP臟頁的線程數,5.6.2開始從master線程中獨立出來,5.7.4之后開始支持多線程flush,默認是4。這個值必須小於等於innodb_buffer_pool_instances,提高CPU的利用率。
1.10:終止會話ctrl+c
在linux下,我們經常使用ctrl+c
來終止一個命令的運行,在MySQL 5.7 之前,如果用戶輸入了錯誤的SQL語句,按下ctrl+c
,雖然能夠"結束"SQL語句的運行,但是,也會退出當前會話,MySQL 5.7對這一違反直覺的地方進行了改進,不再退出會話。
1.11:臨時表性能的優化
MYSQL5.7為了提高臨時表相關的性能,對臨時表相關的部分進行了大幅修改,包括引入新的臨時表空間(ibtmp1);對於臨時表的DDL,不持久化相關表定義;對於臨時表的DML,不寫redo,關閉change buffer等。
InnoDB臨時表元數據不再存儲於InnoDB系統表而是存儲在INNODB_TEMP_TABLE_INFO,包含所有用戶和系統創建的臨時表信息。該表在第一次在其上運行select時被創建:
mysql> select * from information_schema.innodb_temp_table_info; Empty set (0.00 sec) mysql> use dba_test mysql> create temporary table temp_1(id int,name varchar(100))default charset utf8; Query OK, 0 rows affected (0.00 sec) mysql> select * from information_schema.innodb_temp_table_info; +----------+--------------+--------+-------+----------------------+---------------+ | TABLE_ID | NAME | N_COLS | SPACE | PER_TABLE_TABLESPACE | IS_COMPRESSED | +----------+--------------+--------+-------+----------------------+---------------+ | 42 | #sql1883_8_0 | 5 | 27 | FALSE | FALSE | +----------+--------------+--------+-------+----------------------+---------------+ 1 row in set (0.00 sec)
並且MySQL5.7使用了獨立的臨時表空間來存儲臨時表數據,但不能是壓縮表。臨時表空間在實例啟動的時候進行創建,shutdown的時候進行刪除。即為所有非壓縮的innodb臨時表提供一個獨立的表空間,默認的臨時表空間文件為ibtmp1,位於數據目錄。我們可通過innodb_temp_data_file_path參數指定臨時表空間的路徑和大小,默認12M。只有重啟實例才能回收臨時表空間文件ibtmp1的大小。create temporary table和using temporary table將共用這個臨時表空間。
mysql >show variables like 'innodb_temp_data_file_path'; +----------------------------+-----------------------+ | Variable_name | Value | +----------------------------+-----------------------+ | innodb_temp_data_file_path | ibtmp1:12M:autoextend | +----------------------------+-----------------------+
物理文件:
# ls -lh ibtmp1 -rw-r----- 1 mysql mysql 12M 7月 12 15:13 ibtmp1 mysql> create temporary table temp_1(id int,name varchar(100))default character set utf8; Query OK, 0 rows affected (0.01 sec) mysql> insert into temp_1 select * from ttt; Query OK, 2752512 rows affected (7.10 sec) Records: 2752512 Duplicates: 0 Warnings: 0 # ls -lh ibtmp1 -rw-r----- 1 mysql mysql 204M 7月 12 15:16 ibtmp1 #重啟才能回收
在MySQL5.7中,臨時表在連接斷開或者數據庫實例關閉的時候,會進行刪除,也就無需redo logs,避免了寫relog相關的io,從而提高了性能。只有臨時表的metadata使用了redo保護,保護元數據的完整性,以便異常啟動后進行清理工作。臨時表的元數據5.7之后使用了一個獨立的表(innodb_temp_table_info)進行保存,這樣就不要使用redo保護,元數據也只保存在內存中。但這有一個前提,必須使用共享的臨時表空間,如果使用file-per-table,仍然需要持久化元數據,以便異常恢復清理。臨時表需要undo log,用於MySQL運行時的回滾、MVCC等。具體的可以看官方文檔和臨時表優化說明。
注意:從5.7.5開始,新增一個系統選項internal_tmp_disk_storage_engine可定義磁盤臨時表的引擎類型,默認為InnoDB,可選MyISAM。而在這以前,只能使用MyISAM。而在5.6.3以后新增的參數default_tmp_storage_engine是控制create temporary table創建的臨時表的存儲引擎,在以前默認是MEMORY。
mysql> show variables like '%engine%'; +----------------------------------+--------+ | Variable_name | Value | +----------------------------------+--------+ | default_storage_engine | InnoDB | | default_tmp_storage_engine | InnoDB | | disabled_storage_engines | | | enforce_storage_engine | | | internal_tmp_disk_storage_engine | InnoDB | +----------------------------------+--------+
1.12:innochecksum離線的InnoDB文件校驗工具功能增強,可以查看ibd文件。新增選擇項或擴展的功能:
1.支持使用指定校驗算法; 2.支持只重寫校驗值而不進行驗證; 3.可指定允許的校驗和不匹配量; 4.顯示各類頁的個數、導出頁類型信息、輸出至日志、從標准輸入讀取數據等; 5.從5.7.2起可支持校驗超過2G的文件;
如何使用innochecksum可以看官網和執行innochecksum --help。使用時需要停止mysql服務,或則把ibd文件復制出來,否則會報錯:
# innochecksum --page-type-summary ibdata1 Error: Unable to lock file:: ibdata1 fcntl: Resource temporarily unavailable
關閉數據庫或則復制出ibd文件執行:
# innochecksum --page-type-summary /tmp/ibdata1 File::/tmp/ibdata1 ================PAGE TYPE SUMMARY============== #PAGE_COUNT PAGE_TYPE =============================================== 13 Index page #索引頁 2820 Undo log page #undo頁 2 Inode page 0 Insert buffer free list page #插入緩存空閑頁 1928 Freshly allocated page #可用頁 1 Insert buffer bitmap #插入緩存位圖頁 98 System page #系統頁 1 Transaction system page 1 File Space Header 0 Extent descriptor page 0 BLOB page 0 Compressed BLOB page 0 Other type of page =============================================== Additional information: Undo page type: 2806 insert, 14 update, 0 other Undo page state: 0 active, 36 cached, 0 to_free, 0 to_purge, 0 prepared, 2784 other
通過 --page-type-summary 參數可以看到表空間里面各個頁的情況,關於頁的一些細節信息可以參考看MySQL Innodb 存儲結構 。
通過 --count 參數可以查看表空間的總頁數:
# innochecksum --count /tmp/ibdata1 Number of pages:4864
1.13:默認行格式改變,由innodb_default_row_format控制,5.7.9之后默認DYNAMIC,之前默認COMPACT。更多信息見官方文檔。
1.14:支持創建全局通用表空間,全局表空間可以被所有的數據庫的表共享,而且相比於獨享表空間使用手動創建共享表空間可以節約元數據方面的內存。可以在創建表的時候,指定屬於哪個表空間,也可以對已有表進行表空間修改,具體的信息可以查看官方文檔。
mysql> create tablespace dxy add datafile 'dxy.ibd' file_block_size=16k; #創建名為dxy的共享表空間 Query OK, 0 rows affected (0.10 sec) mysql> create table t1(id int,name varchar(10))engine = innodb default charset utf8mb4 tablespace dxy; #指定表空間 Query OK, 0 rows affected (0.09 sec) # ls -lh -rw-r----- 1 mysql mysql 96K 7月 14 12:11 dxy.ibd #查看表空間文件 mysql> alter table ttt tablespace dxy; #指定表空間
# ls -lh dxy.ibd -rw-r----- 1 mysql mysql 244M 7月 14 12:18 dxy.ibd #表空間文件變大
如何刪除創建的共享表空間?因為是共享表空間不能直接通過drop table tbname來刪除,也不能回收空間。當確定共享表空間的數據都沒用,並且依賴該表空間的表均已經刪除,則可以通過drop tablespace來刪除共享表空間來釋放空間,如果依賴該共享表空間的表存在則會刪除失敗。
# ls -lh dxy.ibd -rw-r----- 1 mysql mysql 452M 7月 14 12:27 dxy.ibd mysql> drop table t1; #刪除依賴該表空間的表 Query OK, 0 rows affected (0.16 sec) mysql> drop tablespace dxy; #刪除表空間 ERROR 1529 (HY000): Failed to drop TABLESPACE dxy #刪除失敗,因為還有表依賴這個表空間。 mysql> drop table ttt; Query OK, 0 rows affected (0.04 sec) mysql> drop tablespace dxy; #成功刪除自建的共享表空間 Query OK, 0 rows affected (0.03 sec) # ls -lh dxy.ibd ls: cannot access dxy.ibd: No such file or directory #ibd文件被刪除,空間回收。
1.15:InnoDB Tablespace Encryption,支持對獨享表空間的InnoDB數據文件加密,其依賴keyring plugin來進行秘鑰的管理,開啟加密功能需要啟動參數--early-plugin-load。
[mysqld] early-plugin-load=keyring_file.so
開始參數后,查看是否支持:
mysql> SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS where PLUGIN_NAME LIKE 'keyring%'; +--------------+---------------+ | PLUGIN_NAME | PLUGIN_STATUS | +--------------+---------------+ | keyring_file | ACTIVE | +--------------+---------------+ 1 row in set (0.00 sec)
創建加密表空間:
mysql> create table t(id int,name varchar(10))engine = innodb default charset utf8mb4 encryption='y'; Query OK, 0 rows affected (0.17 sec) mysql> show create table t\G *************************** 1. row *************************** Table: t Create Table: CREATE TABLE `t` ( `id` int(11) DEFAULT NULL, `name` varchar(10) DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ENCRYPTION='y' 1 row in set (0.00 sec)
1.16:NVM file system。MySQL一直使用double write buffer來解決一個page寫入的partial write問題,但在linux系統上的Fusion-io Non-Volatile Memory (NVM) file system支持原子的寫入。這樣就可以省略掉double write buffer的使用, 5.7.4以后,如果Fusion-io devices支持atomic write,那么MySQL自動把dirty block直接寫入到數據文件了。這樣減少了一次內存copy和IO操作。
1.17:InnoDB分區表。MySQL 5.7之前的版本,InnoDB並不支持分區表,分區表的支持是在ha_partition引擎上支持的,從5.7開始,InnoDB支持原生的分區表,並且可以使用傳輸表空間。
1.18:支持在一個table對象上建多個trigger。
持續更新...
...
MySQL 5.7.7版本之后新增了sys 數據庫,該庫通過視圖的形式把information_schema和performance_schema結合起來,查詢出更加令人容易理解的數據,幫助dba和開發人員收集的數據庫性能信息,快速定位性能瓶頸。sys下的一共包括三種對象:1. view,2. procedure 3 function
這些對象都是基於performance_schema下的表,進行了可讀性的聚合,沒有真正存儲數據,只存儲了定義。默認通過賬號'mysql.sys'@'localhost'收集信息,之前是root@localhost進行收集操作。安裝時可以通過--skip-sys-schema跳過安裝。后面會另起一篇文章對sys schema進行說明,也可以先看DBA的好幫手——sys schema和MySQL 5.7系列之sys schema(2) by吳炳錫。
3,被刪除和被修改默認值的參數和特性
參數移除:
3.1:MySQL 5.7.4之后innodb_additional_mem_pool_size參數被移除。原來是存放數據字典和內部數據結構,要是表很多,需要分配更多的內存。若緩沖池的內存溢出則需要從系統分配內存,但會寫一個warning到錯誤日志。
3.2:MySQL5.7.4之后innodb_use_sys_malloc參數被移除。原來表示InnoDB使用操作系統內存分配器還是自己的內存分配器,默認是使用操作系統內存分配器。3.1和3.2被移除的原因,是因為內部實現不如外部的實現,可以見http://www.kancloud.cn/taobaomysql/monthly/143931。
3.3:innodb 存儲引擎不能被禁用,系統表有innodb表。 --innodb=OFF
and --skip-innodb沒有作用,未來會移除該參數。
3.4:innodb_file_format、innodb_file_format_check、innodb_file_format_max在MySQL5.7.7被棄用,未來會被移除。
3.5:innodb_large_prefix在MySQL5.7.7中被棄用,將來會移除。該參數表示當innodb為字段創建索引時,限制的字節長度。關閉時,字節長度大於767則會報錯。開啟時,大於3072則會報錯,創建不成功。
3.6:innodb_locks_unsafe_for_binlog在MySQL5.6.3被棄用,將來會移除。該參數表示innodb鎖和二進制的安全問題,當ON的時候可以避免gap lock的問題,但是會引起binlog寫入順序出問題,導致主從數據不一致。建議關閉。
3.7:innodb_support_xa在MySQL5.7.1中被棄用,將來會移除。MySQL5.7.1之后不能禁用innodb_support_xa。雖然它會導致一次額外的磁盤flush(prepare階段flush redo log). 但是我們必須啟用,而不能關閉它。因為關閉會導致binlog寫入的順序和實際的事務提交順序不一致,會導致崩潰恢復和slave復制時發生數據錯誤。如果啟用了log-bin參數,並且不止一個線程對數據庫進行修改,那么就必須啟用innodb_support_xa參數。
3.8:@@session.gtid_executed 不建議使用,將來會移除。
3.9:binlog_format在MySQL5.7.7之后,默認值變成ROW。
3.10:slave_net_timeout在MySQL5.7.7之后,默認改成60秒。該參數定義了從庫從主庫獲取數據等待的秒數,超過這個時間從庫會主動退出讀取,中斷連接,並嘗試重連。即:設置在多久沒收到數據后認為網絡超時,之后 Slave 的 IO 線程會重新連接 Master。此前的默認值是3600秒,長時間的復制延遲很可能是網絡瞬斷造成的。可以用一個心跳時間master_heartbeat_period來避免,具體可以看MySQL復制心跳的詳細說明。大致的流程如下:

說明: 在MySQL的復制協議里,由 Slave 發送一個 COM_BINLOG_DUMP 命令后,就完全由 Master 來推送數據,Master、Slave 之間不再需要交互。如果 Master 沒有更新,也就不會有數據流,Slave 就不會收到任何數據包。但是如果由於某種原因造成 Master 無法把數據發送到 Slave ,比如發生過網絡故障或其他原因導致 Master 上的 TCP 連接丟失,Slave 沒有機會得到通知,所以也沒法知道收不到數據是因為 Master 本來就沒有更新呢還是由於出了故障。 stop slave; change master to master_heartbeat_period = 10; set global slave_net_timeout = 25; start slave; 心跳會讓Master 在沒有數據的時候,每10秒發送一個心跳包。這樣 Slave 就能知道 Master 是不是還正常。slave_net_timeout是設置在多久沒收到數據后認為網絡超時,之后 Slave 的 IO 線程會重新連接 Master 。 結合這兩個設置就可以避免由於網絡問題導致的復制延誤。master_heartbeat_period 單位是秒,可以是個帶上小數,如 10.5。最高精度為 1 毫秒。 需要注意的是:默認情況heartbeat_period的值是slave_net_timeout的一般。在從上通過show global status like 'slave%'來查看心跳信息。 要是heartbeat_period設置大於slave_net_timeout會報warnings: The requested value for the heartbeat period exceeds the value of `slave_net_timeout' seconds. A sensible value for the period should be less than the timeout.
關於從庫重連主庫的相關信息:

MySQL 可以指定三個參數,用於復制線程重連主庫: --master-retry-count , --master-connect-retry , --slave-net-timeout 。 其中 master-connect-retry 和 master-retry-count 需要在 Change Master 搭建主備復制時指定,而 slave-net-timeout 是一個全局變量,可以在 MySQL 運行時在線設置。 具體的重試策略為:備庫過了slave-net-timeout秒還沒有收到主庫來的數據,它就會開始第一次重試。然后每過 master-connect-retry 秒,備庫會再次嘗試重連主庫。直到重試了 master-retry-count 次,它才會放棄重試。如果重試的過程中,連上了主庫,那么它認為當前主庫是好的,又會開始 slave-net-timeout 秒的等待。 slave-net-timeout 的默認值是 60 秒, master-connect-retry 默認為 60 秒, master-retry-count 默認為 86400 次。也就是說,如果主庫一分鍾都沒有任何數據變更發送過來,備庫才會嘗試重連主庫。 如果主庫上變更比較頻繁,可以考慮將 slave-net-timeout 設置的小一點,避免主庫Binlog dump(IO)線程終止,無法將最新的更新推送過來,及時發現問題而不是等到超時之后才收到報錯去處理。 當然 slave-net-timeout 設置的過小也有問題,這樣會導致如果主庫的變更確實比較少的時候,備庫頻繁的重新連接主庫,造成資源浪費。
3.11:sync_binlog在MySQL5.7.7之后,默認值改成了1,更安全。因為MySQL5.6支持了組提交的功能,所以值1不像5.6之前的說的binlog提交一次就寫一次磁盤,而是表了在把binlog刷新到磁盤前,提交的組的數量。
...
特性移除:
3.1:innodb_table_monitor特性在MySQL 5.7.4中被移除。通過參數innodb_status_output、innodb_status_output_locks動態修改成on,把show engine innodb status打印到error log中;通過information_schema中INNODB_SYS%開頭的表可以把innodb_table_monitor的信息顯示出來,對比說明下他們的差異,方便自己查閱。

####通過innodb_table_monitor打印到error log 中的信息,關於說明請見innodb_table_monitor的介紹 TABLE: name jute/jute_vote, id 149, flags 1, columns 8, indexes 1, appr.rows 182198 COLUMNS: surveyId: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; userId: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; choiceId: DATA_INT DATA_BINARY_TYPE DATA_NOT_NULL len 4; voteTime: DATA_FIXBINARY DATA_BINARY_TYPE DATA_NOT_NULL len 5; comment: DATA_BLOB len 11; DB_ROW_ID: DATA_SYS prtype 256 len 6; DB_TRX_ID: DATA_SYS prtype 257 len 6; DB_ROLL_PTR: DATA_SYS prtype 258 len 7; INDEX: name PRIMARY, id 324, fields 2/7, uniq 2, type 3 root page 3, appr.key vals 182198, leaf pages 472, size pages 545 FIELDS: surveyId userId DB_TRX_ID DB_ROLL_PTR choiceId voteTime comment #####通過information_schema中各相關表(7張表)的說明,和上面對比 information_schema 12:31:21>select * from INNODB_SYS_TABLES where NAME='jute/jute_vote'; +----------+----------------+------+--------+-------+-------------+------------+---------------+ | TABLE_ID | NAME | FLAG | N_COLS | SPACE | FILE_FORMAT | ROW_FORMAT | ZIP_PAGE_SIZE | +----------+----------------+------+--------+-------+-------------+------------+---------------+ | 149 | jute/jute_vote | 1 | 8 | 143 | Antelope | Compact | 0 | +----------+----------------+------+--------+-------+-------------+------------+---------------+ 1 row in set (0.00 sec) information_schema 12:32:30>select * from INNODB_SYS_DATAFILES where SPACE=143; +-------+----------------------+ | SPACE | PATH | +-------+----------------------+ | 143 | ./jute/jute_vote.ibd | +-------+----------------------+ 1 row in set (0.00 sec) information_schema 12:32:44>select * from INNODB_SYS_TABLESPACES where SPACE=143; +-------+----------------+------+-------------+----------------------+-----------+---------------+ | SPACE | NAME | FLAG | FILE_FORMAT | ROW_FORMAT | PAGE_SIZE | ZIP_PAGE_SIZE | +-------+----------------+------+-------------+----------------------+-----------+---------------+ | 143 | jute/jute_vote | 0 | Antelope | Compact or Redundant | 16384 | 0 | +-------+----------------+------+-------------+----------------------+-----------+---------------+ 1 row in set (0.01 sec) information_schema 12:32:55>select * from INNODB_SYS_TABLESTATS where table_id=149; +----------+----------------+-------------------+----------+------------------+------------------+------------------+---------+-----------+ | TABLE_ID | NAME | STATS_INITIALIZED | NUM_ROWS | CLUST_INDEX_SIZE | OTHER_INDEX_SIZE | MODIFIED_COUNTER | AUTOINC | REF_COUNT | +----------+----------------+-------------------+----------+------------------+------------------+------------------+---------+-----------+ | 149 | jute/jute_vote | Initialized | 182198 | 545 | 0 | 0 | 0 | 1 | +----------+----------------+-------------------+----------+------------------+------------------+------------------+---------+-----------+ 1 row in set (0.01 sec) information_schema 12:38:33>select * from INNODB_SYS_INDEXES where TABLE_ID=149; +----------+---------+----------+------+----------+---------+-------+ | INDEX_ID | NAME | TABLE_ID | TYPE | N_FIELDS | PAGE_NO | SPACE | +----------+---------+----------+------+----------+---------+-------+ | 324 | PRIMARY | 149 | 3 | 2 | 3 | 143 | +----------+---------+----------+------+----------+---------+-------+ 1 row in set (0.01 sec) information_schema 12:33:25>select * from INNODB_SYS_COLUMNS where TABLE_ID=149; +----------+----------+-----+-------+---------+-----+ | TABLE_ID | NAME | POS | MTYPE | PRTYPE | LEN | +----------+----------+-----+-------+---------+-----+ | 149 | surveyId | 0 | 6 | 1283 | 4 | | 149 | userId | 1 | 6 | 1283 | 4 | | 149 | choiceId | 2 | 6 | 1283 | 4 | | 149 | voteTime | 3 | 3 | 525580 | 5 | | 149 | comment | 4 | 5 | 2949372 | 11 | +----------+----------+-----+-------+---------+-----+ 5 rows in set (0.01 sec) information_schema 12:33:37>select * from INNODB_SYS_FIELDS where INDEX_ID in (324); +----------+----------+-----+ | INDEX_ID | NAME | POS | +----------+----------+-----+ | 324 | surveyId | 0 | | 324 | userId | 1 | +----------+----------+-----+ 2 rows in set (0.00 sec)
也可以通過一條sql進行對innodb_table_monitor的展示,里面各參數的意義看官方文檔:
SELECT a.PATH datafile,b.NAME name,b.TABLE_ID table_id,b.FLAG flags,b.N_COLS columns,count(distinct c.INDEX_ID) indexes,d.NUM_ROWS `appr.rows`,group_concat(distinct e.NAME) column_name,substring_index(group_concat(e.LEN),',',b.N_COLS-3) column_len,c.NAME index_name,c.INDEX_ID index_id,group_concat(distinct g.NAME) index_fields,d.CLUST_INDEX_SIZE,d.OTHER_INDEX_SIZE,f.PAGE_SIZE,b.FILE_FORMAT,b.ROW_FORMAT FROM INNODB_SYS_TABLES b,INNODB_SYS_DATAFILES a,INNODB_SYS_INDEXES c,INNODB_SYS_TABLESTATS d,INNODB_SYS_COLUMNS e,INNODB_SYS_TABLESPACES f,INNODB_SYS_FIELDS g WHERE a.SPACE=b.SPACE and b.TABLE_ID=c.TABLE_ID and b.TABLE_ID=d.TABLE_ID and b.TABLE_ID=e.TABLE_ID and b.SPACE=f.SPACE and c.INDEX_ID=g.INDEX_ID and b. NAME='jute/jute_vote' GROUP BY c.TABLE_ID,c.INDEX_ID;
效果如下:

*************************** 1. row *************************** datafile: ./jute/jute_vote.ibd name: jute/jute_vote table_id: 149 ###表id flags: 1 columns: 8 ###表只有5列,為什么顯示8列?因為包含了隱藏列:DB_ROW_ID(6)、DB_TRX_ID(6)、DB_ROLL_PTR(7) indexes: 1 appr.rows: 182198 ###表行的估算值 column_name: surveyId,choiceId,voteTime,userId,comment ###表列 column_len: 4,4,5,4,4 ###對應表列的長度 index_name: PRIMARY ###索引名 index_id: 324 ###索引id index_fields: surveyId,userId ###索引列 CLUST_INDEX_SIZE: 545 ###聚集索引的頁數 OTHER_INDEX_SIZE: 0 ###二級索引的頁數,表中沒有二級索引 PAGE_SIZE: 16384 ###頁的單位,16K FILE_FORMAT: Antelope ###文件格式 ROW_FORMAT: Compact ####行格式
從上面看出雖然能用information_schema中的各表展示,但還是少了一些信息,比如隱藏字段和索引包括主鍵的完整字段。
3.2:alter ignore table 語法被移除。
3.3:SHOW PROFILE 語法將被移除。通過information_schema.profiling或則performance_schema相關表來代替,如:
##老 show profile cpu,block io for query 2; ##information_schema SELECT query_id,state,DURATION,CPU_USER,CPU_SYSTEM,BLOCK_OPS_IN,BLOCK_OPS_OUT FROM INFORMATION_SCHEMA.PROFILING WHERE QUERY_ID = 36;
官方文檔已經出了說明,這里大致講下如何通過performance_schema查看,關於performance_schema的說明可以看這里 1)setup_actors:配置用戶緯度的監控,默認監控所有用戶 performance_schema 01:40:04>SELECT * FROM setup_actors; +------+------+------+---------+---------+ | HOST | USER | ROLE | ENABLED | HISTORY | +------+------+------+---------+---------+ | % | % | % | YES | YES | +------+------+------+---------+---------+ 默認是監控所有用戶的操作,會有一定性能的損耗,所以只需要開啟指定用戶的即可: performance_schema 01:40:23>UPDATE performance_schema.setup_actors SET ENABLED = 'NO', HISTORY = 'NO' WHERE HOST = '%' AND USER = '%'; Query OK, 1 row affected (0.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 performance_schema 01:40:40>SELECT * FROM setup_actors; +------+------+------+---------+---------+ | HOST | USER | ROLE | ENABLED | HISTORY | +------+------+------+---------+---------+ | % | % | % | NO | NO | +------+------+------+---------+---------+ 1 row in set (0.17 sec) ##開啟對dba用戶的監控: performance_schema 01:40:42>INSERT INTO performance_schema.setup_actors (HOST,USER,ROLE,ENABLED,HISTORY) VALUES('192.168.100.%','dba','%','YES','YES'); performance_schema 01:43:08>SELECT * FROM setup_actors; +---------------+------+------+---------+---------+ | HOST | USER | ROLE | ENABLED | HISTORY | +---------------+------+------+---------+---------+ | % | % | % | NO | NO | | 192.168.100.% | dba | % | YES | YES | +---------------+------+------+---------+---------+ 2)打開所有需要監控的選項: performance_schema 01:51:35>UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE '%statement/%'; performance_schema 01:57:01>UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME LIKE '%stage/%'; performance_schema 01:57:09>UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE '%events_statements_%'; performance_schema 01:57:27>UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE '%events_stages_%'; 3)執行需要監控的語句 select ..... 4)查看: ①老的: performance_schema 01:42:06>show profile cpu,block io for query 6; +----------------------+----------+----------+------------+--------------+---------------+ | Status | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out | +----------------------+----------+----------+------------+--------------+---------------+ | starting | 0.000178 | NULL | NULL | NULL | NULL | | checking permissions | 0.000012 | NULL | NULL | NULL | NULL | | Opening tables | 0.000050 | NULL | NULL | NULL | NULL | | init | 0.000065 | NULL | NULL | NULL | NULL | | System lock | 0.000017 | NULL | NULL | NULL | NULL | | optimizing | 0.000022 | NULL | NULL | NULL | NULL | | statistics | 0.001057 | NULL | NULL | NULL | NULL | | preparing | 0.000135 | NULL | NULL | NULL | NULL | | executing | 0.000009 | NULL | NULL | NULL | NULL | | Sending data | 1.265446 | NULL | NULL | NULL | NULL | | end | 0.000013 | NULL | NULL | NULL | NULL | | query end | 0.000393 | NULL | NULL | NULL | NULL | | removing tmp table | 0.000033 | NULL | NULL | NULL | NULL | | query end | 0.000004 | NULL | NULL | NULL | NULL | | closing tables | 0.000013 | NULL | NULL | NULL | NULL | | freeing items | 0.000056 | NULL | NULL | NULL | NULL | | logging slow query | 0.000006 | NULL | NULL | NULL | NULL | | logging slow query | 0.000202 | NULL | NULL | NULL | NULL | | cleaning up | 0.000042 | NULL | NULL | NULL | NULL | +----------------------+----------+----------+------------+--------------+---------------+ ②新的: 先找出EVENT_ID: SELECT EVENT_ID, TRUNCATE(TIMER_WAIT/1000000000000,6) as Duration, SQL_TEXT FROM performance_schema.events_statements_history_long WHERE SQL_TEXT like '%18,19,20,21%'; ... ... 通過上面找到的EVENT_ID再執行: SELECT event_name AS Stage, TRUNCATE(TIMER_WAIT/1000000000000,6) AS Duration FROM performance_schema.events_stages_history_long WHERE NESTING_EVENT_ID=231; +--------------------------------+----------+ | Stage | Duration | +--------------------------------+----------+ | stage/sql/starting | 0.000213 | | stage/sql/checking permissions | 0.000009 | | stage/sql/Opening tables | 0.000049 | | stage/sql/init | 0.000065 | | stage/sql/System lock | 0.000016 | | stage/sql/optimizing | 0.000022 | | stage/sql/statistics | 0.001060 | | stage/sql/preparing | 0.000136 | | stage/sql/executing | 0.000003 | | stage/sql/Sending data | 1.265452 | | stage/sql/end | 0.000006 | | stage/sql/query end | 0.000412 | | stage/sql/removing tmp table | 0.000011 | | stage/sql/closing tables | 0.000012 | | stage/sql/freeing items | 0.000058 | | stage/sql/logging slow query | 0.000203 | | stage/sql/cleaning up | 0.000002 | +--------------------------------+----------+
3.4:采用ALTER USER來為用戶修改密碼,不建議再使用SET PASSWORD修改密碼。
...
4,總結
在官方測試里看到,MySQL5.7在功能、性能、可用性、安全和監控上又提升了很高。如上面介紹的這些,特別是復制方面的改進:多線程、多源、GTID,半同步等都做了很大改進,以及中文分詞的支持還有sys schema上面的數據庫性能信息狀態收集等。后續會詳細介紹這幾方面的知識,加強對MySQL5.7的認識,本文只是說了一些自己比較關注的,比較詳細的請見 What’s New in MySQL 5.7,后續會持續更新說明。
5,參考文檔:
MySQL5.7中InnoDB不可不知的新特性(9月5號更新)