Mysql

MySQL VARCHAR 大小的性能影響

  • December 3, 2020

MySQL 的 varchar 大小之間是否存在性能差異?例如,varchar(25)varchar(64000)。如果不是,是否有理由不聲明所有具有最大大小的 varchars,以確保您不會用完空間?

您必須意識到使用 CHAR 與 VARCHAR 的權衡

使用 CHAR 欄位,您分配的正是您得到的。例如,CHAR(15) 分配並儲存 15 個字節,無論您在欄位中放置何種字元。字元串操作簡單直接,因為數據欄位的大小是完全可預測的。

使用 VARCHAR 欄位,您會得到一個完全不同的故事。例如,VARCHAR(15) 實際上動態分配最多 16 個字節,最多 15 個用於數據,至少還有 1 個額外的字節來儲存數據的長度。如果您要儲存字元串“hello”,則需要 6 個字節,而不是 5 個字節。字元串操作在所有情況下都必須始終執行某種形式的長度檢查。

當您做兩件事時,這種權衡更加明顯:

  1. 儲存數百萬或數十億行

  2. 索引 CHAR 或 VARCHAR 列

權衡#1

顯然,VARCHAR 具有優勢,因為可變長度數據會產生更小的行,從而產生更小的物理文件。

權衡#2

由於 CHAR 欄位由於欄位寬度固定而需要較少的字元串操作,因此針對 CHAR 欄位的索引查找平均比 VARCHAR 欄位快 20%。這不是我的任何猜測。MySQL Database Design and Tuning一書在 MyISAM 表上做了一些奇妙的事情來證明這一點。書中的例子做瞭如下的事情:

ALTER TABLE tblname ROW_FORMAT=FIXED;

該指令強制 VARCHAR 表現為 CHAR。早在 2007 年,我在上一份工作中就做到了這一點,並使用了一個 300GB 的表並將索引查找速度提高了 20%,而沒有更改任何其他內容。它按已發布的方式工作。然而,它確實產生了一個幾乎兩倍大小的表,但這又回到了權衡#1。

您可以分析儲存的數據以查看 MySQL 推薦的列定義。只需對任何表執行以下命令:

SELECT * FROM tblname PROCEDURE ANALYSE();

這將遍歷整個表,並根據其包含的數據、最小欄位值、最大欄位值等為每列推薦列定義。有時,您只需要使用常識來規劃 CHAR 與 VARCHAR。這是一個很好的例子:

如果要儲存 IP 地址,則此類列的遮罩最多為 15 個字元 (xxx.xxx.xxx.xxx)。我會立即跳到 CHAR(15) 處,因為 IP 地址的長度不會有太大變化,而且字元串操作的複雜性由額外的字節控制。您仍然可以對這樣的列執行 PROCEDURE ANALYSE()。它甚至可能會推薦 VARCHAR。在這種情況下,我的錢仍然會放在 CHAR 上而不是 VARCHAR 上。

CHAR 與 VARCHAR 問題只能通過適當的計劃來解決。權力越大,責任越大(陳詞濫調但真實)

該執行緒中的大多數答案已有五八年的歷史,在 InnoDB 和 utf8 成為預設值之前編寫。那麼,讓我重新開始……

當查詢需要內部臨時表時,它會嘗試使用MEMORY表。但是如果 MEMORY 不能使用

  • TEXT/BLOB列被提取,甚至TINYTEXT.
  • VARCHAR大於某個數量,在目前版本中可能為 512。

另外,請注意VARCHARs變成CHARs. (8.0 對此進行了修改。)因此,無論列中的內容如何,都將VARCHAR(255)a擴展為 765 個字節。CHARACTER SET utf8然後,這可能會被觸發:

  • 如果MEMORYtable 變得大於max_heap_table_size or tmp_table_size,它將被轉換為 MyISAM 並可能溢出到磁碟。

因此,VARCHAR(25)更有可能留下來MEMORY,因此速度更快。 (255)不是那麼好,而且(64000)是壞的。

(將來,臨時表可能會是InnoDB,這個答案的一部分需要修改。)

(更新)MySQL 8.0.2:“TempTable 儲存引擎將 MEMORY 儲存引擎替換為記憶體內部臨時表的預設引擎。TempTable 儲存引擎為 VARCHAR 和 VARBINARY 列提供高效儲存。” (從那以後,臨時表的處理有了進一步的變化;我懷疑塵埃還沒有落定。)

引用自:https://dba.stackexchange.com/questions/424