背景:
之前介紹過 MySQL 5.5 新功能、參數,現在要用MySQL5.6,所以就學習和了解下MySQL5.6新的特性和功能,盡量避免踩坑。在后續的學習過程中文章也會不定時更新。
一:參數默認值的改變。
Table Changes to Server Defaults in MySQL 5.6
其中比較重要的參數:
表空間增長大小:innodb_autoextend_increment
是否獨享表空間:innodb_file_per_table
查詢information_schema元數據庫里的表時,Innodb還會隨機提取其他數據庫每個表索引頁的部分數據:innodb_stats_on_metadata
主從復制時候的刷寫:sync_master_info、sync_relay_log、sync_relay_log_info
二 功能提升:
1)字段類型Timestamp,datetime的改變:時間類型字段,4個字節。更多的信息見官方文檔。可以為表設置多個Timestamp的特性,且datetime類型支持DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP。 參考:MySQL5.6中TIMESTAMP的變化
時間戳。范圍是'1970-01-01 00:00:00'到2037年。 TIMESTAMP列用於INSERT或UPDATE操作時記錄日期和時間。如果你不分配一個值,表中的第一個TIMESTAMP列自動設置為最近操作的日期和時間。也可以通過分配一個NULL值,將TIMESTAMP列設置為當前的日期和時間。 TIMESTAMP值返回后顯示為'YYYY-MM-DD HH:MM:SS'格式的字符串,顯示寬度固定為19個字符。如果想要獲得數字值,應在TIMESTAMP 列添加+0。
在MySQL 5.6.6之前,TIMESTAMP的默認行為:
- TIMESTAMP列如果沒有明確聲明NULL屬性,默認為NOT NULL。(而其他數據類型,如果沒有顯示聲明為NOT NULL,則允許NULL值。)設置TIMESTAMP的列值為NULL,會自動存儲為當前timestamp。
- 表中的第一個TIMESTAMP列,如果沒有聲明NULL屬性、DEFAULT或者 ON UPDATE,會自動分配 DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAMP 屬性。
- 表中第二個TIMESTAMP列,如果沒有聲明為NULL或者DEFAULT子句,默認自動分配’0000-00-00 00:00:00′。插入行時沒有指明改列的值,該列默認分配’0000-00-00 00:00:00′,且沒有警告。
Timestamp在5.5和5.6中的表現:5.6取消了一張表只有一個timestamp特性的限制。

MySQL 5.5: zjy@192.168.210.245 : test 05:58:13>create table tmp_a(id int,a timestamp,b timestamp,c timestamp)engine = innodb default charset utf8; Query OK, 0 rows affected (0.33 sec) zjy@192.168.210.245 : test 05:58:50>show create table tmp_a\G; *************************** 1. row *************************** Table: tmp_a Create Table: CREATE TABLE `tmp_a` ( `id` int(11) DEFAULT NULL, `a` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `b` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `c` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.01 sec) #已經有了一個timestamp熟悉,再創建一個。 zjy@192.168.210.245 : test 05:58:57>alter table tmp_a modify b timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; ERROR 1293 (HY000): Incorrect table definition; there can be only one TIMESTAMP column with CURRENT_TIMESTAMP in DEFAULT or ON UPDATE clause #失敗 MySQL 5.6: mysql> create table tmp_a(id int,a timestamp,b timestamp,c timestamp)engine = innodb default charset utf8; Query OK, 0 rows affected (0.02 sec) mysql> show create table tmp_a\G; *************************** 1. row *************************** Table: tmp_a Create Table: CREATE TABLE `tmp_a` ( `id` int(11) DEFAULT NULL, `a` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `b` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `c` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) #已經有了一個timestamp熟悉,再創建一個。 mysql> alter table tmp_a modify b timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table tmp_a modify c timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; Query OK, 0 rows affected (0.01 sec) Records: 0 Duplicates: 0 Warnings: 0 #成功
datetime 類型改進:支持DEFAULT CURRENT_TIMESTAMP和ON UPDATE CURRENT_TIMESTAM。

mysql> show create table tmp_time\G; *************************** 1. row *************************** Table: tmp_time Create Table: CREATE TABLE `tmp_time` ( `id` int(11) DEFAULT NULL, `day` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `cc` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1 mysql> select * from tmp_time; +------+---------------------+---------------------+ | id | day | cc | +------+---------------------+---------------------+ | 1 | 2015-08-21 15:50:12 | 2015-08-21 15:50:12 | | 2 | 2015-08-21 15:50:12 | 2015-08-21 15:50:12 | +------+---------------------+---------------------+
特別注意:在MySQL5.6里,特別為timestamp新增了一個參數:explicit_defaults_for_timestamp。該參數默認是關閉的,所以在啟動的時候,錯誤日志里面會出現:
[Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
上面5.6的測試都是在默認情況下進行的,下面開啟這個參數試試,在my.cnf里的mysqld選項組里添加:
explicit_defaults_for_timestamp = 1
測試參數:

mysql> create table tmp_a(id int,a timestamp,b timestamp,c timestamp not null,d timestamp)engine = innodb default charset utf8; Query OK, 0 rows affected (0.02 sec) mysql> show create table tmp_a\G; *************************** 1. row *************************** Table: tmp_a Create Table: CREATE TABLE `tmp_a` ( `id` int(11) DEFAULT NULL, `a` timestamp NULL DEFAULT NULL, #開啟參數之后,timestamp可以為NULL了。 `b` timestamp NULL DEFAULT NULL, `c` timestamp NOT NULL, `d` timestamp NULL DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) #開啟參數也一樣可以支持多個timestamp特性 mysql> alter table tmp_a modify a timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; Query OK, 0 rows affected (0.02 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> alter table tmp_a modify b timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; Query OK, 0 rows affected (0.03 sec) Records: 0 Duplicates: 0 Warnings: 0 mysql> insert into tmp_a(id) values(1),(2); Query OK, 2 rows affected, 1 warning (0.00 sec) Records: 2 Duplicates: 0 Warnings: 1 mysql> show warnings; +---------+------+----------------------------------------+ | Level | Code | Message | +---------+------+----------------------------------------+ | Warning | 1364 | Field 'c' doesn't have a default value | +---------+------+----------------------------------------+ 1 row in set (0.00 sec) mysql> show create table tmp_a\G; *************************** 1. row *************************** Table: tmp_a Create Table: CREATE TABLE `tmp_a` ( `id` int(11) DEFAULT NULL, `a` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `b` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `c` timestamp NOT NULL, #不為null的值且沒有默認值,寫入會報warning,用“0000-00-00 00:00:00”填充。 `d` timestamp NULL DEFAULT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8 1 row in set (0.00 sec) mysql> select * from tmp_a; +------+---------------------+---------------------+---------------------+------+ | id | a | b | c | d | +------+---------------------+---------------------+---------------------+------+ | 1 | 2015-08-20 06:21:53 | 2015-08-20 06:21:53 | 0000-00-00 00:00:00 | NULL | | 2 | 2015-08-20 06:21:53 | 2015-08-20 06:21:53 | 0000-00-00 00:00:00 | NULL | +------+---------------------+---------------------+---------------------+------+ 2 rows in set (0.01 sec)
所以MySQL5.6開啟該參數之后,timestamp字段類型的行為是:
- TIMESTAMP如果沒有顯示聲明NOT NULL,是允許NULL值的,可以直接設置改列為NULL,而沒有默認填充行為。
- TIMESTAMP不會默認分配DEFAULT CURRENT_TIMESTAMP 和 ON UPDATE CURRENT_TIMESTAMP屬性。
- 聲明為NOT NULL且沒有默認子句的TIMESTAMP列是沒有默認值的。往數據表中插入列,又沒有給TIMESTAMP列賦值時,如果是嚴格SQL模式,會拋出一個錯誤,如果嚴格SQL模式沒有啟用,該列會賦值為’0000-00-00 00:00:00′,同時出現一個警告。(這和MySQL處理其他時間類型數據一樣,如DATETIME)
2)InnoDB的增強
① 全文索引的支持(Fulltext index):MySQL5.6中內置了對Innodb的全文索引支持。5.6.4之前版本的MySQL只有MyISAM支持全文搜索。對於全文索引的概念和使用方法可以自行在網上搜索,比如MySQL必知必會第18章。
全文搜索的基礎是FULLTEXT索引,在MySQL5.6.4以后的版本中可以在Innodb,MyISAM數據表里的CHAR,VARCHAR和TEXT字段創建。 全文搜索在MyISAM表中,將忽略至少在一半數據行中出現的單詞(Innodb沒有此限制)。 全文搜索會忽略一些常見單詞,如“a”,“the”等,這些單詞被成為“停止詞”。(可以修改停止詞) FULLTEXT索引可以為一個或多個數據列創建。如果搜索涉及多個數據列,必須為多個數據索引。FULLTEXT(title,address)和FULLTEXT(address,title)效果是一樣的,搜索時使用順序也是不重要的。
mysql> show variables like '%ft%'; +---------------------------------+----------------+ | Variable_name | Value | +---------------------------------+----------------+ | ft_boolean_syntax | + -><()~*:""&| | | ft_max_word_len | 84 | | ft_min_word_len | 4 | | ft_query_expansion_limit | 20 | | ft_stopword_file | (built-in) | | innodb_ft_aux_table | | | innodb_ft_cache_size | 8000000 | | innodb_ft_enable_diag_print | OFF | | innodb_ft_enable_stopword | ON | | innodb_ft_max_token_size | 84 | | innodb_ft_min_token_size | 3 | | innodb_ft_num_word_optimize | 2000 | | innodb_ft_result_cache_limit | 2000000000 | | innodb_ft_server_stopword_table | | | innodb_ft_sort_pll_degree | 2 | | innodb_ft_total_cache_size | 640000000 | | innodb_ft_user_stopword_table | | +---------------------------------+----------------+
現在來說明下MyISAM和InnoDB對全文索引的使用。
1、索引長度的設置:
#MyISAM ft_min_word_len = 1 ft_max_word_len =84 #InnoDB innodb_ft_min_token_size= 1 innodb_ft_max_token_size=84
2、停止詞的設置(stopword):
#MyISAM 停止詞存放在文件 ft_stopword_file = /var/lib/mysql/stopword.txt #InnoDB,停止詞存放在表 innodb_ft_server_stopword_table = dbname/ft_stopwords innodb_ft_user_stopword_table = dbname/ft_stopwords
3、測試
mysql> show create table tmp_mfulltext\G; *************************** 1. row *************************** Table: tmp_mfulltext Create Table: CREATE TABLE `tmp_mfulltext` ( `id` int(11) DEFAULT NULL, `name` varchar(30) DEFAULT NULL, `content` text, FULLTEXT KEY `idx_content` (`content`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 mysql> show create table tmp_ifulltext\G; *************************** 1. row *************************** Table: tmp_ifulltext Create Table: CREATE TABLE `tmp_ifulltext` ( `id` int(11) DEFAULT NULL, `name` varchar(30) DEFAULT NULL, `content` text, FULLTEXT KEY `idx_content` (`content`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 mysql> select * from tmp_mfulltext where MATCH(content) AGAINST('Auxiliary'); #正常 +------+------+---------------------------------------------------------------------------------+ | id | name | content | +------+------+---------------------------------------------------------------------------------+ | 2 | jin | Auxiliary index table names are prefixed with FTS_ and postfixed with INDEX_*. | +------+------+---------------------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> select * from tmp_ifulltext where MATCH(content) AGAINST('Auxiliary'); #正常 +------+------+---------------------------------------------------------------------------------+ | id | name | content | +------+------+---------------------------------------------------------------------------------+ | 2 | jin | Auxiliary index table names are prefixed with FTS_ and postfixed with INDEX_*. | +------+------+---------------------------------------------------------------------------------+ 1 row in set (0.01 sec) mysql> select * from tmp_mfulltext where MATCH(content) AGAINST('when'); #搜索長度大於ft_min_word_len,但是沒有找到結果。 Empty set (0.00 sec) mysql> select * from tmp_ifulltext where MATCH(content) AGAINST('when'); #搜索長度大於innodb_ft_min_token_size,但是沒有找到結果。 Empty set (0.00 sec) 原因可能就停止詞(stopword)的問題,之前介紹過:MySQL全文檢索Stopwords的設置 手動指定停止詞后: mysql> repair table tmp_mfulltext; #需要修復下才能進行match +------------------------+--------+----------+----------+ | Table | Op | Msg_type | Msg_text | +------------------------+--------+----------+----------+ | dba_test.tmp_mfulltext | repair | status | OK | +------------------------+--------+----------+----------+ 1 row in set (0.00 sec) mysql> select count(*) from tmp_mfulltext where MATCH(content) AGAINST('when');#停止詞的問題,指定好之后有結果。 +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec) mysql> select * from tmp_ifulltext where MATCH(content) AGAINST('when'); #沒有結果,這里說明Innodb的全部文索停止詞和MyISAM的不一樣。 Empty set (0.01 sec)
關於InnoDB fulltext的停止詞相關的設置,默認的停止詞表是:
mysql> select * from INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD; 36 rows in set (0.00 sec)
手動設置停止表:
#因為InnoDB的停止詞是以表形式存的,先建立停止詞表:停止詞表必須是InnoDB表,只包含一個VARCHAR類型名為VALUE的列 mysql> create table innodb_ft_stopwords(value varchar(30))ENGINE=INNODB; #結構和INFORMATION_SCHEMA.INNODB_FT_DEFAULT_STOPWORD一樣 Query OK, 0 rows affected (0.01 sec) #插入停止詞: mysql> INSERT INTO innodb_ft_stopwords(value) VALUES('a'); Query OK, 1 row affected (0.00 sec) #加載停止詞表,注意格式 mysql> SET GLOBAL innodb_ft_server_stopword_table = 'dba_test/innodb_ft_stopwords'; Query OK, 0 rows affected (0.00 sec) mysql> SET GLOBAL innodb_ft_user_stopword_table = 'dba_test/innodb_ft_stopwords'; Query OK, 0 rows affected (0.00 sec) #因為fulltext的創建是在加載停止詞之后的,之前建立的fulltext找不到結果。 mysql> select * from tmp_ifulltext where MATCH(content) AGAINST('when'); Empty set (0.00 sec) #optimize table 之后可以 mysql> optimize table tmp_ifulltext; +------------------------+----------+----------+-------------------------------------------------------------------+ | Table | Op | Msg_type | Msg_text | +------------------------+----------+----------+-------------------------------------------------------------------+ | dba_test.tmp_ifulltext | optimize | note | Table does not support optimize, doing recreate + analyze instead | | dba_test.tmp_ifulltext | optimize | status | OK | +------------------------+----------+----------+-------------------------------------------------------------------+ 2 rows in set (0.07 sec) #搜索出結果 mysql> select count(*) from tmp_ifulltext where MATCH(content) AGAINST('when'); +----------+ | count(*) | +----------+ | 1 | +----------+ 1 row in set (0.00 sec)
這里需要注意的是在創建全文索引之前就應先設置好停止詞表,不然就得執行optimize。停止詞表確定之后,請加入到配置文件中:
innodb_ft_server_stopword_table = dba_test/innodb_ft_stopwords innodb_ft_user_stopword_table = dba_test/innodb_ft_stopwords
Tips:
· 全文搜索在MyISAM表中,將忽略至少在一半數據行中出現的單詞,而Innodb沒有此限制:
mysql> select count(*) from tmp_ifulltext where MATCH(content) AGAINST('the'); +----------+ | count(*) | +----------+ | 6 | +----------+ 1 row in set (0.00 sec) mysql> select count(*) from tmp_mfulltext where MATCH(content) AGAINST('the'); +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
關於更多的信息請查看官方文檔和MySQL5.6 InnoDB FULLTEXTIndexes研究測試。
#生成測試數據 mysql> SHOW VARIABLES LIKE 'innodb_file_per_table'; +-----------------------+-------+ | Variable_name | Value | +-----------------------+-------+ | innodb_file_per_table | ON | +-----------------------+-------+ 1 row in set (0.00 sec) mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY) DATA DIRECTORY = '/tmp/mysqldata/'; #會在該目錄下再生成一個以數據庫命名的目錄 Query OK, 0 rows affected (0.02 sec) mysql> insert into t1 values(1),(2),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 #查看物理文件 root@zjy:~# ls -lh /var/lib/mysql3/dba_test/ -rw-rw---- 1 mysql mysql 8.4K 8月 21 00:44 t1.frm -rw-rw---- 1 mysql mysql 30 8月 21 00:44 t1.isl root@zjy:~# ls -lh /tmp/mysqldata/dba_test/ -rw-rw---- 1 mysql mysql 96K 8月 21 00:45 t1.ibd
上面被看到數據文件.ibd和表結構定義文件.frm已分離。注意:表空間分離表會產生一個
的連接。table_name
.isl
③ 導入和導出表空間:復制文件比mysqldump&restore快
#生成測試數據 server1: mysql> CREATE TABLE test (c1 INT PRIMARY KEY)engine = innodb; Query OK, 0 rows affected (0.02 sec) mysql> insert into test values(1),(2),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 server2: mysql> CREATE TABLE test (c1 INT PRIMARY KEY)engine = innodb; Query OK, 0 rows affected (0.02 sec) mysql> insert into test values(1),(3); Query OK, 3 rows affected (0.00 sec) Records: 3 Duplicates: 0 Warnings: 0 #接着把server2的表空間給discard掉: root@zjy:/var/lib/mysql/dba_test# ls -lh test.* -rw-rw---- 1 mysql mysql 8.4K 8月 21 01:37 test.frm -rw-rw---- 1 mysql mysql 96K 8月 21 01:37 test.ibd #discard 表空間 mysql> ALTER TABLE test DISCARD TABLESPACE; Query OK, 0 rows affected (0.00 sec) #表空間沒了 root@zjy:/var/lib/mysql/dba_test# ls -lh test.* -rw-rw---- 1 mysql mysql 8.4K 8月 21 01:37 test.frm #然后把server1的表空間復制給server2: mysql> FLUSH TABLES test FOR EXPORT; #必須要生成cfg metadata文件 Query OK, 0 rows affected (0.00 sec) root@zjy:/var/lib/mysql3/dba_test# ls -lh test.* -rw-rw---- 1 mysql mysql 330 8月 21 01:40 test.cfg -rw-rw---- 1 mysql mysql 8.4K 8月 21 01:36 test.frm -rw-rw---- 1 mysql mysql 96K 8月 21 01:36 test.ibd #需要把ibd和cfg文件復制到server2上 root@zjy:/var/lib/mysql3/dba_test# cp test.cfg /var/lib/mysql/dba_test/ root@zjy:/var/lib/mysql3/dba_test# cp test.ibd /var/lib/mysql/dba_test/ #最后修改server2文件權限和import表空間: root@zjy:/var/lib/mysql/dba_test# chown -R mysql.mysql * mysql> ALTER TABLE test IMPORT TABLESPACE; Query OK, 0 rows affected (0.02 sec) #值從1,3變成了1,2,3。數據已成功遷移過來 mysql> select * from test; +----+ | c1 | +----+ | 1 | | 2 | | 3 | +----+ #最后解鎖server1上的鎖: mysql> unlock tables;
3)innodb內部性能增強:
① 將flushing操作獨立出主線程,減少核心互斥鎖。可設置多個清除線程,減少內存資源爭奪。回收UNDO,通過innodb_purge_threads 來開啟,在5.5中只能也只有1可以設置。5.6可以設置大於1。刷寫臟頁,5.6之后支持,Page cleaner線程,從Master Thread獨立出來,減輕了Master Thread 的工作和對用戶查詢的阻塞。進一步提高Innodb 存儲引擎的性能和並發。
② 檢測死鎖算法增強。在非遞歸情況下死鎖檢測:死鎖信息不止可以通過show engine innodb status一種方法查看,還可以記錄到 error 日志,並且可以查看歷史的死鎖,方便分析。開啟參數:innodb_print_all_deadlocks,默認關閉。
如果一台高負荷的機器重啟后,buffer pool中的熱數據被丟失,此時就會重新從磁盤加載到Buffer_Pool緩沖池里,這樣當高峰期間,性能就會變得很差,連接數就會很高,應用的性能也受到影響。MySQL5.6里,一個新特性避免的這種問題的出現,在配置文件里添加:
#在關閉時把熱數據dump到本地磁盤 #5.7.7默認開啟 innodb_buffer_pool_dump_at_shutdown = 1 #在啟動時把熱數據加載到內存 #5.7.7默認開啟 innodb_buffer_pool_load_at_startup = 1 #采用手工方式把熱數據dump到本地磁盤 innodb_buffer_pool_dump_now = 1 #采用手工方式把熱數據加載到內存 innodb_buffer_pool_load_now = 1
參數:innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup 是數據庫關閉開啟時候起作用的:
當數據庫正常關閉/重啟之后,錯誤日志里面會記錄:會生一個ib_buffer_pool的文件,這個文件名字有參數 innodb_buffer_pool_filename 控制。
2015-08-21 19:55:07 7fe34dff8700 InnoDB: Dumping buffer pool(s) to .//ib_buffer_pool 2015-08-21 19:55:07 7fe34dff8700 InnoDB: Buffer pool(s) dump completed at 150821 19:55:07 2015-08-21 19:55:08 31943 [Note] InnoDB: Shutdown completed; log sequence number 3052155687
當數據庫重新起來之后,錯誤日志里會記錄:
2015-08-21 19:55:59 7f5eaf7f8700 InnoDB: Buffer pool(s) load completed at 150821 19:55:59
參數:innodb_buffer_pool_dump_now和innodb_buffer_pool_load_now 是需要手動執行的:
當數據庫正在運行時執行:
查看BP里dump文件的時間: root@zjy:/var/lib/mysql# ls -lh ib_buffer_pool -rw-rw---- 1 mysql mysql 52K 8月 25 18:30 ib_buffer_pool 執行: mysql> SET GLOBAL innodb_buffer_pool_dump_now=ON; Query OK, 0 rows affected (0.01 sec) 查看BP里dump文件的時間:時間變成當前時間,說明dump成功。 root@zjy:/var/lib/mysql# ls -lh ib_buffer_pool -rw-rw---- 1 mysql mysql 52K 8月 25 19:02 ib_buffer_pool load dump文件到BP: mysql> SET GLOBAL innodb_buffer_pool_load_now=ON; Query OK, 0 rows affected (0.01 sec)
顯示BP導入、導出的狀態:重啟數據庫雖然在日志文件里面可以查看到dump和load的一些信息,但在運行時,也可以監控是否成功:
#監控查看BP dump的狀態:Innodb_buffer_pool_dump_status,手動執行BP的dump動作 mysql> select now();SET GLOBAL innodb_buffer_pool_dump_now=ON;SHOW STATUS LIKE 'Innodb_buffer_pool_dump_status'; +---------------------+ | now() | +---------------------+ | 2015-08-25 19:08:49 | +---------------------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) +--------------------------------+--------------------------------------------------+ | Variable_name | Value | +--------------------------------+--------------------------------------------------+ | Innodb_buffer_pool_dump_status | Buffer pool(s) dump completed at 150825 19:08:49 | #和dump執行的時間一致,說明dump成功,是上一個dump的結果 +--------------------------------+--------------------------------------------------+ 1 row in set (0.00 sec) #監控查看BP load的狀態:Innodb_buffer_pool_load_status,手動執行load dump文件動作 mysql> select now();SET GLOBAL innodb_buffer_pool_load_now=ON;SHOW STATUS LIKE 'Innodb_buffer_pool_load_status'; +---------------------+ | now() | +---------------------+ | 2015-08-25 19:10:21 | +---------------------+ 1 row in set (0.00 sec) Query OK, 0 rows affected (0.00 sec) +--------------------------------+--------------------------------------------------+ | Variable_name | Value | +--------------------------------+--------------------------------------------------+ | Innodb_buffer_pool_load_status | Buffer pool(s) load completed at 150825 19:10:21 | #和load執行的時間一致,說明load成功,是還原上一個dump文件 +--------------------------------+--------------------------------------------------+ 1 row in set (0.00 sec)
通過show status 查看之外,還可以通過在information_schema里查看:
dump: SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'INNODB_BUFFER_POOL_DUMP_STATUS'; load: SELECT variable_value FROM information_schema.global_status WHERE variable_name = 'INNODB_BUFFER_POOL_LOAD_STATUS';
此外,也可以中止BP的load,參數:innodb_buffer_pool_load_abort,中止緩沖池加載操作。
#在MySQL里運行: mysql> set global innodb_buffer_pool_load_abort = on; Query OK, 0 rows affected (0.00 sec) #也可以在配置文件里添加: innodb_buffer_pool_load_abort = 1
另外,innodb_buffer_pool_dump_pct控制備份buffer pool的百分比,5.7中支持。5.6默認dump所有的Buffer pool。
總之,引入看BP的自動預熱解決了數據庫維護重啟的時候導致性能變差的問題。
注意:只有在正常關閉MySQL服務,或者pkill mysql時,會把熱數據dump到內存。機器宕機或者pkill -9 mysql,是不會dump。
④ 新增參數innodb_page_size設置頁大小。指定在一個MySQL實例的所有InnoDB表空間的頁大小。該值是在創建實例時設置的,並且在隨后的情況中保持不變。你可以使用16K指定頁面大小(默認),8K,或4K。或者,您可以指定字節的頁大小(4096,8192,16384)。16K頁面適合大部分場景,特別是表掃描、DML操作和批量更新;較小的頁面可能更是適合OLTP和SSD存儲設備。
⑤ undo log可獨立出系統表空間,原來存在ibd系統表空間里。undo log分離到獨立的表空間,並放到單獨的文件目錄下。對於並發寫入型負載,我們可以把undo文件部署到單獨的高速存儲設備上。缺點就是不能進行回收(收縮)空間大小。直到MySQL5.7 ,才支持在線收縮。由參數innodb_undo_tablespaces和innodb_undo_directory控制:需要在數據庫實例建立之后就開啟,否則會初始化innodb 失敗,開啟之后不能修改。具體信息可以看這篇文章
在配置文件里設置: innodb_undo_directory = /var/lib/mysql4/undolog/ #undo log 存放的目錄 innodb_undo_tablespaces = 10 #默認表空間的個數,大小默認是10M,以undo001形式存在,值為0則表示使用系統表空間。
另外一個參數是:inodb_undo_logs:代替了先前的參數innodb_rollback_segments,控制着回滾段的數量(注意范圍是0-128) 默認不指定的時候是128個回 滾段。(注意要想增加回滾段的時候必須要重啟mysql)。
要是開啟的時候遇到innodb數據初始化失敗:Plugin 'InnoDB' init function returned error。則需要先把數據dump出來,刪除掉ibdata、ib_logfile等文件,再開啟。
⑥ 優化器統計持續化:重啟不丟失。緩沖池flush算法增強、支持read-only事務、redo log最大增至512G。
⑦ 支持使用enosql api訪問innodb表、redo log最大增至512G、INFORMATION_SCHEMA新增相關字典表若干。 InnoDB更多的改進:http://dev.mysql.com/doc/refman/5.6/en/optimizing-innodb.html
4)復制、日志功能增強
① binlog_row_image 參數控制Row模式下的binlog記錄格式。在MySQL5.6只之前,Row模式記錄所有列,即使是修改一個列。這樣就存在一個問題,如果表中包含很多的大字段,表的單行長度就會非常長,這樣每次update就會導致大量的 binlog空間生成,具體的可以看這里。該參數可以控制ROW下的記錄格式,可以動態修改,3個值可以設置:
full:默認行為,記錄所有的列,和MySQL5.6之前的版本一樣。 minimal:記錄被修改的列,其他未修改的列不記錄。 noblob :記錄所有的列,除text、blob列外。
測試:
BINLOG: binlog_format = ROW binlog_row_image = minimal SQL: update doctors set username ='XXXYYYZZZ',cellphone='110110110110',modifyTime=now() where id = 101; LOG: #記錄了紙杯修改的三個列 ### UPDATE `dba_test`.`doctors` ### WHERE ### @1=101 /* INT meta=0 nullable=0 is_null=0 */ ### SET ### @4='XXXYYYZZZ' /* VARSTRING(192) meta=192 nullable=0 is_null=0 */ ### @13='110110110110' /* VARSTRING(48) meta=48 nullable=1 is_null=0 */ ### @19='2015-08-28 11:20:09' /* DATETIME(0) meta=0 nullable=1 is_null=0 */ 其他2個可以自行測試。
所以在5.6中binlog_row_image設置為minimal,這樣就可以大大減小了binlog的長度,進而減少了空間的使用。但不能通過腳本實現回滾了。
② log_bin_basename、log_bin_index
、relay_log_basename,顯示binlog和relay log 日志名字,直接用log_bin指定。5.5和5.6的區別如下:

mysql> show global variables like 'log%'; +---------------------------------+-------------------------------+ | Variable_name | Value | +---------------------------------+-------------------------------+ | log_bin | ON | #看不到,需要到配置文件、目錄里找。 +---------------------------------+-------------------------------+ mysql> show global variables like 'log%'; +----------------------------------------+------------------------------------+ | Variable_name | Value | +----------------------------------------+------------------------------------+ | log_bin | ON | | log_bin_basename | /var/lib/mysql/mysql-bin_06 | #可以看到名稱和路徑,即log_bin配置。 | log_bin_index | /var/lib/mysql/mysqld-bin_06.index | #索引文件 +----------------------------------------+------------------------------------+ zjy@192.168.100.2 : analyze_data 05:12:57>show variables like 'relay%'; +-----------------------+-----------------------+ | Variable_name | Value | +-----------------------+-----------------------+ | relay_log | mysqld-relay-bin-3306 | #同上 | relay_log_index | | +-----------------------+-----------------------+ mysql> show global variables like 'relay%'; +---------------------------+-------------------------------------------+ | Variable_name | Value | +---------------------------+-------------------------------------------+ | relay_log | mysqld-relay-bin3306 | | relay_log_basename | /var/lib/mysql/mysqld-relay-bin3306 | #同上 | relay_log_index | /var/lib/mysql/mysqld-relay-bin3306.index | +---------------------------+-------------------------------------------+
③ master.info和relay-log.info支持存儲在表中,通過參數:master-info-repository、relay-log-info-repository控制,默認是存文件(file):
mysql> show variables like '%info%'; +---------------------------+----------------+ | Variable_name | Value | +---------------------------+----------------+ | master_info_repository | FILE | | relay_log_info_repository | FILE | +---------------------------+----------------+ 在配置文件里添加: master_info_repository = table relay_log_info_repository = table mysql> show variables like '%info%'; +---------------------------+----------------+ | Variable_name | Value | +---------------------------+----------------+ | master_info_repository | TABLE | | relay_log_info_repository | TABLE | +---------------------------+----------------+
這里需要知道的是,設置成Table之后,表存儲在mysql數據庫中。對應的表名是:slave_master_info,slave_relay_log_info。
④ mysqlbinlog命令支持binlog備份。在5.6之前mysqlbinlog只是讀取binglog日志,並解析出一個文本格式的內容。5.6增加了一個--raw參數,作用是讀取binglog日志,並重新生成binlog格式的文件。其原理就是開啟一個IO(dump)線程來拉取binlog日志,下面通過使用方法介紹下:
A Server: mysql> SHOW BINARY LOGS; +---------------------+-----------+ | Log_name | File_size | +---------------------+-----------+ | mysql-bin_06.000001 | 174 | | mysql-bin_06.000002 | 201 | | mysql-bin_06.000003 | 201 | | mysql-bin_06.000004 | 1864 | | mysql-bin_06.000005 | 1420 | | mysql-bin_06.000006 | 191 | +---------------------+-----------+ B Server: 備份1~6的二進制日志: 1:備份001和002的二進制日志,再備份其他的就繼續指定binlog name mysqlbinlog --read-from-remote-server --user=zjy --password=123456 --host=127.0.0.1 --raw mysql-bin_06.000001 mysql-bin_06.000002 2:從000001開始備份所有的二進制日志: mysqlbinlog --read-from-remote-server --user=zjy --password=123456 --host=127.0.0.1 --raw --to-last-log mysql-bin_06.000001 3:從000001開始備份所有的二進制日志,命令行不退出,一直監控着日志的輪巡,一有新的event就馬上備份。 mysqlbinlog --read-from-remote-server --user=zjy --password=123456 --host=127.0.0.1 --raw --stop-never mysql-bin_06.000001
4:--stop-never-slave-server-id=
。id
,指定binlog server的id,開啟多個binlog server,可以用不同的server-id,默認是65535
mysqlbinlog --read-from-remote-server--stop-never-slave-server-id=1
--user=zjy --password=123456 --host=127.0.0.1 --raw --stop-never mysql-bin_06.000001
5:--result-file,指定一個文件目錄。
mysqlbinlog --read-from-remote-server --user=zjy --password=123456 --host=127.0.0.1 --raw --stop-never mysql-bin_06.000001 --result-file=/home/zhoujy/
在Server B里面看到從Server A上備份過來的binlog日志,具體的使用方法請見官方文檔和這篇說明。
⑤ 支持多線程復制:slave_parallel_workers:多線程復制是基於庫的,一個線程也只針對一個數據庫。注意:當開啟多線程復制后,需要關閉slave_transaction_retries,設置其為0,否則會在start/stop slave中遇到:
slave_transaction_retries is not supported in multi-threaded slave mode. In the event of a transient failure, the slave will not retry the transaction and will stop.
5.6以前的從服務器,有一個io線程負責接收binary log,還有一個sql線程負責執行binary log中的sql語句。如果主服務器的數據更新相當頻繁,而從服務器由於某些原因跟不上,會導致從服務器落后比較長的時間。5.6之后采用多個sql線程,每個sql線程處理不同的database,提高了並發性能,即使某database的某條語句暫時卡住,也不會影響到后續對其它的database進行操作。
要把多線程改成單線程,即 slave_parallel_workers 從非0改成0,則執行:
zjy@192.168.110.xx : (none) 02:28:49>stop slave; Query OK, 0 rows affected (0.30 sec) zjy@192.168.110.xx : (none) 02:28:55>START SLAVE UNTIL SQL_AFTER_MTS_GAPS; Query OK, 0 rows affected (0.02 sec) zjy@192.168.110.xx : (none) 02:29:07>SET @@GLOBAL.slave_parallel_workers = 0; Query OK, 0 rows affected (0.01 sec) zjy@192.168.110.xx : (none) 02:29:29>START SLAVE SQL_THREAD; Query OK, 0 rows affected (0.11 sec)
查看,只有一個線程:
更多的信息見官方文檔。
⑥ 支持延遲復制,MASTER_DELAY。在change的時候指定,單位是秒。
CHANGE master TO MASTER_DELAY=600;
mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Master_Host: 127.0.0.1 Master_User: rep Master_Port: 3306 Connect_Retry: 60 Master_Log_File: mysql-bin3306.000006 Read_Master_Log_Pos: 23940536 ... ... SQL_Delay: 0 ...
⑦ 新增GTID復制,詳細信息見:MySQL5.6 新特性之GTID。
⑧ binlog支持crash-safe:
binlog_checksum=CRC32 :事件寫入二進制進行校驗,默認CRC32。
master_verify_checksum =1 :檢查二進制日志,bin log。默認禁止。
slave_sql_verify_checksum =1 :檢查中繼日志,relay log。默認禁止。
⑨ thread_pool_size 的引入:在引入線程池之前,MySQL支持的線程處理方式(thread_handling參數控制)有no-threads和one-thread-per-connection兩種方式,no-threads方式是指任一時刻最多只有一個連接可以連接到server,一般用於實驗性質。 one-thread-per-connection是指針對每個連接創建一個線程來處理這個連接的所有請求,直到連接斷開,線程 結束。是thread_handling的默認方式。one-thread-per-connection存在的問題就是需要為每個連接創建一個新的thread,當並發連接數達到一定程度,性能會有明顯下降,因為過多的線程會導致頻繁的上下文切換,CPU cache命中率降低和鎖的競爭 更加激烈。解決one-thread-per-connection的方法就是降低線程數,這樣就需要多個連接共用線程,這便引入了線程池的概念。
thread_handling = pool-of-threads
5)優化器增強 :可以看這里
mysql >show variables like 'optimizer_switch'\G; *************************** 1. row *************************** Variable_name: optimizer_switch Value: 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,subquery_materialization_cost_based=on,use_index_extensions=on
① MRR優化(Multi-Range Read):mrr=on,mrr_cost_based=on 。MRR的優化用於range, ref, eq_ref, and Batched Key Access訪問方法
Multi-Range Read 多范圍讀(MRR) 它的作用是基於輔助/第二索引的查詢,減少隨機IO,並且將隨機IO轉化為順序IO,提高查詢效率。在沒有MRR之前(MySQL5.6之前),先根據where條件中的輔助索引獲取輔助索引與主鍵的集合,再通過主鍵來獲取對應的值。輔助索引獲取的主鍵來訪問表中的數據會導致隨機的IO(輔助索引的存儲順序並非與主鍵的順序一致),不同主鍵不在同一個page里面時必然導致多次IO 和隨機讀。使用MRR優化(MySQL5.6之后),先根據where條件中的輔助索引獲取輔助索引與主鍵的集合,再將結果集放在buffer里面(read_rnd_buffer_size 大小直到buffer滿了),然后對結果集按照pk_column排序,得到有序的結果集rest_sort。最后利用已經排序過的結果集,訪問表中的數據,此時是順序IO。即MySQL 將根據輔助索引獲取的結果集根據主鍵進行排序,將無序化為有序,可以用主鍵順序訪問基表,將隨機讀轉化為順序讀,多頁數據記錄可一次性讀入或根據此次的主鍵范圍分次讀入,以減少IO操作,提高查詢效率。
具體參考:http://blog.itpub.net/22664653/viewspace-1673682/
② ICP優化(Index Condition Pushdown):index_condition_pushdown=on。ICP的優化用於range, ref, eq_ref, and ref_or_null訪問方法
Index Condition Pushdown (ICP)是MySQL用索引去表里取數據的一種優化。禁用ICP(MySQL5.6之前),引擎層會利用索引在基表中尋找數據行,然后返回給MySQL Server層,再去為這些數據行進行WHERE后的條件的過濾(回表)。啟用ICP(MySQL5.6之后),如果部分WHERE條件能使用索引中的字段,MySQL會把這部分下推到引擎層。存儲引擎通過使用索引把滿足的行從表中讀取出。ICP減少了引擎層訪問基表的次數和MySQL Server 訪問存儲引擎的次數。總之是 ICP的優化在引擎層就能夠過濾掉大量的數據,減少io次數,提高查詢語句性能。
具體參考:http://blog.itpub.net/22664653/viewspace-1678779/和http://www.cnblogs.com/zhoujinyi/archive/2013/04/16/3016223.html
③ Limit優化 :
SELECT … FROM single_table … ORDER BY non_index_column [DESC] LIMIT N [OFFSET M];
當有足夠的內存(sort_buffer_size)來存儲N+M行記錄時, 會在內存中創建一個優先隊列來存儲數據,這意味着一次掃描表就可以獲得想要的數據,避免了創建/寫入臨時表及歸並排序操作(之前版本的邏輯)
大概邏輯為:
1.掃描表,將數據有序的插入到優先隊列中,如果隊列滿了,則按順序移除多余的記錄
2.返回隊列中的N行記錄,如果指定了OFFSET M,則忽略開始的M條記錄,然后返回剩下的N條
④ Index Extension優化 :use_index_extensions=on。
InnoDB的二級索引都包含主鍵信息,隱性的包含了主鍵列,可以通過在二級索引上添加主鍵列來查看(顯性的添加主鍵列到二級索引,索引大小不變)。在MySQL5.6之前,MySQL優化器選擇索引時不會考慮到這些隱性的主鍵列,一般都需要手動添加。而在MySQL5.6之后,優化器選擇時,會考慮到二級索引上的primary key。
⑤ BKA優化(Batched Key Access):mrr=on,mrr_cost_based=off,batched_key_access=on.
提高表join性能的算法,在介紹BKA之前,先了解下Join表的優化歷史:
Nested Loop Join算法:將驅動表/外部表的結果集作為循環基礎數據,然后循環該結果集,每次獲取一條數據作為下一個表的過濾條件查詢數據,然后合並結果,獲取結果集返回給客戶端。Nested-Loop一次只將一行傳入內層循環, 所以外層循環(的結果集)有多少行, 內存循環便要執行多少次,效率非常差。
Block Nested-Loop Join算法:將外層循環的行/結果集存入join buffer, 內層循環的每一行與整個buffer中的記錄做比較,從而減少內層循環的次數。主要用於當被join的表上無索引。
Batched Key Access算法:當被join的表能夠使用索引時,就先排好順序,然后再去檢索被join的表。對這些行按照索引字段進行排序,因此減少了隨機IO。如果被Join的表上沒有索引,則使用老版本的BNL策略(BLOCK Nested-loop)。BKA默認是關閉的,要使用BKA,必須調整系統參數optimizer_switch的值,batched_key_access設置為on,因為BKA使用了MRR,因此也要打開MRR,但是基於成本優化MRR算法不是特別准確官方文檔推薦關閉mrr_cost_based,將其設置為off。
set optimizer_switch='mrr=on,mrr_cost_based=off,batched_key_access=on'
具體參考:http://blog.itpub.net/22664653/viewspace-1715511/
⑥ explain支持對insert、delete、update、replace語句,並且支持json格式的 optimizer_trace。
mysql>set optimizer_trace='enabled=on'; mysql>select * from information_schema.optimizer_trace\G;
具體參考:http://hidba.ga/2014/09/24/in-and-range/
⑦ 子查詢優化 :subquery_materialization_cost_based
更多的信息見:http://dev.mysql.com/doc/refman/5.6/en/index.html
⑧ in、range優化: eq_range_index_dive_limit
在較多等值查詢(例如多值的IN查詢)情景中,預估可能會掃描的記錄數,從而選擇相對更合適的索引。用於優化in(),以確認是否直接使用索引統計,在where條件中列的等值條件個數小於這個值時,使用index dive來估算行數,否則使用index statistics來估算;設置為0則禁用index statistics, index dive更准確但效率低
更多的信息見:http://myrock.github.io/2014/09/24/in-and-range/
...
6)參數說明 : http://dev.mysql.com/doc/refman/5.6/en/innodb-parameters.html
5.6的新參數會在另一篇文章說明。
...
三 總結
上面大概介紹了5.6的一些新的特性,后續會不定時更新,盡量避免5.6的一些問題。
四 參考文章
http://dev.mysql.com/doc/refman/5.6/en/index.html
http://www.ttlsa.com/mysql/summary-of-the-new-features-of-mysql5_6/