【MySQL數據類型測試】枚舉數據類型ENUM的DDL變更測試(第五節)

MySQL數據庫之枚舉數據類型ENUM的DDL變更測試

針對四種數據類型:布爾類型BOOL或稱布爾類型BOOLEAN、微整型TINYTINT、枚舉類型ENUM、集合類型SET,我們已經分多篇文章篇幅給出詳細的介紹與功能測試數據,接下來我們深入介紹枚舉類型EUNM和集合類型SET。測試基於InnoDB存儲引擎上,對MySQL數據庫枚舉類型ENUM的字段進行DDL變更操作,是否需要重新創建表呢?對數據庫的事務處理有何影響?對數據庫的數據服務提供有何性能影響?
(一)系統環境
硬件:DELL R510 10塊盤做的RAID5,上面跑了幾十個虛擬機
操作系統:CentOS release 5.5 (Final)
MySQL數據庫:5.5.15-log
InnoDB存儲引擎:plugin-InnoDB 1.1.8

(二)測試數據準備
詳見之前的文章。
(三)枚舉類型ENUM字段DDL操作
a)增加枚舉類型字段定義的默認值屬性
root@localhost : mysqlops 02:35:51> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘DBA’,‘SA’,‘C++’,‘JavaScript’,‘NA’,‘QA’,‘Java’,‘PHP’,‘other’,’’) NOT NULL DEFAULT ‘DBA’;
Query OK, 20017251 rows affected (2 min 7.76 sec)
Records: 20017251 Duplicates: 0 Warnings: 0
小結:
枚舉類型字段,由允許NULL值且無默認值的定義屬性,變更爲不允許存儲NULL值和制定枚舉類型字段的默認值,這個過程需要表級鎖,鎖住表堵塞其他事務性操作,與其他數據類型的字段屬性變更是一樣的。

b)修改枚舉類型字段定義的默認值
root@localhost : mysqlops 02:38:19> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘DBA’,‘SA’,‘C++’,‘JavaScript’,‘NA’,‘QA’,‘Java’,‘PHP’,‘other’,’’) NOT NULL DEFAULT ‘’;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0

小結:
枚舉類型字段已經存在默認值,只是修改默認值爲不同默認值的操作,是不需要重新建表與鎖表,也是與其他數據類型字段的字段屬性變更一樣。

c)修改枚舉類型字段定義的默認值,且新默認值不在枚舉列表中
root@localhost : mysqlops 02:39:15> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘DBA’,‘SA’,‘C++’,‘JavaScript’,‘NA’,‘QA’,‘Java’,‘other’,’’) NOT NULL DEFAULT ‘iphone’;
ERROR 1067 (42000): Invalid default value for ‘Work_Option’
小結:
若是給枚舉類型字段指定的默認值,沒有在枚舉類型值域列表中出現,則會出現SQL語法錯誤,導致SQL語句執行失敗。

d)修改枚舉類型字段定義,尾部追加枚舉元素
root@localhost : mysqlops 02:39:27> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘DBA’,‘SA’,‘C++’,‘JavaScript’,‘NA’,‘QA’,‘Java’,‘PHP’,‘other’,’’,‘Python’) NOT NULL DEFAULT ‘DBA’;
Query OK, 0 rows affected (0.00 sec)
Records: 0 Duplicates: 0 Warnings: 0
小結:
爲枚舉類型字段的值域列表增加枚舉元素,若是尾部追加的方式,則不需要表級鎖,可以非常快就可以完成DDL變更。

e)修改枚舉類型字段定義,調整枚舉元素的順序
root@localhost : mysqlops 02:38:10> SELECT * FROM mysqlops_set_enum WHERE Work_Option=1 LIMIT 1;
±---------±------------±------------------+
| ID | Work_Option | Work_City |
±---------±------------±------------------+
| 12017252 | DBA | guangzhou,tianjin |
±---------±------------±------------------+
1 row in set (3.22 sec)

root@localhost : mysqlops 02:39:39> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘JavaScript’,‘DBA’,‘SA’,‘C++’,‘NA’,‘QA’,‘Java’,‘PHP’,‘other’,’’,‘Python’) NOT NULL DEFAULT ‘DBA’;
Query OK, 20017251 rows affected (2 min 10.75 sec)
Records: 20017251 Duplicates: 0 Warnings: 0

root@localhost : mysqlops 02:42:01> SELECT * FROM mysqlops_set_enum WHERE Work_Option=1 LIMIT 1;
±---------±------------±------------------+
| ID | Work_Option | Work_City |
±---------±------------±------------------+
| 12017252 | DBA | guangzhou,tianjin |
±---------±------------±------------------+
1 row in set (3.22 sec)
小結:
對枚舉類型字段的值域列表元素順序進行調整,會發現:
i.將需要表級鎖和重見數據存儲表的方式,完成枚舉類型字段表的結構調整;
ii.枚舉類型字段值域列表中受影響元素的存儲順序編號發生變化;
iii.數據庫表枚舉類型字段中存儲的數據是枚舉類型元素的編號,枚舉類型元素順序編號發生變化時,對應存儲的數據序號也需要跟着發生變化;

f)修改枚舉類型字段定義,刪除某個枚舉元素
root@localhost : mysqlops 02:05:24> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_Option=’’;
±---------+
| COUNT(
) |
±---------+
| 4017251 |
±---------+
1 row in set (5.00 sec)

root@localhost : mysqlops 02:05:40> SELECT * FROM mysqlops_set_enum limit 6000000,1;
±--------±------------±----------+
| ID | Work_Option | Work_City |
±--------±------------±----------+
| 6000001 | PHP | dalian |
±--------±------------±----------+
1 row in set (1.38 sec)

root@localhost : mysqlops 02:06:55> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_Option=‘PHP’;
±---------+
| COUNT(
) |
±---------+
| 2000000 |
±---------+
1 row in set (5.11 sec)

root@localhost : mysqlops 02:45:40> ALTER TABLE mysqlops_set_enum MODIFY Work_Option enum(‘JavaScript’,‘DBA’,‘SA’,‘C++’,‘NA’,‘QA’,‘Java’,‘other’,’’,‘Python’) NOT NULL DEFAULT ‘DBA’;
Query OK, 20017251 rows affected, 65535 warnings (2 min 11.71 sec)
Records: 20017251 Duplicates: 0 Warnings: 2000000

root@localhost : mysqlops 02:54:01> SHOW WARNINGS;
±--------±-----±-------------------------------------------------------+
| Level | Code | Message |
±--------±-----±-------------------------------------------------------+
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017252 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017253 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017254 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017255 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017256 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017257 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017258 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017259 |
| Warning | 1265 | Data truncated for column ‘Work_Option’ at row 4017260 |

root@localhost : mysqlops 02:56:18> SELECT COUNT() FROM mysqlops_set_enum WHERE Work_Option=’’;
±---------+
| COUNT(
) |
±---------+
| 6017251 |
±---------+
1 row in set (4.68 sec)

root@localhost : mysqlops 02:56:48> SELECT * FROM mysqlops_set_enum WHERE ID=6000001;
±--------±------------±----------+
| ID | Work_Option | Work_City |
±--------±------------±----------+
| 6000001 | | dalian |
±--------±------------±----------+
1 row in set (0.00 sec)
小結:
對於枚舉類型字段中已存儲某枚舉元素的數據,再刪除枚舉類型ENUM字段值域列表中某個枚舉值,則會出現:
I.存在多少條要刪除的枚舉值記錄數,就會產生多少條警告信息(注:警告信息最大值65535條);
II.被刪除枚舉值對應的字段的記錄值,會發生截斷,並且用空字符串值填充;

g)上述DDL變更操作之後的表結構
root@localhost : mysqlops 02:57:30> SHOW CREATE TABLE mysqlops_set_enum\G
*************************** 1. row ***************************
Table: mysqlops_set_enum
Create Table: CREATE TABLE mysqlops_set_enum (
ID int(11) NOT NULL AUTO_INCREMENT,
Work_Option enum(‘JavaScript’,‘DBA’,‘SA’,‘C++’,‘NA’,‘QA’,‘Java’,‘other’,’’,‘Python’) NOT NULL DEFAULT ‘DBA’,
Work_City set(‘shanghai’,‘beijing’,‘hangzhou’,‘shenzhen’,‘guangzhou’,‘xiamen’,‘tianjin’,‘qingdao’,‘dalian’,‘xian’,‘other’) NOT NULL DEFAULT ‘shanghai’,
PRIMARY KEY (ID)
) ENGINE=InnoDB AUTO_INCREMENT=20017252 DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

(四)枚舉類型ENUM字段數據庫索引創建與刪除

a)枚舉類型字段無創建索引條件的SQL語句執行計劃
root@localhost : mysqlops 03:40:35> EXPLAIN SELECT * FROM mysqlops_set_enum WHERE Work_Option=4 LIMIT 1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mysqlops_set_enum
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 20017710
Extra: Using where
1 row in set (0.00 sec)
小結:
MySQL數據庫枚舉類型字段沒有顯式創建索引信息時,即使符合MySQL數據庫使用索引條件要求的SQL語句,也無索引信息可用,也即MySQL數據庫枚舉類型字段值域列表中的存儲序列編號,無法做到替代索引的作用,也即依然需要顯式創建數據庫索引,加速數據查找速度。

b)爲枚舉類型字段創建索引
root@localhost : mysqlops 03:40:59> ALTER TABLE mysqlops_set_enum ADD INDEX idx_Work_Option_enum(Work_Option);
Query OK, 0 rows affected (1 min 14.31 sec)
Records: 0 Duplicates: 0 Warnings: 0
小結:

mysql數據庫枚舉類型字段上創建普通索引,也是需要表級鎖、創建臨時表等方式實現,並沒有什麼內部特殊的機制可使用。

c)枚舉類型字段有索引條件的SQL語句執行計劃
root@localhost : mysqlops 03:42:53> EXPLAIN SELECT * FROM mysqlops_set_enum WHERE Work_Option=4 LIMIT 1\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: mysqlops_set_enum
type: ref
possible_keys: idx_Work_Option_enum
key: idx_Work_Option_enum
key_len: 1
ref: const
rows: 3927162
Extra: Using where
1 row in set (0.00 sec)
小結:
mysql數據庫枚舉類型字段創建索引之後,若是根據枚舉類型字段進行數據查找,且WHERE子句符合正確寫法和枚舉值所佔比例符合使用索引的要求,即可根據索引數據完成數據查找。

d)刪除枚舉類型字段上的索引
root@localhost : mysqlops 03:44:22> ALTER TABLE mysqlops_set_enum DROP INDEX idx_Work_Option_enum;
Query OK, 0 rows affected (0.80 sec)
Records: 0 Duplicates: 0 Warnings: 0
小結:
MySQL5.5.X版本數據庫對於普通索引的刪除操作,還是非常好的支持,並不需要創建臨時表等操作,對於枚舉類型字段上的索引也是同樣適用的,關於這方面的文章可參考MySQL 5.5版本對普通索引增刪性能的優化。

(五)總結
通過上述對MySQL數據庫表枚舉類型字段的定義屬性和索引方面的DDL變更操作,觀察對枚舉類型字段存儲的數據影響,可以得出下列結論:
a)MySQL數據庫枚舉類型字段與其他數據類型一樣,進行DDL變更操作可能產生的影響;
b)MySQL數據庫枚舉類型字段的DDL變更操作,屬於枚舉類型字段特有的內容:
I.枚舉類型字段的枚舉數據值域列表,以尾部追加枚舉元素值的方式,不會出現鎖表等;
II.枚舉類型字段的枚舉數據值域列表中,若是調整枚舉類型枚舉元素值的順序,不會導致數據庫表存儲的數據出現錯亂對照關係,數據庫表存儲數值會發生更新,以及需要鎖表等操作;
III.刪除枚舉類型字段的枚舉數據值域列表中,某個枚舉元素值,會導致數據庫表已存儲的數據行出現截斷,以及需要鎖表等操作;
IV.枚舉類型字段內部的枚舉數據與存儲序號之間的對照關係,不會能起到MySQL數據庫表索引的功能;
V.枚舉類型字段存儲的數據值,則是枚舉類型枚舉元素的序列編號,而不是真實的字符串數據,而是通過其內部對照表的方式轉換而實現的;

好了以上就是今天的內容,覺得這篇文章有價值的讀者可以進入我的主頁瀏覽之前發佈的其他文章,相信同樣也會給你帶來很多幫助的呦~我們下篇文章再見!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章