web-dev-qa-db-ja.com

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

VARCHARサイズの宣言はパフォーマンスにとって意味がありますか? VARCHAR(50)VARCHAR(255)の間に(速度の)違いはありますか?または長さの定義はロジック/デザイン制約ですか?

26
Sonique

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

InnoDBとMyISAM(ダイナミック/コンパクト)の標準行フォーマットでは、VARCHAR(50)VARCHAR(255)は同じ方法で文字列テキストを格納します-長さと実際の文字列の1バイト1文字あたり1〜4バイト(エンコードと格納されている実際の文字によって異なります)。

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

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

つまり、つまり、常にVARCHAR(255)を実行する必要があるということです。いいえいくつかの理由があります。

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

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

さらに、InnoDBの最大インライン行サイズはページの半分(約8000バイト)であり、BLOBやvarcharなどの可変長フィールドは、収まらない場合はページ外に格納できますハーフページ。これには、無視できないパフォーマンスの結果(使用状況によっては、良い場合もあれば悪い場合もあります)があります。これにより、COMPACT形式とDYNAMIC形式の間に奇妙さが生じました。例を参照してください。 エラー1118:行サイズが大きすぎます。utf8innodb

最後に重要なことですが、@ 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)
_

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

更新:たとえば、絵文字を使用するなど、可変長文字列の爆発的な人気のため、Oracleはそれらの場合のパフォーマンスの向上を推進しています。最新のMySQLバージョン(5.6、5.7)では、InnoDBが組み込みおよび明示的な一時テーブルのデフォルトエンジンとして設定されており、可変長フィールドが一流のシチズンになりました。つまり、文字の長さが非常に制限されている理由は少ないかもしれません(ただし、文字の長さはまだ存在しています)。

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

35
jynus

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

  • わずかな量でパフォーマンスに影響します。
  • 当然のルールが言うよりも「2」多い。

255に関する質問は何度も尋ねられ、答えられました。

  • 長すぎるVARCHARsは、_CREATE TABLE_の失敗につながる可能性があります。
  • 複雑なSELECTは、一時テーブルを使用して、たとえば、_ORDER BY_の並べ替えを行います。 MEMORYテーブルが使用されます状況によっては。他の状況では、MyISAMが使用されます。 MEMORYを使用すると、VARCHARsCHARsに変換されます(一時テーブル用)。これは、たとえば、VARCHAR(255) CHARACTER SET utf8mb4が1020バイトの固定長を必要とすることを意味します。そして、それはMEMORYを使用するには「大きすぎる」ので、効率の低いMyISAMに切り替わります。

(MySQL 8.0では、一時テーブルの詳細が変更されました。前の段落は8.0より前のすべてのエンジンのテーブルに適用されます。)

結論:盲目的に255(または256)を使用しないでください。スキーマにとって意味のあることを行います。 255(または1024など)が必要な場合は、使用してください。私は単にいくつかの欠点を指摘しています。

どのくらいのパフォーマンスがヒットしましたか?予測するのは難しいです。一般に、心配する価値はありません。 (質問はパフォーマンスに関するものでしたが、私はVARCHARの数が重要であるすべてのケースをリストしようとしましたが、少しでもです。)

0
Rick James