MySQL-varcharの長さとパフォーマンス


回答:


31

これは非常に一般的な「試験/面接の質問」です。できる限り良い回答をします。

InnoDBとMyISAM(動的/コンパクト)の標準行形式では、a VARCHAR(50)とa VARCHAR(255)は同じ方法で文字列テキストを保存します-長さは1バイトで、文字ごとに1〜4バイトの実際の文字列(エンコードと保存されている実際の文字)。

実際、正しく覚えていれば、aのようなものをa VARCHAR(50)に変更するために16進エディターでデータディクショナリを変更している人を思い出すVARCHAR(100)ので、動的に行うことができます(通常、テーブルの再構築が必要です)。実際のデータはその変更の影響を受けなかったため、それは可能でした。

VARCHAR(256)では、長さの2バイト(少なくとも)が常に必要なので、これは当てはまりません。

だから、それは私たちがいつもやるべきことを意味しVARCHAR(255)ますよね?いいえ。いくつかの理由があります。

InnoDBはvarcharを動的な方法で保存する場合がありますが、他のエンジンには当てはまりません。MyISAMの行サイズの形式は固定されており、MEMORYテーブルのサイズは常に固定されています。他のエンジンを気にする必要がありますか?はい、直接使用しない場合でも、MEMORYテーブルは中間結果(メモリ上の一時テーブル)非常に一般的に使用され、結果が事前にわからないため、テーブルを最大サイズで作成する必要があるためです可能- VARCHAR(255)それが私たちのタイプの場合。無駄なスペースについて考えることができ、MySQLの'utf8' charsetエンコーディングを使用している場合、MEMORYは行ごとに長さ+ 3 * 255バイトの2バイトを予約します(InnoDBで数バイトしか使用できない値の場合)。これは、1,000,000個のテーブルでほぼ1GBです(VARCHARのみ)。これは不必要なメモリストレスを引き起こすだけでなく、ディスク上で実行されるアクションを引き起こし、潜在的に数千倍の速度低下を引き起こす可能性があります。そのすべては、(コンテンツとは無関係に)定義されたデータ型の選択が不十分なためです。

InnoDBにもいくつかの影響があります。インデックスサイズは3072バイトに制限され、単一列インデックスは767バイトに制限されています*。そのためVARCHAR(255)フィールドを完全にインデックス化できない可能性が非常に高くなります(utf8またはその他の可変長エンコードを使用すると仮定します)。

さらに、InnoDBの最大インライン行サイズはページの半分(約8000バイト)であり、BLOBやvarcharなどの可変長フィールドは、half-pageに収まらない場合、ページ外に格納できます。これは、無視できないパフォーマンス(使用状況によっては、良い場合も悪い場合もあります)にいくつかの結果をもたらします。これにより、コンパクト形式とダイナミック形式の間に奇妙なことが起こりました。例:エラー1118:行サイズが大きすぎます。utf8 innodb

最後になりましたが、@ ypercubeが思い出したようにVARCHAR(255)、定義は文字であり、長さはバイトを格納するため、を使用している場合でも、長さに1バイト以上が必要になる場合があります。たとえばREPEAT('ñ', 255)、utf8には2 ^ 255バイト以上あるため、長さを保存するには1バイト以上が必要になります。

mysql> SELECT LENGTH(REPEAT('ñ', 255));
+---------------------------+
| LENGTH(REPEAT('ñ', 255))  |
+---------------------------+
|                       510 |
+---------------------------+
1 row in set (0.02 sec)

mysql> SELECT CHAR_LENGTH(REPEAT('ñ', 255));
+--------------------------------+
| CHAR_LENGTH(REPEAT('ñ', 255))  |
+--------------------------------+
|                            255 |
+--------------------------------+
1 row in set (0.00 sec)

したがって、一般的なアドバイスとしては、パフォーマンスや管理の問題を引き起こす可能性があるため、可能な限り小さいタイプ使用することです。正確な長さがわからない場合でも、A VARCHAR(100)VARCHAR(255)(aのVARCHAR(20)方が優れていますが)よりも優れています。テーブルが大きすぎない限り、後からいつでも定義を変更できるため、保守的にしてください。

更新:たとえば、絵文字を使用するなど、可変長文字列の人気が爆発的に高まっているため、Oracleはそのような場合のパフォーマンスの向上を推進しています。最新のMySQLバージョン(5.6、5.7)では、InnoDBは組み込みの一時テーブルと明示的な一時テーブルの両方のデフォルトエンジンとして設定されています。つまり、可変長フィールドがファーストクラスの市民になりました。つまり、文字の長さが非常に制限されている理由が少なくなる可能性があることを意味します(ただし、文字の長さはまだ存在します)。

(*)2番目の更新:large_prefix_indexは、最新のMySQLバージョン(8.0)でデフォルトで有効になりましたが、古いバージョンまたは遅延innodbファイル/行形式(動的または圧縮以外)を使用している場合は引き続き有効ですが、デフォルトでは、単一列のインデックスは3072バイトまで可能です。


小規模な更新:MySQL-8.0.13 +は、varcharの効率的なストレージを持つ一時テーブルにデフォルトでTempTableを使用します。
ダンブラック

0

で1バイトと2バイトのプレフィックスを忘れてくださいVARCHARs

  • わずかな量でパフォーマンスに影響します。
  • 明白なルールが言うよりも頻繁に「2」です。

255についての質問が何度も聞かれ、回答されました。

  • 長すぎるVARCHARsとの失敗につながりCREATE TABLEます。
  • 一時テーブルはに変わることMEMORYで、テーブルVARCHARsになってVARCHAR。これは、たとえば、VARCHAR(255) CHARACTER SET utf8mb41020バイトの固定長が必要であることを意味します。(これは失敗し、MyISAMを使用すると劣化します。)

結論:盲目的に255(または256)を使用しないでください。スキーマにとって意味のあることを行います。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.