兩種升級方式
-
In-Place Upgrade: Involves shutting down the old MySQL version, replacing the old MySQL binaries or packages with the new ones, restarting MySQL on the existing data directory, and running mysql_upgrade.
-
Logical Upgrade: Involves exporting existing data from the old MySQL version using mysqldump, installing the new MySQL version, loading the dump file into the new MySQL version, and running mysql_upgrade.
主從的升級:
- 主從想都替換二進制安裝包為最新版本
- 停從,通過mysql_upgrade升級后,加參數 --skip-slaves-start 進行啟動
- 加參數 --skip-networking重啟主,拒絕來自應用的TCP/IP的連接,關閉binlog,執行mysql_upgrade,然后重啟
- 注意點:在關閉服務時加參數 --innodb_fast_shutdown=0 (slow shutdown),會將所有提交的事務對應的臟頁刷新到數據文件中,默認是1(fast shutdown 參考文獻:http://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_fast_shutdown)
MySQL5.6版本到5.7版本的更新包括一些不兼容的特性,在升級到5.7之前,我們需要知道這些不兼容的特性並手動更新,在其中涉及到REPAIR TABLE和USE_FRM選項的指令一定要在更新版本之前完成。
配置項更新
- --early-plugin-load
MySQL5.7.11,此參數的默認值為keyring_file(是一個二進制文件的插件),InnoDB表空間在初始化InnoDB之前需要此插件來加密,但是MySQL5.7.12及以后此參數默認為空,所以5.7.11升級到5.7.12后,如果已經在之前的版本中使用此插件對InnoDB表空間進行了加密,在開啟服務時需要指定參數 --early-plugin-load
系統表
MySQL5.6中INFORMATION_SCHEMA 中存在系統變量和狀態變量的表,show variables 和show status也是基於此庫中的表,在5.7.6時被Performance Schema也存在這四張表,show 語句開始基於Performance Schema中的表,如果show_compatibility_56參數開啟,則兼容5.6
下面的測試庫是從MySQL5.6版本中直接物理恢復到MySQL5.7環境下的
mysql> select version(); +------------+
| version() |
+------------+
| 5.7.10-log |
+------------+
1 row in set (0.00 sec)
mysql> show variables like '%56%';
ERROR 1146 (42S02): Table 'performance_schema.session_variables' doesn't exist
mysql> use performance_schema;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables like '%variable%';
Empty set (0.00 sec)
mysql> set global show_compatibility_56=ON;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%56%';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| sha256_password_proxy_users | OFF |
| show_compatibility_56 | ON |
+-----------------------------+-------+
2 rows in set (0.00 sec)
- 使用mysqld --initialize (or mysqld --initialize-insecure).初始化實例
sql mode
ONLY_FULL_GROUP_BY
, STRICT_TRANS_TABLES
, NO_ENGINE_SUBSTITUTION
, NO_ZERO_IN_DATE,
NO_ZERO_DATE
默認開啟
如以下sql在only full group by下,name非聚集字列,如果不在乎返回的address的值是否准確,則可以使用ANY_VALUE函數,這樣address字段就無需滿足full group by 出現在group by 中
SELECT name, ANY_VALUE(address), MAX(age) FROM t GROUP BY name;
時間格式不允許
'2010-00-01'
或 '2010-01-00'
, 或 '0000-00-00'
.
系統表的改變
mysql.user的password字段在5.7.6中已去除,認證信息記錄在authentication_string中,運行in-place upgrade 遷移password列值到authentication_string
如果是通過logical upgrade,需要注意:
-
You must include the
--add-drop-table
option -
You must not include the
--flush-privileges
option
server端的更改
MySQL5.7.5開始mysql_old_password 插件被移除
secure-auth 系統變量僅支持值1
--skip-secure-auth 選項被棄用
old_password系統變量的值1(將密碼hash為41位的hash值)不再被允許
old_password ()函數被移除
字段類型YEAR(2)被更改為YEAR(4)
MySQL5.7.2開始mysql.user系統表中的plugin字段不允許為空,運行mysql_upgrade會進行如下操作
UPDATE mysql.user SET plugin = 'mysql_native_password'
WHERE plugin = '' AND (Password = '' OR LENGTH(Password) = 41);
FLUSH PRIVILEGES;
需要注意sql_mode的變更,如:
mysql> SET sql_mode = ''; Query OK, 0 rows affected (0.00 sec) mysql> CREATE TABLE t (d DATE DEFAULT 0); SET sql_mode = 'NO_ZERO_DATE,STRICT_ALL_TABLES'; INSERT INTO t (d) VALUES(DEFAULT);Query OK, 0 rows affected (0.52 sec) mysql> SET sql_mode = 'NO_ZERO_DATE,STRICT_ALL_TABLES'; Query OK, 0 rows affected, 1 warning (0.00 sec) mysql> INSERT INTO t (d) VALUES(DEFAULT); ERROR 1292 (22007): Incorrect date value: '0000-00-00' for column 'd' at row 1
InnoDB變更
如果采用IN-PLACE的升級方式則需要具體關注
SQL變更
GET_LOCK()函數行為
MySQL5.7.5之前GET_LOCK()在執行第二次的額時候會釋放前面獲得的鎖,在此版本以后支持同時獲得多個鎖,如:
mysql> select version(); +------------+
| version() |
+------------+
| 5.6.33-log |
+------------+
1 row in set (0.00 sec) mysql> SELECT GET_LOCK('lock1',10); +----------------------+
| GET_LOCK('lock1',10) |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec) mysql> SELECT GET_LOCK('lock2',10); +----------------------+
| GET_LOCK('lock2',10) |
+----------------------+
| 1 |
+----------------------+
1 row in set (0.00 sec) mysql> SELECT RELEASE_LOCK('lock2'); +-----------------------+
| RELEASE_LOCK('lock2') |
+-----------------------+
| 1 |
+-----------------------+
1 row in set (0.00 sec) mysql> SELECT RELEASE_LOCK('lock1'); +-----------------------+
| RELEASE_LOCK('lock1') |
+-----------------------+
| NULL |
+-----------------------+
1 row in set (0.00 sec)
返回null說明此鎖已經被釋放了
所以依賴於釋放任何先前鎖的GET_LOCK()的行為的應用程序必須針對新行為進行修改。
derived_merge被自動開啟
5.7中優化器使用一致的機制處理from語句中的派生表和視圖是為了更好地避免不必要的物化並能夠通過條件下放產生更有效的執行計划。
但是,對於修改表的語句(例如DELETE或UPDATE),使用先前物化的派生表的合並策略可能會導致ER_UPDATE_TABLE_USED錯誤:
錯誤原因:外部查詢表和內部更改的表屬於同一張表時,如果將派生表合並到外部查詢塊就會觸發此錯誤(物化方式不會導致此錯誤,因為實際上,它將派生表轉換為單獨的表)
如:
mysql> delete from t1 where id in (select t1.id from t1 inner join t2 using(id) where t2.a1=100); ERROR 1093 (HY000): You can't specify target table 't1' for update in FROM clause
解決:關閉optimizer_switch的derived_merge選項,此選項默認是打開的
# 5.6 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,subquery_materialization_cost_based=on,use_index_extensions=on # 5.7 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
關閉derived_merge
SET optimizer_switch = 'derived_merge=off';
關鍵字和保留字
如果要引用保留字,必須使用反引號括起或跟在限定名稱的逗點后,否則報語法錯誤,如
mysql> CREATE TABLE interval (begin INT, end INT); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'interval (begin INT, end INT)' at line 1 mysql> CREATE TABLE `interval` (begin INT, end INT); Query OK, 0 rows affected (1.14 sec) mysql> CREATE TABLE test.interval (begin INT, end INT); Query OK, 0 rows affected (1.84 sec)
MySQL 5.7中有而MySQL 5.6中沒有的關鍵字和保留字;有R標記的為保留字
ACCOUNT |
ALWAYS |
CHANNEL |
COMPRESSION |
ENCRYPTION |
FILE_BLOCK_SIZE |
FILTER |
FOLLOWS |
GENERATED (R) |
GROUP_REPLICATION |
INSTANCE |
JSON |
MASTER_TLS_VERSION |
NEVER |
OPTIMIZER_COSTS (R) |
PARSE_GCOL_EXPR |
PRECEDES |
REPLICATE_DO_DB |
REPLICATE_DO_TABLE |
REPLICATE_IGNORE_DB |
REPLICATE_IGNORE_TABLE |
REPLICATE_REWRITE_DB |
REPLICATE_WILD_DO_TABLE |
REPLICATE_WILD_IGNORE_TABLE |
ROTATE |
STACKED |
STORED (R) |
VALIDATION |
VIRTUAL (R) |
WITHOUT |
XID |
表聯合查詢
使用union連接的單個查詢語句中如果有order by或limit關鍵字需要將此單個語句使用括號引起。如:
mysql> select * from t1 limit 1 union select * from t2 limit 2; ERROR 1221 (HY000): Incorrect usage of UNION and LIMIT mysql> (select * from t1 limit 1) union (select * from t2 limit 2); +------+-------+-------+ | id | name1 | name2 | +------+-------+-------+ | 1 | a1 | a2 | | 1 | 2 | 2 | | 1 | 1 | 1 | +------+-------+-------+ 3 rows in set (0.00 sec)
升級實踐(采用in-place方式)
#關閉快速關閉服務選項,防止關閉服務后有臟頁未刷進磁盤,升級后表格式變化無法進行recovery mysql -u root -p123456 -S /tmp/mysql_3306.sock -e "SET GLOBAL innodb_fast_shutdown=0" #關閉MySQL服務 mysqld_multi --defaults-file=/etc/3306.cnf --password='123456' stop 3306 #冷拷貝到部署MySQL5.7的環境 #啟動服務 mysqld_multi --defaults-file=/etc/3306.cnf --password='123456' start 3306 #更改配置文件,解決版本不兼容的參數配置 關注點為sql_mode、並行復制 #使用mysqld_upgrade 檢查並修改和MySQL5.7結構不一致的地方 mysql_upgrade -uroot -p'123456' -S /tmp/mysql_3306.sock
#重啟服務,加載變更的數據結構
注意點
mysq_upgrade 不會更改help表的內容,需要手動升級,sql文件存儲路徑在share或
share/mysql目錄下
mysql -uroot -S /tmp/mysql_3306.sock <fill_help_tables.sql
參考文獻:
http://dev.mysql.com/doc/refman/5.7/en/upgrading-from-previous-series.html