2009-12-26 203 views
90

我有一個MySQL表,其中的行是動態插入的。因爲我不能確定字符串的長度並且不希望它們被截斷,所以我使它們的varchar(200)通常比我需要的大得多。在給varchar字段的長度超過必要時,是否會有大的性能下降?MySQL表中varchar長度的重要性

回答

60

不,從某種意義上說,如果您在該列中存儲的值總是(比如說)少於50個字符,則聲明該列爲varchar(50)varchar(200)具有相同的性能。

+4

不完全如此。查看[Bill Karwin]的答案(http://stackoverflow.com/questions/1962310/importance-of-varchar-length-in-mysql-table#answer-1962329) – hejdav 2016-10-05 09:17:37

+0

我認爲類似的答案應該由docs支持,基準或類似的東西。 – 2018-01-07 12:40:39

13

VARCHAR非常適合你所描述的情況,因爲它的全稱是「可變字符」 - 限制,根據你的榜樣,是200個字符,但東西少被接受將無法​​填補的分配大小該列。

VARCHAR也佔用較少的空間 - 值存儲爲單字節或雙字節長度前綴加數據。長度前綴表示該值中的字節數。如果值不超過255個字節,則列使用一個長度字節,如果值可能需要超過255個字節,則使用兩個長度字節。

有關將MySQL CHAR與VARCHAR數據類型進行比較的更多信息,請參見this link

+1

MySQL存儲(關於CHAR和VARCHAR)中的每個人都應該閱讀本答案中提到的鏈接。謝謝! – Pascal 2016-02-25 09:21:52

3

表現?沒有。磁盤存儲?是的,但價格便宜而豐富。除非你的數據庫會增長到TB級,否則你可能沒問題。

+0

奇怪的是,這個答案在發佈六年後被低估了,其他的都沒有。似乎鬥氣和小氣。這個答案沒有任何不正確的地方。版主? – duffymo 2016-04-06 23:04:05

+0

這裏有一個upvote – 2017-09-22 09:04:33

+0

正如它所說,它確實影響性能。另外,磁盤存儲也不是免費的。更寬的列意味着更多的磁盤讀取/寫入(並且磁盤訪問是懶惰的),還有更寬的索引,這降低了它們的有用性。這兩件事都會對性能產生負面影也許這對於一個小型數據庫來說可以忽略不計,但正如你所說,在千兆字節/兆字節的規模上它肯定會很重要。對於100個註冊表而言,這並不重要。 – Alejandro 2017-12-27 13:24:27

0

作爲varchar而不是char,大小是基於一個內部字段來表示它的實際長度和字符串本身。因此,使用varchar(200)與使用varchar(150)並無太大區別,除了您有可能更多地存儲 。

而且你應該考慮一個行增長時更新會發生什麼。但是,如果這很罕見,那麼你應該沒問題。

241

有一個可能的性能影響:在MySQL中,臨時表和MEMORY表將VARCHAR列存儲爲固定長度列,填充爲其最大長度。如果你設計的列比你需要的最大尺寸大得多,你會消耗更多的內存。這會影響緩存效率,排序速度等。

+25

+1。我還看到一些JDBC驅動程序在設置緩衝區以檢索行時爲最大大小分配足夠的空間。不用說,當一些小丑剛剛完成varchar(50000)以防萬一某人有一個非常大的姓氏時,這會引起很多焦慮和咬牙切齒:-) – paxdiablo 2009-12-26 01:03:34

+15

+1。這是一個重要的影響,我相信這是這個問題的真正答案。 – 2010-02-14 08:07:52

+6

這個答案和接受的答案都是理解OP的正確答案所必需的。 – kd8azz 2013-02-19 23:37:27

1

可以有性能點擊 - 但通常不在大多數用戶會注意的級別。

當預先知道每個字段的大小時,MySQL確切知道每個字段/行之間有多少字節,並且可以在不讀取所有數據的情況下向前翻頁。使用可變字符減少了優化的能力。

Does varchar result in performance hit due to data fragmentation?

更妙的是,char vs varchar

對於大多數用途,你會沒事的 - 但有的區別,對於大型數據庫,你有選擇其中一個的原因。

10

尺寸是性能!尺寸越小越好。不是今天或明天,但總有一天,無論您設計了什麼樣的設計,在嚴重的瓶頸問題上,桌子都會變大。但是,您可以預見設計階段中可能首先發生的一些潛在瓶頸,並嘗試擴展數據庫快速且快樂地執行的時間,直到您需要重新考慮計劃或通過添加更多服務器進行水平擴展。

在您的情況下,您可能遇到很多性能泄漏:對於長的varchar列,大連接幾乎不可能。索引這些列是真正的殺手。您的磁盤必須存儲數據。一個內存頁面可以容納較少的行,並且表掃描速度會更慢。查詢緩存也不太可能在這裏幫助你。

你必須問自己:每年可能會發生多少次插入?平均長度是多少?我是否真的需要超過200個字符,或者我是否可以在應用程序前端捕獲這些字符,甚至可以通知用戶最大長度?我是否可以將表格分成狹義的表格進行快速索引和掃描,以及另一個表格是否容納擴展大小的額外的,不太常用的數據?我可以將可能的varchar數據輸入到類別中,然後將一些數據提取到幾個較小的,也許是int或bool-類型的列中,並以這種方式縮小varchar列嗎?

你可以在這裏做很多事情。最好先進行第一個假設,然後使用實際測量的性能數據逐步重新設計。祝你好運。

+0

+1用於列出設計選項並探索影響。對我的問題也很有幫助。 http://stackoverflow.com/q/12083089/181638 – 2012-08-24 06:39:04

+4

設置較高的最大長度是否會對實際性能產生影響,還是由實際大小決定的性能? – poolie 2013-06-14 04:03:27

3

你們有些人誤以爲varchar(200)佔用磁盤上的表格大小比varchar(20)多。不是這種情況。只有超過255個字符時,mysql纔會使用額外的字節來確定varchar字段數據的長度。

+8

臨時表和「MEMORY」表不是這樣。 – 2011-09-11 18:12:17

+3

任何時候,您的選擇查詢使用臨時表(組和按操作順序等),它會將varchar(200)轉換爲char(200),並且性能將受到影響。 – Jamie 2013-02-07 20:14:35

0

根據數據類型名稱表明這是VARCHAR即變量字符數據存儲,mysql引擎本身根據存儲的數據分配正在使用的內存,所以根據我的知識沒有性能影響。

0

您應該嘗試在大多數場景中查看與char列相同的varchar列,並保守地設置長度。你不必總是將var修飾語想象成影響你在最大長度上作出決定的東西。它應該被看作是一種表現提示,而不是提供的字符串會有不同的長度。

這不是一個必須嚴格遵循數據庫內部指令的指令,它可以完全忽略。不過要注意這一點,因爲有時候實現可能會泄漏(例如固定長度和填充),即使它不應該處於理想的世界。

如果你有一個varchar(255),那麼你不能保證性能明智,它總是會在所有情況下對char(255)的行爲有不同的表現。

將內容設置爲諸如255,65535等內容似乎很容易與內存需求手冊中給出的建議內嵌。這給人的印象是,0(是的,這是一件事)和255之間的任何值都會產生相同的影響。但是,這並不能完全保證。

在行存儲方面,存儲需求往往是真實的或者是體面和成熟的持久存儲引擎的良好指標。它並不像指數那樣強大。

有時候這是一個很難的問題,一個字符串的長度應該設置多長時間才能達到您應該知道的最高界限,但這並沒有影響。不幸的是,這通常是留給用戶去解決的,它確實有點武斷。你不能說永遠不要超過一個字符串,因爲有些情況下你不確定。

當字符串過長而不是截斷時,您應該確保MySQL查詢拋出錯誤,以便至少知道它是否可能與錯誤排放過短。調整列的大小以放大或縮小列可能是昂貴的DDL操作,應該牢記這一點。

字符集也應該考慮長度和性能的起作用。長度是指這個而不是字節。例如,如果使用utf8(不是MB4),則varchar(255)確實是varbinary(3 * 255)。如果沒有運行測試並深入研究源代碼/文檔,很難知道如何實現這些功能。由於這個原因,可能會出現意想不到的膨脹影響。這不僅適用於表演。如果你有一天需要將varchar列的字符集更改爲更大的字符集,那麼如果允許不必要的長字符串出現,可能會避免,最終可能會遇到一些無法追索的限制。這通常是一個相當小的問題,但它確實出現了,最近引入了用於MySQL的utf8mb4和對密鑰長度有限制的索引是一個重大問題。

如果事實證明MAX(LENGTH(column))總是爲< 64(例如,如果確定輸入的限制與列定義不匹配),但是您有varchar(255 )那麼在某些情況下,您很可能會使用比所需空間多四倍的空間。

這可能包括:

  • 不同的引擎,有些人可能會完全忽略它。
  • 緩衝區大小,例如更新或插入可能必須分配完整的255(雖然我沒有檢查源代碼來證明這一點,它只是一個假設)。
  • 索引,如果您嘗試從大量varchar(255)列創建組合鍵,這將立即顯而易見。
  • 中間表和可能的結果集。考慮到事務的工作方式,有些東西可能並不總是可能使用列中字符串的實際最大長度,而不是定義的限制。
  • 內部預測優化可能會將最大長度作爲輸入。
  • 數據庫實施版本的變化。

作爲一個經驗法則,實際上沒有必要使varchar比它需要的時間更長,性能問題或不是,所以我建議儘量堅持。花更多的努力來抽樣數據的大小,通過詢問/研究來強制實際限制或找出真正的限制是理想的方法。

如果你不能,如果你想對varchar(255)做些什麼,如果有疑問的話,那麼我建議你去做科學。這可能包括複製表格,減少var char列的大小,然後將數據從原始數據複製到其中,並查看索引/行數據的大小(索引列也可以將其作爲主鍵在InnoDB中行的行爲可能與行按主鍵排序的行爲不同)。至少通過這種方式,您將知道您是否對IO有影響,而這往往是最敏感的瓶頸之一。測試內存使用情況比較困難,很難對其進行詳盡的測試。我會建議測試潛在的最壞情況(在內存結果中有很多中間值的查詢,檢查大臨時表的解釋等)。

如果你知道表中不會有很多行,你不會使用連接列,索引(特別是複合,唯一)等等,那麼你很可能不會有很多問題。