java有趣的技术分享ppt_技术分享 | 关于 MySQL Online DDL 有趣的验证
作者:胡存存
愛可生 DBA 團隊成員,主要負責 MySQL 故障處理和 SQL 審核優化。對技術執著,為客戶負責。
本文來源:原創投稿
*愛可生開源社區出品,原創內容未經授權不得隨意使用,轉載請聯系小編并注明來源。
MySQL 在 5.6 引入 Online DDL 之后,在 5.7 和 8.0 版本又對這一功能進行了大幅的優化。尤其是在 8.0 之后,已經實現了列的秒加。在 5.7 中有些 DDL 操作也實現了秒修改,比如修改字段的默認值,修改列名,但是這些在工作中不是很常見,今天我們討論下能夠實現秒修改的一種特殊情況,稍不注意可能就掉進坑中。
在日常工作中,我們用的最多的數據類型就是 int(bigint) 類型和 varchar 類型。在這兩個數據類型中,其中 int 類型只要不超過數據類型允許的最大值,int(N) 類型的中的 N 不會影響輸入的字節數,但是 varchar(N) 數據類型中的 N,當輸入的字符數超過 N 時,就不允許輸入,這時就需要擴容,這也是我們經常會遇到的一種數據變更。當出現這種需求,我們是采用 MySQL 的 Online DDL 直接修改還是用第三方的工具呢。我們先看下官網關于擴 varchar 類型的描述:參考文章:https://dev.mysql.com/doc/refman/5.7/en/innodb-online-ddl-operations.html通過上圖可以發現,Extending VARCHAR column size 在 In Place 是 yes,Rebuilds Table 是 no,也就是在修改是在修改時不用 copy 表,那是不是這樣,我們驗證下。我們用 sysbench 準備 4 張表,單表 500w,用 4 線程壓數據庫,模擬業務量(數據庫版本:5.7.29)。表結構為:root@localhost[sbtest]> show create table sbtest1\G*************************** 1. row *************************** Table: sbtest1Create Table: CREATE TABLE `sbtest1` ( `id` int(11) NOT NULL AUTO_INCREMENT, `k` int(11) NOT NULL DEFAULT '0', `c` char(120) NOT NULL DEFAULT '', `pad` char(60) NOT NULL DEFAULT '', `c1` varchar(10) NOT NULL DEFAULT 'cc', PRIMARY KEY (`id`), KEY `k_1` (`k`)) ENGINE=InnoDB AUTO_INCREMENT=5000001 DEFAULT CHARSET=utf8mb41 row in set (0.00 sec)此時啟動 sysbench,看到此時的 qps 在 5000 左右,此時將 c1 列從 varchar(10) 擴到 varchar(50),我們發現秒修改,直接毫無感知,與官網上說的一樣。這時候字節長度又不夠了,我們需要擴到 100,這時候,我們發現了異常,這次不再是秒修改,而是停在了那,現在是不是覺得有點不妙,這時候,再看我們的壓測日志,這時候業務完全被阻塞了,這時候,腦瓜子是不是嗡嗡的了。。。到底怎么回事,我們看下官網怎么說:Extending?VARCHAR?column sizeALTER TABLE tbl_name CHANGE COLUMN c1 c1 VARCHAR(255), ALGORITHM=INPLACE, LOCK=NONE;The number of length bytes required by a?VARCHAR?column must remain the same. For?VARCHAR?columns of 0 to 255 bytes in size, one length byte is required to encode the value. For?VARCHAR?columns of 256 bytes in size or more, two length bytes are required. As a result, in-place?ALTER TABLE?only supports increasing?VARCHAR?column size from 0 to 255 bytes, or from 256 bytes to a greater size. In-place?ALTER TABLE?does not support increasing the size of a?VARCHAR?column from less than 256 bytes to a size equal to or greater than 256 bytes. In this case, the number of required length bytes changes from 1 to 2, which is only supported by a table copy (ALGORITHM=COPY). For example, attempting to change?VARCHAR?column size for a single byte character set from VARCHAR(255) to VARCHAR(256) using in-place?ALTER TABLE?returns this error:ALTER TABLE tbl_name ALGORITHM=INPLACE, CHANGE COLUMN c1 c1 VARCHAR(256);ERROR 0A000: ALGORITHM=INPLACE is not supported. Reason: Cannot change column type INPLACE. Try ALGORITHM=COPY.由上文可知,在 varchar 類型中,當大小在 0 到 255 字節時,需要 1 個字節編碼,當大于 255 時,需要 2 個字節編碼。所以在相同字節編碼的長度內變更,可以用 inplace 的方式,當字節編碼長度變更時,只能用 copy 模式,這種情況下會完全阻塞表的讀寫。這樣我們大約明白怎么回事了,但細想,又在哪里有問題,剛才我們在變更時,從 varchar(50) 到 varchar(100),還沒到 255,為什么會出現 copy 表的現象?其實這里我們注意的是 varchar(N) 中,N 表示的是字符,而不是字節。所以,所以根據字符集不一樣,每個字符需要的字節也不一樣,所以在擴 varchar 長度時,N 的范圍也不一樣。在 utf8 字符集中,一個字符需要三個字節,所以,當 N<=85 時,需要一個 1 個字節編碼,當 N>85 時,需要兩個。所以我們來驗證下,這里我們建 3 張表:我們在表中插入幾條數據,如下:我們先修改 t1(字符集為 utf8)表,如下:如上圖,我們看到,當字段擴到 85 時,影響的行數還為 0,當擴到 86 之后,影響行數變為 3,也就是說字符長度從 85 擴到 86,此時發生了全表的 copy。當大于 86 之后,我們怎么擴,也不會發生表的 copy 操作了。我們再來驗證 utf8mb4:因為 utf8mb4 字符集一個字節需要 4 個字符,所以,當擴到 63 時,影響行數為 0,當擴到 64,影響行數為 3,發生了表的 copy。我們進一步用 latin1 驗證,因為拉丁 1 字符集,一個字符只需要一個字節,所以,當擴大到 255 時,仍為 0,當擴大到 256 時,影響行數變為 2。綜上,我們可以總結:因為 varchar 字符集在存儲時除了數據,還需要存 1~2 字節的前綴,長度前綴表示 varchar 中的字節數,當字段的字節數不大于 255 時,需要 1 個字節前綴,當大于 255 時,需要 2 個字節長度。
innodb 存儲引擎,在擴大 varchar 字符長度時,當字節長度在 0~255 之間,或者 256 開始擴大,能用到 inplace 特性,當從 255 擴大到 256 時,只能 copy 表。
varchar(N) 字段類型中的 N 表示字符,根據不同字符集,單個字符需要的字節不一樣,所以范圍也不一樣。
所以,我們在日常工作中,可以制定相應開發規范,盡量防止這類的事情發生。
另外,再提醒下,MySQL 5.7.20 之前的版本可能不支持(我測試的版本是 5.7.29),生產使用時需要再測試下。
此外,varchar 類型的縮小字符長度和字段數據類型更改都只能用 copy 的方式,有此需求要小心。
相關推薦:
技術分享 | Online DDL 工具 pt-osc
技術分享 | Online DDL 工具 gh-ost
新特性解讀 | MySQL 8.0 之原子 DDL社區近期動態
本文關鍵字:#DDL# #mysql5.7#?點一下“閱讀原文”了解更多資訊總結
以上是生活随笔為你收集整理的java有趣的技术分享ppt_技术分享 | 关于 MySQL Online DDL 有趣的验证的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++ 跳转到上级目录_Windows漏
- 下一篇: 影像之王登场!华为P60系列正式发布 售