MySQLテーブルでのvarchar長の重要性


112

行が動的に挿入されるMySQLテーブルがあります。文字列の長さがわからないため、切り取ってほしくないので、varchar(200)にして、一般的に必要以上に大きくしています。varcharフィールドに必要以上に長い長さを与えると、パフォーマンスに大きな影響がありますか?


VARCHAR(255) utf8mb4約15万行のインデックス付き列が1つあるテーブルのサイズは11.5MBです。VARCHAR(48) utf8mb4同じデータ(最大長46文字)のインデックス付き列を持つテーブルは、4.5MBを使用しました。クエリにはそれほど大きな違いはありません。インデックスが付けられています。しかし、クエリのI / Oやデータベースのバックアップのようなもので追加されます。
Code4R7 2018年

回答:


59

いいえ、その列に格納している値が常に(たとえば)50文字未満の場合、その列をと宣言するvarchar(50)varchar(200)、同じパフォーマンスを発揮するという意味です。


9
真実ではありません。ビルカーウィンの
hejdav

5
のような答えは、ドキュメント、ベンチマーク、または同様の何かによってサポートされるべきだと思います。
Gokhan Sari

301

パフォーマンスへの影響が1つ考えられます。MySQLでは、一時テーブルとMEMORYテーブルはVARCHAR列を固定長の列として格納し、最大長までパディングされます。VARCHAR必要な最大サイズよりもはるかに大きい列を設計すると、必要以上のメモリが消費されます。これは、キャッシュ効率、ソート速度などに影響します。


33
+1。行を取得するためのバッファを設定するときに、最大サイズに十分なスペースを割り当てるJDBCドライバもいくつかあるようです。言うまでもなく、誰かが本当に大きな姓を持っている場合に備えて、いくつかのピエロがvarchar(50000)を実行したとき、これは歯のかなりの不安と
歯ぎしりを引き起こし

21
+1。これは重要な影響であり、これがこの質問の正解です。
Emre Yazici 2010

6
この答えと受け入れられた答えはどちらも、OPの正しい答えを理解するために必要です。
kd8azz 2013

2
実際、このようなMEMORYテーブルが大きすぎると見なされると、ディスクに書き込まれ、パフォーマンスが大幅に低下します。
Timo

1
この回答は、どのストレージエンジンが真であるかを指定することで実行できます(dev.mysql.com/doc/refman/8.0/en/…は、MySQL 8以降、一時テーブルが常にInnoDBであることを示しています。何か変更されますか?) 、その主張を裏付けるドキュメントへのリンク付き。Stack Exchangeでの出力について私が見たものから、あなたがこれを書いたときはあなたが正しかったと私は確信していますが、状況は変更されている可能性があり、リンクは他の人にとって良い例となり、他の人に見つけてもらうのに役立ちますこの種の情報は私たち自身のためです。
Mark Amery

14

VARCHARは、あなたが記述の状況に最適です、それは「変数の文字」を意味するので-リミット、あなたの例に基づいて、200文字以内何でもだろうあまり受け入れられている、列の割り当てられたサイズを記入しないであろう。

VARCHARはスペースも少なくて済みます-値は1バイトまたは2バイトの長さのプレフィックスとデータとして格納されます。長さプレフィックスは、値のバイト数を示します。値に255バイト以下が必要な場合、列は1つの長さバイトを使用し、値に255バイト以上が必要な場合、2つの長さバイトを使用します。

MySQLのCHARとVARCHARのデータ型の比較の詳細については、このリンクを参照してください


1
MySQLストレージに関心のあるすべての人(CHARおよびVARCHARについて)は、この回答で言及されているリンクを読んでください。ありがとう!
Pascal

14

サイズは性能です!サイズが小さいほど良いです。今日や明日ではありませんが、設計がどのようなものであっても、深刻なボトルネックになると、いつかテーブルが大きくなることがあります。ただし、最初に発生する可能性が高い設計フェーズでの潜在的なボトルネックの一部を予測し、サーバーを追加してスキームを再考するか、水平方向にスケーリングする必要があるまで、dbが高速かつ幸福に実行される時間を拡大しようとすることができます。

あなたの場合、遭遇する可能性のある多くのパフォーマンスリークがあります:大きな結合は長いvarchar列ではほとんど不可能です。それらの列のインデックス作成は本当にキラーです。ディスクにはデータを保存する必要があります。1つのメモリページはより少ない行を保持でき、テーブルスキャンははるかに遅くなります。また、クエリキャッシュはここでは役に立ちません。

あなたは自分自身に問いかける必要があります:年間何回の挿入が発生するのでしょうか?平均の長さは?最大長をユーザーに通知しても、実際に200文字以上必要ですか、それともアプリケーションのフロントエンドでそれをキャッチできますか?インデックス作成とスキャンを高速化するためにテーブルを狭いテーブルに分割し、拡張サイズのそれほど頻繁に必要とされない追加のデータを保持するために別のテーブルに分割できますか?可能なvarcharデータをカテゴリに入力して、一部のデータをいくつかの小さな、おそらくintまたはboolタイプの列に抽出し、そのようにvarchar列を絞り込めますか?

ここでたくさんすることができます。最初の仮定で行って、実際の測定されたパフォーマンスデータを使用して段階的に再設計するのが最善の場合があります。幸運を。


+1は、設計オプションの一覧表示と影響の調査に使用します。私の質問にも非常に役立ちます。 stackoverflow.com/q/12083089/181638
Assad Ebrahim

5
最大長を高く設定することによる実際のパフォーマンスへの影響はありますか、またはパフォーマンスは実際のサイズによって決まりますか?
poolie 2013年

5

パフォーマンス?いいえ、ディスクストレージですか。はい、しかしそれは安くて豊富です。データベースがテラバイト規模に成長しない限り、おそらく大丈夫です。


この回答が投稿されてから6年後に反対投票され、他の誰もそうではなかったのは奇妙でした。独裁的でささいなことのようです。この答えに間違いはありません。モデレーター?
duffymo 2016

1
言われたように、それはパフォーマンスに影響を与えます。また、ディスクストレージも無料ではありません。列の幅が広いほど、ディスクの読み取り/書き込みが多くなり(ディスクへのアクセスが遅くなる)、インデックスも広くなるため、その有用性が低下します。どちらもパフォーマンスに悪影響を及ぼします。小さなデータベースではそれは無視できるかもしれませんが、ギガバイト/テラバイトの規模では、あなたが言うように、それは確かに重要です。100レジスタテーブルの場合、それは重要ではありません。
アレハンドロ

5

一部のユーザーはvarchar(200)、ディスク上のテーブルサイズがのテーブルサイズよりも大きいと誤解していますvarchar(20)。これはそうではありません。mysqlが255文字を超えた場合にのみ、mysqlは追加のバイトを使用してvarcharフィールドデータの長さを決定します。


9
一時テーブルとMEMORYテーブルではそうではありません。
オービットの軽さのレース

4
選択クエリが一時テーブル(とりわけ、グループ化と順序による操作)を使用する場合は常に、varchar(200)をchar(200)に変換し、パフォーマンスが低下します。
ジェイミー

1

パフォーマンスに影響が出る可能性がありますが、通常、ほとんどのユーザーが気付くレベルではありません。

各フィールドのサイズが事前にわかっている場合、MySQLは各フィールド/行の間にあるバイト数を正確に認識し、すべてのデータを読み取らずにページを転送できます。可変文字を使用すると、この最適化機能が低下します。

varcharはデータの断片化が原因でパフォーマンスに影響しますか?

さらに良いのは、charとvarcharです。

ほとんどの用途ではどちらでもかまいません、違いがあり、大規模なデータベースでどちらか一方を選択する理由があります。


0

charだけでなくvarcharであるため、サイズは、実際の長さと文字列自体を示す内部フィールドに基づいています。したがって、varchar(200)を使用することは、varchar(150)を使用することとそれほど変わりませんが、さらに多くを格納する可能性があります。

そして、行が大きくなると、更新で何が起こるかを考慮する必要があります。しかし、これがまれな場合は、大丈夫です。


0

データ型名からわかるように、これはVARCHAR、つまり可変文字データストレージです。mysqlエンジン自体が、格納されているデータに従って使用中のメモリを割り当てるため、私の知る限りパフォーマンスに影響はありません。


0

ほとんどのシナリオでchar列と同じようにvarchar列を表示し、長さを控えめに設定する必要があります。var修飾子を、最大長の決定に影響を与えるものと常に考える必要はありません。提供される文字列の長さがさまざまであることは、実際にはパフォーマンスのヒントと見なすべきです。

これは、データベース内部が厳密に続く必要があるディレクティブではなく、完全に無視できます。ただし、理想的な世界ではないはずの実装がリークする可能性があるため(固定長やパディングなど)、これには注意してください。

varchar(255)を使用している場合、すべての状況において、パフォーマンスの点で常にchar(255)とは異なる動作をするという保証はありません。

ストレージ要件についてのマニュアルのアドバイスに従って、255、65535などにインラインで設定するのは簡単に思えるかもしれません。これは、0(はい、事柄です)と255の間の任意の値が同じ影響を与えるという印象を与えます。ただし、これは完全に保証できるものではありません。

ストレージ要件は、行ストレージの観点から、まともな、または成熟した永続ストレージエンジンの適切な指標となる傾向があります。インデックスなどの指標としてはそれほど強力ではありません。

これは難しい質問になる場合があります。文字列がどれくらいの長さである必要があるかを正確に設定します。そのため、文字列が含まれるはずの上限に設定すると、影響はありません。残念ながら、これは多くの場合、解決するためにユーザーに残されたものであり、実際にはいくぶん恣意的です。正確にわからない場合もあるので、実際には文字列のサイズを大きくしないとは言えません。

文字列が切り捨てられるのではなく長すぎる場合、MySQLクエリがエラーをスローするようにして、少なくともエラーエミッションから文字列が短すぎるかどうかを確認する必要があります。列を拡大または縮小するために列のサイズを変更すると、費用のかかるDDL操作になる可能性があります。これは覚えておく必要があります。

文字セットは、長さとパフォーマンスが関係する場所でも考慮する必要があります。長さはバイトではなくこれを参照します。たとえばMB4ではなくutf8を使用している場合、varchar(255)は実際にはvarbinary(3 * 255)です。テストを実行したり、ソースコードやドキュメントを深く調べたりしないと、このようなことが実際にどのように行われるかを知ることは困難です。このため、予想外に膨らんだ影響を与える過度な長さの余地があります。これはパフォーマンスだけに当てはまるわけではありません。ある日、varcharカラムの文字セットをより大きな文字セットに変更する必要がある場合、無理に長い文字列を存在させて回避できたとしたら、頼りなく制限に達する可能性があります。これは通常、かなりニッチな問題ですが、実際に発生します。

MAX(LENGTH(column))が常に<64であることが判明した場合(たとえば、列の定義と一致しない入力に制限があると判断された場合)、varchar(255)がある場合、一部のシナリオで必要なスペースの4倍のスペースを使用する可能性が高いです。

これには以下が含まれます。

  • エンジンが異なると、完全に無視される場合があります。
  • 更新や挿入などのバッファーサイズでは、255全体を割り当てる必要がある場合があります(これを証明するためにソースコードをチェックしていませんが、これは仮説にすぎません)。
  • インデックス。多数のvarchar(255)列から複合キーを作成しようとすると、これはすぐにわかります。
  • 中間テーブルと結果セット。トランザクションが機能する方法を考えると、定義された制限とは対照的に、何かが列内の文字列の実際の最大長を使用することが常に可能であるとは限りません。
  • 内部予測最適化では、最大長を入力として使用する場合があります。
  • データベース実装バージョンの変更。

経験則として、とにかくvarcharを必要以上に長くする必要はありません。パフォーマンスの問題かどうかに関係なく、可能であればそれを守ることをお勧めします。データのサイズをサンプリングし、真の制限を適用するか、質問/調査を通じて真の制限を見つけるためにより多くの努力を払うことが理想的なアプローチです。

できない場合は、疑わしい場合にvarchar(255)などを実行したい場合は、科学を実行することをお勧めします。これは、テーブルを複製し、var char列のサイズを小さくしてから、データを元のテーブルからコピーして、インデックス/行データのサイズを調べることで構成される場合があります(列にもインデックスを付け、主キーとしても試してください)。行が主キーによって順序付けられるため、InnoDBでは動作が異なる場合があります)。少なくともこの方法で、最も敏感なボトルネックの1つになりがちなIOに影響があるかどうかがわかります。メモリ使用量のテストはより難しく、徹底的にテストすることは困難です。潜在的な最悪のケースをテストすることをお勧めします(メモリ内の中間結果が多いクエリ、大きな一時テーブルの説明で確認するなど)。

テーブルに多くの行がないことがわかっている場合は、その列を結合、インデックス(特に複合、一意)などに使用しないので、多くの問題は発生しません。

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