自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

MySQL枚舉類型的“八宗罪”

數(shù)據(jù)庫 MySQL
MySQL的 枚舉(ENUM)類型 是程序員群體中的一個討論熱點。乍一看,我們可以通過枚舉類型,很好地將記錄值限制在允許范圍內(nèi)。一個典型的例子是,一個具有字段名稱為“大陸板塊”的數(shù)據(jù)表:每一個國家位于一個大陸板塊,而這些大陸板塊不太可能經(jīng)常變化。

[[223100]]

MySQL的 枚舉(ENUM)類型 是程序員群體中的一個討論熱點。乍一看,我們可以通過枚舉類型,很好地將記錄值限制在允許范圍內(nèi)。一個典型的例子是,一個具有字段名稱為“大陸板塊”的數(shù)據(jù)表:每一個國家位于一個大陸板塊,而這些大陸板塊不太可能經(jīng)常變化。當然,或許一天北美板塊會與亞洲板塊碰撞形成北美亞,但即便你的數(shù)據(jù)庫能夠延續(xù)使用到那個時候,起碼你也不需要研討怎么去重構你的數(shù)據(jù)表,那將是當時的開發(fā)者要做的工作。

言歸正傳。如果,使用ENUM是唯一 一個,能夠代表某一個國家屬于哪個大陸板塊的選擇,那我們大可進行下一步,去爭辯諸如NoSQL的優(yōu)劣、Git和SVN孰強孰弱、你喜歡的框架有哪些缺點這些其他的問題。但這里有一個普遍適用于實現(xiàn)枚舉的最佳實踐:

維基百科 是這樣描述關系表的:

…這是一種將可知的枚舉數(shù)據(jù)分離出來的表。例如,一個關系型數(shù)據(jù)庫的倉庫數(shù)據(jù),倉庫里面的“物件”有可能會有一個“狀態(tài)”的字段記錄已經(jīng)聲明的值,例如:“已售,預定,售罄”。在極簡的數(shù)據(jù)庫設計當中,這些值都會在獨立的關系表“狀態(tài)”中存儲,以此滿足范式(database normalization)。

所以,關系表也可以滿足枚舉的實現(xiàn)。下面就來看看,ENUM的”八宗罪“到底是什么:

1. 數(shù)據(jù)被錯誤對待

男、女;先生、夫人、小姐;非洲、亞洲,等等。這些人們使用作為ENUM類型字段的短詞稱為數(shù)據(jù)。當你使用一個ENUM類型字段, 技術上看,是你將數(shù)據(jù)抽離出來 (對應到實際數(shù)據(jù)表時), 放到一個獨立的地位(一種數(shù)據(jù)庫的元數(shù)據(jù),具有精確定義字段)。 這不同與約束數(shù)據(jù)類型,如我們通常的做法:數(shù)值型字段只能存儲整型數(shù)據(jù),或者日期型字段不能為空——這些都沒有問題,而且還十分重要。使用ENUM類型字段時,我們實際上是保存部分數(shù)據(jù) 去作為 這個數(shù)據(jù)模型的一個特征信息。簡而言之, ENUM類型字段破壞了范式要求。這也許看起來十分“學院派”或“迂腐陳舊”,但這正是以下各種“罪行”的源頭。

2. 更改ENUM類型字段,代價很昂貴

永恒不變的是, 每次你創(chuàng)建ENUM類型字段的時候都說:“這個字段不可能變的”。人類普遍欠缺顧全大局的能力,預測上更是糟糕,其如研發(fā)部的新產(chǎn)品線、貴司新的航運方案、北美板塊碰撞亞洲板塊。

使用ALTER TABLE去修改整個數(shù)據(jù)表的ENUM類型字段,是十分耗費資源的。如果將ENUM('red', 'blue', 'black') 改為 ENUM('red', 'blue', 'white'), MySQL 需要重構整個數(shù)據(jù)表,并且檢索 所有數(shù)據(jù)去檢查 'black'這個無效值。 MySQL 是真的蠢,它確實會在你每次增加一個新的ENUM值時都這么做的?。▊餮晕磥頃幚鞥NUM類型字段的效率問題,但我對其受重視程度深表懷疑。)

全表重構在小型數(shù)據(jù)表中可能沒有那么痛苦,但在海量數(shù)據(jù)的情況下可能會導致資源被鎖死很長很長一段時間。如果你使用關系表去替代ENUM類型字段,改變枚舉集合只不過是使用INSERT、UPDATE和DELETE,對比來看真是滑稽。

很重要的一點,當更改ENUM類型字段的枚舉集合時,MySQL會轉(zhuǎn)換任意已有但不存在于新的枚舉集合中的記錄值為''(空的字符串)。使用關系表,在更改和刪除枚舉集合時會靈活很多(下面會提到)。

3. 幾乎無法給關聯(lián)數(shù)據(jù)添加額外的屬性

至今都沒有一個可以更加明智地改變ENUM類型字段的方法,這也是我們的常態(tài)。在我們的“國家、大陸板塊”例子中, 更改“國土面積”會出現(xiàn)什么情況?我們沒有預料到這個屬性, 但也要既來之則安之。使用關系表設計,我們可以輕易地拓展“大陸板塊”這個數(shù)據(jù)表,各種方式為其增加我們想要的數(shù)據(jù)和字段 。ENUM?快別說了。

另一種極妙的靈活性體現(xiàn)在關系表的拓展便捷性上。一個簡單的標記位字段即可表示這個“枚舉值”是否可用。所以,當你的公司不打算銷售黑色的裝飾品了,你只需在“黑色”所對應的_isdiscontinued字段中做個標記即可。而且你依然可以查詢到已售的顏色(譯者:指的是,ENUM的修改會導致原有,而現(xiàn)在已經(jīng)沒有的值變?yōu)榭兆址?,?shù)據(jù)失去了部分特征),同時你那些黑色裝飾品的訂單依然可統(tǒng)可計哦!ENUM,你要不要試試?

4. 獲取ENUM全部可能值,很麻煩

一個很常見的需求是,將數(shù)據(jù)庫中存在的數(shù)據(jù)顯示在可拖拽列表中,例如:

選擇顏色:

紅 藍 黑

如果這些數(shù)值存儲在一個名為‘colors’的數(shù)據(jù)表里,你所要做的僅僅是:SELECT * FROM colors,這樣即可動態(tài)地令數(shù)據(jù)地顯示在可拖拽列表中。你可以添加或者改變color關系表中的顏色,并且,你那酷炫訂單的顏色可選項會自動更新,真了不起。 (譯:此處所舉例子,應等同于:“通過后臺管理,可以限定前端用戶某類型數(shù)據(jù)的可選項。”這樣的功能。)

回到ENUM上:你要如何獲取全部的枚舉值?你當然可以使用ENUM值搭配DISTINCT去查詢(譯:即是查詢ENUM值互相不相同的數(shù)據(jù),等于利用DISTINCT的唯一性去查詢ENUM),但這樣也只會返回確實使用過,并存在于數(shù)據(jù)表ENUM字段可選值中的ENUM值,而不是所有可能的值。你也可以查詢INFORMATION_SCHEMA然后通過代碼解析返回的數(shù)據(jù),去找到你想要的ENUM的所有值,但這完全是多此一舉。事實上,我依然沒有發(fā)現(xiàn),有任何兼顧了優(yōu)雅與原生的SQL方式,可以獲取ENUM類型字段的所有值。

5. ENUM類型字段所提供的優(yōu)化有限

通常使用ENUM的正當理由,不外乎“優(yōu)化”二字,譬如,性能提升,簡化模型與高可讀性。

那我們從性能上看。你可以在未優(yōu)化的數(shù)據(jù)庫中做很多匪夷所思而夸張的事,但是大多情況是,在數(shù)據(jù)達到一定規(guī)模前,都不會出現(xiàn)影響性能的情況,并且通常我們的產(chǎn)品遠未達到那個尺度規(guī)模。有一點需要注意的是,因為數(shù)據(jù)庫開發(fā)者們都熱衷于令自己的設計可以達到完備的范式,并且只會在遇到性能問題時才會考慮反范式。如果你擔心使用關系表會導致變慢,可以在同一基準下測試不同方式下的表現(xiàn),再進行考慮。切勿先入為主地認為關聯(lián)查詢會成為瓶頸,可能有時并非如此。(可參照 evidence to support that ENUM isn't always appreciably faster than alternatives.)

另一個關于ENUM優(yōu)化方式的說法是,ENUM可以有效減少數(shù)據(jù)庫中的數(shù)據(jù)表外鍵。不可置否,使用外鍵相當于是將很多不同的盒子以線相連,而且在大型系統(tǒng)中,范式設計已可降低對人類的理解能力界限、復雜型查詢的要求。但是,我們?yōu)槭裁磿O計模型,為什么要將模型抽象化以便我們能夠理解它。去試試做一個新數(shù)據(jù)模型圖或者ER圖,并且忽略一些小細節(jié)和關系表。有時候使用ENUM確實如看上去那般簡單,但事實上你在心里需要想著一個隱式的關系表,所以并沒有看上去那般簡單。

6. ENUM值在其他數(shù)據(jù)表中不可直接復用

當你(在數(shù)據(jù)表中)創(chuàng)建了一個帶值的ENUM字段,在其他數(shù)據(jù)表中無法直接復用這個ENUM。而當有了關系表,相同應用形式下,可以在其他多個數(shù)據(jù)表中復用。當改變關系表中的一個數(shù)據(jù),其他多個數(shù)據(jù)表也會得到響應。

ENUM類型字段的分離,將使你能在多個數(shù)據(jù)表中復用相同的ENUM值(需要保持一致性)。

7. ENUM類型字段有顯然陷阱

假設你設置了一個字段“color”ENUM('blue', 'black', 'red') ,這時你想INSERT一行數(shù)據(jù),但“color”字段是 'purple', MySQL 會將不合法的值變?yōu)?'' (空字符串)。 處理上沒問題, 但如果我們使用的是帶外鍵的關系表, 那么我們的數(shù)據(jù)能因健壯性而更加可靠。

同樣,MySQL 會為ENUM值關聯(lián)枚舉索引,并且在使用中會錯誤地調(diào)用到索引而不是ENUM值,反之亦然。

想象一下:

 

  1. CREATE TABLE test (foobar ENUM('0''1''2'));  
  2. mysql> INSERT INTO test VALUES ('1'), (1);  
  3. Query OK, 2 rows affected (0.00 sec)  
  4. Records: 2 Duplicates: 0 Warnings: 0  
  5.  
  6. mysql> SELECT * FROM test;  
  7. +--------+  
  8. | foobar |  
  9. +--------+  
  10. | 1 |  
  11. | 0 |  
  12. +--------+  
  13. rows in set (0.00 sec) 

 

我們插入了 '1' (字符串),并且不小心插入了 1 (沒有引號,數(shù)值型)。 MySQL 會將我們地數(shù)值型數(shù)據(jù)當作是枚舉索引去處理(并沒有錯,但會令人混淆),根據(jù)索引可知,ENUM字段的第一個值為 0 。(譯:枚舉索引由 1 開始)

8. ENUM 的移植性不佳

ENUM類型不是SQL標準,屬于MySQL,而其他DBMS不一定有原生的支持。 PostgreSQL, MariaDB,與Drizzle (后面那兩個就MySQL的分支), 我只知道這三個是支持的ENUM的。如果某個人打算將數(shù)據(jù)庫遷移, 那么他就要花費更多的步驟去處理你那些“精妙”的ENUM字段了,相信他會“更愛你”。如果(那個人)是你, 你可會發(fā)現(xiàn)自己當時真是“聰明夠了”。通常來說,數(shù)據(jù)庫遷移不會經(jīng)常發(fā)生,并且,由于所有人都會假設遷移數(shù)據(jù)庫的過程中,必然要出亂子,因此成為“第八宗罪”。

幾時適合使用ENUM:

1. 當你需要存儲的是準確、不變的值時

大陸板塊就是最好的例子,定義十分準確。另一個常用例子是稱謂:先生、夫人、小姐,或者是撲克的花色:方塊、梅花、紅心、黑桃。但是,即便是這些例子,有時也需要去拓展值的范圍(例如有人需要你稱呼“陳醫(yī)生”而不是“陳先生”的時候,或者你的撲克游戲里面需要用到小丑牌)。

2. 你永遠不需要存儲額外的關聯(lián)信息

用回撲克牌的例子。撲克游戲老少咸宜,依賴的規(guī)則是梅花和黑桃為黑色,方塊和紅心為紅色(例如,尤克牌)。如果我們需要為花色關聯(lián)額外的信息,例如顏色,那將如何?如果我們使用關系表,那我們只需要在關系表中新增字段即可,小事一樁。如果我們使用ENUM去表示花色,那我們就很難去準確的表示花色于顏色的關聯(lián)了,如此我們只能在應用層上去達成這種關聯(lián)。

3. ENUM值的數(shù)量大于2個并少于20個

如果你的ENUM值只有兩個,你完全可以將ENUM換成更加高效的TINYINT(1)或者更更高效的BIT(1)(MySQL5.0.3及以上)。例如: gender ENUM('male', 'female') 可以變換為: is_male BIT(1). 當你只有兩個選項時,完全能以布爾值 true/false,結合字段名字中的“is”關鍵詞來區(qū)分。至于20個的上限設定,沒錯,ENUM事實上可以保存多達65535個值,但求你千萬別試。超過二十個值會變得很累贅,超過50個必然難于管理與使用。

如果你無論如何都要用ENUM:

1. ENUM值千萬不要使用數(shù)值型

ENUM定義為字符型數(shù)據(jù)是有原因的。并不是說你使用數(shù)值型字段類型去存儲數(shù)字是錯誤的,但有充足的證據(jù)顯示,MySQL內(nèi)部機制使用數(shù)字去引用索引(參考 上面的第七條)。反正不要在ENUM中存儲數(shù)字,OK?

2. 考慮使用嚴格模式

啟用嚴格模式,至少在你插入一個不存在的ENUM值時會報告錯誤。否則,只會簡單地出現(xiàn)一個警告,繼而該值被設置為一個空字符串""(枚舉索引為0)。抄筆記:如果你設置了IGNORE,錯誤依然會被忽略。

結論

從開發(fā)、維護的角度去做有意義的事,性能問題出現(xiàn)時再考慮優(yōu)化——普遍而言,使用關系表抑或是使用ENUM類型,爭議不斷。

 

性能瓶頸(這個概念)被濫用已是不爭事實。 開發(fā)者們浪費了大量的時間去思考它、擔心它,(例如)非關鍵代碼上的運行速度。這些對效率的苛求,給調(diào)試與維護造成了很大的負面影響。我們理應忽略那小部分的效率,就拿(達到)97%(效率)而言,過早的優(yōu)化是萬惡之源。 

 

責任編輯:龐桂玉 來源: 數(shù)據(jù)庫開發(fā)
相關推薦

2018-12-19 15:30:27

Python編程語言

2012-12-10 13:26:01

2011-07-08 09:43:51

Chromebook

2011-06-01 10:09:49

Ubuntu

2023-05-08 10:54:39

IT管理CIO

2024-06-19 19:28:51

2011-06-17 14:24:28

Java

2018-02-05 23:14:35

光纖網(wǎng)絡光纖施工

2012-04-29 10:40:23

APP

2011-02-21 09:04:25

2021-03-01 18:48:21

Go管理工具

2014-01-13 09:35:13

創(chuàng)業(yè)企業(yè)

2009-09-04 09:38:00

2021-09-10 13:23:57

數(shù)據(jù)閃存 磁盤

2010-07-20 09:56:53

VDI部署

2010-08-18 10:05:27

IE7IE6

2011-02-23 10:51:36

Chrome

2019-04-15 09:00:00

SQLOracle數(shù)據(jù)庫

2015-10-27 15:41:32

twitter開發(fā)者錯誤策略

2012-09-07 14:41:26

點贊
收藏

51CTO技術棧公眾號