MySQL 資料庫設計的“奧祕”

Yin發表於2021-06-27

2 MySQL 資料庫設計的“奧祕”

【主題】邏輯設計:資料型別與 Schema

所謂“萬丈高樓平地起”,一個穩固的建築離不開紮實的基礎。同樣,良好的的「邏輯設計」「物理設計」是資料庫高效能的基石。

本文的主要內容總結了一張圖,你可以點選檢視。

image

我們需要根據系統需要執行的 SQL 語句設計 schema,這往往權衡各種因素。

[idea]瞧!權衡和取捨不僅僅在系統設計、方案設計時處處體現其價值,在資料庫表設計也同樣如此。

舉個例子,反正規化設計可以加快某些型別查詢,但可能會使另一些型別查詢變慢。如增加彙總表可以優化查詢,但這些表維護成本可能很高。

首先,讓我們一起來看下 MySQL 的資料型別,這是我們設計資料表前需要事先掌握的。

如何選擇優化的資料型別?

MySQL 支援的資料型別很多,為了做出更好的選擇,我們來看幾個簡單的原則:

1.更小的通常更好

儘量使用可以正確儲存資料的最小資料型別

優點:

  • 佔用更少的磁碟、記憶體和 CPU 快取
  • 處理時需要 CPU 週期更少

缺點:

  • 但是要確保沒有低估儲存值範圍

2.簡單就好

簡單資料型別需要更少的 CPU 週期。

比如整型比字串代價低(字串有字符集和校對規則)。

3.儘量避免 NULL

NULL 列對 MySQL 更難優化,因為為 NULL 的列使得索引、索引統計和值比較都更復雜;並且佔用更多儲存空間。

todo 為什麼佔用更多儲存空間?

推薦步驟

步驟1:確定合適的大型別

如數字、字串、時間等。

步驟2:選擇具體型別

同型別下只是儲存的長度、範圍、允許的精度、需要的物理空間(磁碟、記憶體)不同。

資料型別概覽

1.整數型別

有兩種型別的數字:「整數」「實數」

整數有很多種,如:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分別使用 8,16,24,32,64 位儲存空間。

  • 有可選的 UNSIGNED 屬性,表示不允許負值。

  • 還可以指定寬度

    例如 INT(11),它不會限制值的合法範圍,只是規定了 MySQL 的一些客戶端顯示字元的個數。

    INT(1) 和 INT(11) 是相同的。

2.實數型別

即帶有小數部分的數字。MySQL 既支援精確型別,也支援不精確型別。

  • 可以指定需要的精度

FLOAT 和 DOUBLE 型別使用浮點運算進行近似計算。

DECIMAL 型別用於儲存精確的小數。使用場景:儘量只有對小數需要精確計算時才使用,因為需要額外的儲存空間和計算開銷。

資料量比較大時,可以使用 BIGINT 代替 DECIMAL,對應單位乘以相應倍數即可。

3.字串型別

VACHAR 和 CHAR 型別

VACHAR
  • 比定長型別更節省空間,因為它只使用必要的空間(如字串越短使用空間越少)。

  • 需要使用 1(<=255) 或 2(>255) 個額外位元組記錄字串長度。

  • 由於變長,Update 可能使行變得比原來更長,容易產生碎片

    如 InnoDB 需要頁分裂使得行可以放到頁內。

適合 VACHAR 的場景:

  • 最大長度比平均長度大得多
  • 列的更新很少
  • 使用了像 UTF-8 這樣的複雜字符集
CHAR
  • 定長,會根據需要填充空格

適合 CHAR 的場景:

  • 儲存很短的字串或所有值接近同一個長度
  • 經常變更資料,不易產生碎片(因為定長不會頁分裂)

建議:最好的策略是隻分配真正需要的空間

todo Vachar(5) 和 Vachar(200) 又什麼區別?空間開銷一樣吧?

BLOB 和 TEXT 型別

適合場景:儲存很大的資料,前者使用二進位制,後者使用字元儲存。

特殊之處:MySQL 把 BLOB 和 TEXT 值當作獨立物件處理,值太大時會使用專門的“外部”儲存區域儲存,在行記憶體儲指標指向外部實際值。

[idea]這個設計在程式開發中也可以使用,有時一些大屬性佔用儲存較多但使用頻率較低,可以單獨儲存在其他地方,通過指標進行引用,從而使得該物件更小。

不能將 BLOB 和 TEXT 列全部長度索引,不能用這些索引消除排序。

如果 Explain 執行計劃的 Extra 列包含“Using temporary”,說明這個查詢使用了「隱式臨時表」

使用列舉(ENUM)代替字串型別

優點:儲存列舉時非常緊湊,節約空間

MySQL 內部將每個值在列表中位置儲存為整數,在表的 .frm 檔案中儲存“數字-字串”對映關係的“查詢表”。

所以,使用數字作為列舉常量,這種雙重性容易導致混亂。建議儘量避免這麼做

例如 ENUM('1','2',3'')

⚠️列舉欄位是按照內部儲存整數而不是定義的字串數字排序。

缺點:

  • 字串列表是固定的,如果未來要改變列舉值則不適合
  • 列舉值轉為整數值儲存有開銷

建議通用設計實踐:在“查詢表”時採用整數主鍵而避免採用字串的值進行關聯,因為效能更好。


END

相關文章