MySQL 的 varchar 與 text 對比

MySQL 的 varchar 與 text 對比

  varchar 和 text 是 MySQL 字符存儲爭議比較多的領域,究竟大字段用那個比較好,我們來對比一下,然後自行選擇。

1 大小對比

1.1 VARCHAR

  varchar 在 MySQL 中必須滿足最大行寬度限制,也就是 65535(64k) 字節,而 varchar 本身是按字符串個數來定義的,在 MySQL 中使用 uft-8 字符集一個字符佔用三個字節,所以單表 varchar 實際佔用最大長度如下:
  1)使用 utf-8 字符編碼集 varchar 最大長度是 (65535-2)/3 = 21844 個字符(超過 255 個字節會有 2 字節的額外佔用空間開銷,所以減 2,如果是 255 以下,則減 1)。
  2)使用 utf-8mb4 字符集,MySQL 中使用 utf-8mb4 字符集一個字符佔用 4 個字節,所以 varchar 最大長度是 (65535-2)/4 = 16383 個字符(超過 255 個字節會有 2 字節的額外佔用空間開銷,所以減 2,如果是 255 以下,則減 1)。

注:如果使用 utf-8mb4 字符集時,有些需要存儲 utf-8 字符的時候,還是會只佔 3 字節,所以有時會比這個計算值能存更多個字符,因爲 utf-8mb4 是 utf-8 的超集。

1.2 TEXT

  最大限制也是 64k 個字節,但是本質是溢出存儲,InnoDB 默認只會存放前 768 字節在數據頁中,而剩餘的數據則會存儲在溢出段中,雖然也受單表 65535 最大行寬度限制,但 MySQL 表中每個 BLOB 和 TEXT 列實際只佔其中的 5 至 9 個字節,其他部分將進行溢出存儲。所以實際佔用表最大行寬度爲 9+2 字節,外加的是額外開銷,跟表的實際寬度沒有關係:
  1)如果使用 utf-8 字符集,那麼單字段佔用最大長度也是 21844 個字符。
  2)不過單表可以設置多個 text 字段,這就突破了單表最大行寬度 65535 的限制。

注:如果採用了新的行格式類型 Barracuda (梭子魚),該文件格式擁有新的兩種行格式(compressed 和 dynamic),兩種格式對 blob/text 字段採用完全溢出的方式,數據頁中只存放 20 字,,其餘的都存放在溢出段中。

1.3 其他 TEXT

  text 字段是分長中短類型,不像 varchar 只有一種,除了上面的 text,還有下面三個:

1.3.1 TinyText

  最大長度 255 個字節,實際上是個沒什麼意義的類型了。

1.3.2 MEDIUMTEXT

  最大長度限制 16M 個字節。和普通 text 一樣也支持溢出存儲,所以實際佔用表最大行寬度爲 9+3 字節,外加的是額外開銷。

1.3.3 LONGTEXT

  最大長度限制 4G 個字節。和普通 text 一樣也支持溢出存儲,所以實際佔用表最大行寬度爲 9+4 字節,外加的是額外開銷。

1.4 示例

# VARCHAR 單表單字段最長不能超過 21844
CREATE TABLE test(
    va VARCHAR(21845)
)DEFAULT CHARSET=utf8;
[Err] 1118 - Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

# 這樣就可以了
CREATE TABLE test(
    va VARCHAR(21844)
)DEFAULT CHARSET=utf8;
受影響的行: 0
時間: 0.155s

# 雖然每個BLOB和TEXT列 賬戶只佔其中的5至9個字節。但是還不夠
CREATE TABLE test(
    va VARCHAR(21841),
    tx text
)DEFAULT CHARSET=utf8;
[Err] 1118 - Row size too large. The maximum row size for the used table type, not counting BLOBs, is 65535. This includes storage overhead, check the manual. You have to change some columns to TEXT or BLOBs

#然後9+2就可以了
CREATE TABLE test(
    va VARCHAR(21840),
    tx text
)DEFAULT CHARSET=utf8;
受影響的行: 0
時間: 0.170s

1.5 額外佔用空間開銷說明

  • varchar 小於 255byte 1byte overhead
  • varchar 大於 255byte 2byte overhead
  • tinytext 0-255 1 byte overhead
  • text 0-65535 byte 2 byte overhead
  • mediumtext 0-16M 3 byte overhead
  • longtext 0-4Gb 4byte overhead

注:雖然 text 字段會把超過 768 字節的大部分數據溢出存放到硬盤其他空間,看上去是會更加增加磁盤壓力。但從處理形態上來講 varchar 大於 768 字節後,實質上存儲和 text 差別不是太大了。因爲超長的 varchar 也是會用到溢出存儲,讀取該行也是要去讀硬盤然後加載到內存,基本認爲是一樣的。
  另外從 8000byte 這個點說明一下,MySQL 的 InnoDB data page 默認一個數據頁是 16K,要存兩行數據,所以對於 varcahr,,text 如果一行數據不超過 8000byte,overflow 不會存到別的 page 中。

2 差異點

  text 字段,MySQL不允許有默認值。建立索引必須給出前綴索引長度。
  varchar 允許有默認值,對索引長度沒限制。

注:InnoDB 引擎單一字段索引的默認長度最大爲 767 字節,MyISAM 爲 1000 字節。例如字符編碼是 utf8,那麼 varchar 的索引最大長度是 256 個字符。超出限制會導致索引創建不成功,轉而需要創建前綴索引。設置InnoDB_large_prefix = 1 可以增大限制,允許索引使用動態壓縮,但是表的 row_format 必須是 compressed 或者 dynamic。可以使索引列長度大於767bytes,但是總長度不能大於 3072 bytes。

3 總結

  • 根據存儲的實現:可以考慮用 varchar 替代 text,因爲 varchar 存儲更彈性,存儲數據少的話性能更高。
  • 如果存儲的數據大於 64K,就必須使用到 mediumtext,longtext,因爲 varchar 已經存不下了。
  • 如果 varchar(255+) 之後,和 text 在存儲機制是一樣的,性能也相差無幾。
  • 需要特別注意 varchar(255) 不只是 255byte,實質上有可能佔用的更多。
發佈了32 篇原創文章 · 獲贊 6 · 訪問量 2427
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章