從SQL Server到MySql(2) : MySql 數據類型與優化

1. 優化數據結構

  • 盡量避免null.
    • 可為NULL的列使索引,索引統計和值比較都更加復雜.
    • 它需要更多的存儲空間, 在MySql 里需要特殊的處理.
    • 索引可為NULL的列時,每個索引記錄需要一個額外的字節. (InnoDB使用單獨的bit來存儲NULL值,會稍微好點).
  • 更小的通常更好. 它們占用更少的磁盤,內存和緩存, 處理時需要的CPU 周期也更少.
  • 簡單就好. 簡單類型的操作需要更少的CPU周期.
  • 兩步進行數據類型的選擇:
    • 確定合適的大類型: 數字,字符串,時間等.
    • 根據存儲的長度和范圍, 允許的精度, 需要的物理空間 來選擇具體的類型.

2. 整數類型

2.1 整數類型

  • 不同的具體類型(包含無符號數)決定的是如何在內存和磁盤中保存數據,并不影響性能,整數計算都使用64位的BIGINT.
  • 整型的寬度,例如INT(11)中的11, 只是規定了某些交互工具中, 用來顯式字符的個數, 并不影響存儲和值范圍.

2.2 實數類型

  • 使用DOUBLE作為內部浮點類型的計算類型.
  • Decimal需要額外的空間和計算開銷. 僅在需要對小數進行精確計算時才使用. 當數據量大時可使用BIGINT替代.

3. 字符串類型

  • VARChar 需要額外的1或2個字節(根據最大長度的大小)記錄長度.
    • 比定長類型更節省空間, 因為僅使用必要的空間.
    • 若表使用Row_Format = Fixed 創建時,每一行都使用定長存儲,會浪費空間.
    • Update 時若造成行更長, 可能會導致碎片.
    • 適用場景: 字符串列的最大長度比平均長度大很多. 列更新少(不易產生碎片). 采用的字符集中每個字符都使用不同的字節數進行存儲.
  • CHAR 適合較短的字符串, 或所有值都接近一個長度.
  • Binary,VarBinary 在需要存儲二進制數據時, 其比較是按字節逐次比較,更加簡單高效.
  • Blob和Text 用于存儲很大的字符串.
    • 其值會被當成獨立的對象處理. 當值很大時,會使用外部空間存儲,內部存儲指針.
    • 其列排序只對最前max_sort_length字節而非整個字節排序.
    • 不能對列全部長度的字符串進行索引.
    • Memory?引擎不支持Blob和Text. 若查詢使用了他們, 會造成磁盤臨時表的使用.
    • 應避免使用它們. 如使用Substring將列值轉換為字符串.

4. 枚舉

  • 有時可以使用枚舉類代替常用的字符串類型.
  • 問題: 列表是固定的,添加或刪除必須使用alter table. 對于未來會變更的情況,盡量不使用,除非只在末尾添加元素.
  • 存儲枚舉時非常緊湊, 會根據列表值的數量壓縮到1/2字節中. 在內部將值在列表中的位置保存為整數. 并在.frm文件中保存'數字-字符串'映射關系的查找表.
  • 盡量避免使用數字作為枚舉常量, 這樣會有雙重性.
  • 按照內部存儲的整數而不是定義的字符串的值進行排序的(也就是定義值時的順序).

5. 日期和時間類型

  • TimeStamp 保存了從1970 年以來的秒數.
    • 只使用4個字節存儲,所以只能到2038 年.
    • 等同于UNIX時間戳.
      • from_unixtime()/unix_timestamp()進行日期和Unix時間戳的轉換.
    • 顯示值依賴于時區.
    • TimeStamp 列默認為Not Null.
    • 其空間效率更高,所以應盡量使用TimeStamp.
  • DateTime
    • 可保存從1001到9999 年, 精度為秒.
    • 將時間和日期封裝到格式為YYYYMMDDHHMMSS 的整數中,與時區無關.
    • 使用8個字節存儲.

6. 位數據類型

  • BIT
    • 被當做字符串類型,而不是數字類型.
    • 檢索出的結果是包含0和1的字串.
    • 但在數字上下文中得到的是字串對應的數字值. 所以會產生二義性.
  • SET
    • 若需要保存很多true/false 值, 可以合并這些列到一個SET中.
      • 如ACL: SET('CAN_READ', 'CAN_WRITE', 'CAN_DELETE').
    • 內部以一系列打包的位的集合來表示,從而有效地利用了存儲空間.
    • 問題是改變列定義(交換可讀和可寫的位置)?時的代價較大, 且無法在SET列上通過索引查找.
  • 在整數列上進行按位操作.
    • 一種替代SET的方式是使用一個整數包裝一系列的位. 如把8個位包裝到一個TINYINT中,并按位操作來使用.
    • 好處是可以不適用Alter Table 改變字段代表的"枚舉"值.
    • 缺點是查詢語句更難寫, 并且難以理解.

7. Schema 的設計陷阱

  • 太大的列.
    • 存儲引擎API需要在服務器層和存儲引擎層通過緩存格式拷貝數據, 然后在服務器層將緩存內容解碼成各個列. 從行緩存中將編碼過的列轉換成行數據結構的代碼很高.
    • 定長行結構與服務器層的行結構正好匹配, 所以不需要轉換. 而變長結構總是需要昂貴的轉換.
  • 太多的關聯
    • 所謂的"實體-屬性-值(EVA)"是一種糟糕的設計模式. 它需要過多的自關聯.
  • 全能的枚舉
    • 類似enum('','0','1',....'31'). 會造成新增值時的alter table.
    • 應該使用整數作為外鍵關聯到字典表或查找表來查找具體值.
  • 多數情況下,應該避免使用NULL值,而使用替代(0,特殊值). 但不要極端.
    • MySql會在索引中存儲NULL值.
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容