すべてのテキストベースのフィールドに汎用のvarchar(255)を使用することには欠点がありますか?


100

私が持っているcontactsようなフィールドを含むテーブルをpostcodefirst namelast nametowncountryphone numberなど、のように定義されているすべてのそれらのVARCHAR(255)も、これらの分野のどれもが今までに近い255個の文字を有することに来ないだろうけれども。(不思議に思っているのは、Ruby on RailsのマイグレーションVARCHAR(255)がデフォルトでStringフィールドをマッピングし、私がそれをオーバーライドすることを決してしなかったからです)。

VARCHARのみ(フィールド長と共に)フィールドの実際の文字の数を格納するため、たとえば、使用する任意の明確な利点(性能又はその他)があるVARCHAR(16)上にVARCHAR(255)

さらに、これらのフィールドのほとんどにはインデックスがあります。フィールドのVARCHARサイズが大きくなると、インデックスのサイズやパフォーマンスに影響がありますか?

参考までに、MySQL 5を使用しています。


2
@ceejayoz、受け入れられた答えが正しくないことを述べ、理由が実際には役に立たない さらに悪いことに、受け入れられた回答は時間とともに変化する可能性があり、あなたのコメントは新しい受け入れられた回答が間違っていると人々を混乱させるでしょう。
Gili

1
OPの受け入れが明らかに変わったため、@ Giliは私のコメントを削除しました。良い点は、将来私が話している答えとその理由を示すことです。
ceejayoz、2011年

この重複した質問での他のいくつかの回答、stackoverflow.com
James McMahon

回答:


129

ストレージでVARCHAR(255)は、CHAR(255)常に255文字を格納するのとは異なり、特定の行に必要な長さのみを格納するのに十分スマートです。

しかし、この質問にMySQLのタグを付けたので、MySQL固有のヒントに言及します。行がストレージエンジンレイヤーからSQLレイヤーにコピーされると、VARCHARフィールドが変換されCHARて固定幅の行を処理する利点が得られます。したがって、メモリ内の文字列は、宣言された列の最大長まで埋め込まれVARCHARます。

クエリが暗黙的に一時テーブルを生成する場合、たとえば、ソート中または中にGROUP BY、これは大量のメモリを使用する可能性があります。VARCHAR(255)それほど長くする必要のない多くのフィールドをデータに使用すると、一時テーブルが非常に大きくなる可能性があります。

また、この「パディングアウト」動作は、utf8文字セットで宣言された文字列が、シングルバイトコンテンツ(たとえば、ASCIIまたはlatin1文字)で格納されている文字列であっても、1文字あたり3バイトにパディングすることを意味します。同様に、utf8mb4文字セットは、文字列をメモリ内の文字ごとに4バイトまで埋め込みます。

したがって、VARCHAR(255)「意見なし」のような短い文字列を格納するutf8のa は、ディスクで11バイト(10文字の下位文字セット文字と長さとして1バイト)を必要としますが、メモリ、したがって一時テーブルまたはソート結果で765バイトを使用します。

私は無意識のうちに1.5 GBの一時テーブルを頻繁に作成し、ディスク領域をいっぱいにしたMySQLユーザーを支援しました。VARCHAR(255)実際には非常に短い文字列を格納する列がたくさんありました。

保存するデータのタイプに基づいて列を定義するのが最善です。他の人々が述べたように、アプリケーション関連の制約を強制することには利点があります。しかし、上記で説明したメモリの浪費を回避することには物理的な利点があります。

もちろん、最長の住所が何であるかを知ることは困難です。そのため、多くの人VARCHARがどの住所よりも長いlong を選択するのはそのためです。また、255はVARCHAR長さが1バイトでエンコードできるaの最大長であるため、通例です。またVARCHAR、5.0より古いMySQL の最大長でもありました。


6
255文字列の長さが1バイトに収まるように使用されていたといつも思っていました
BlueRaja-Danny Pflughoeft

3
@BlueRaja:内部ファイル構造が文字列の長さを1バイトでエンコードするデータベースや、短い文字列を1バイトでエンコードするデータベースの場合は、おそらくそれが当てはまりました。しかし、ほとんどのデータベースには当てはまりません。
ビルカーウィン、2011

7
@BlueRaja:InnoDBは次のvarcharの長さを格納せず、行内のすべてのフィールドの一連のフィールドオフセットを格納します。これらのフィールドオフセットは、行の合計サイズが127バイト未満の場合は1バイト、そうでない場合は2バイトです。forge.mysql.com/wiki/MySQL_Internals_InnoDBを
Bill Karwin

6
@BlueRaja:MyISAM(まだ使用している人向け)はvarcharの長さを格納し、これらは1バイトまたは2バイトで格納できます。ただし、「index_read()またはrecords_in_rangeのハンドラーにキーを送信するときは、VARCHARに常に2バイトの長さを使用して物事を簡素化しています。forge.mysql.com/wiki/MySQL_Internals_MyISAMを
Bill Karwin

1
1つの質問-任意のフィールドまたはvarcharフィールド自体でソートおよびグループ化しますか?
Rohit Banga

24

varcharのサイズを設定する際のサイズとパフォーマンスに関する考慮事項に加えて(ストレージと処理が毎秒安くなるため、より重要になる可能性があります)、データの整合性が低下するという理由だけでvarchar(255)を使用することの欠点があります

文字列の最大制限を定義することは、予想より長い文字列がRDBMSに入り、後で予想より長い(より多くのバイト)データベースから値を取得して解析するときに、バッファオーバーランまたは例外/エラーが発生するのを防ぐために行うことをお勧めします。

たとえば、国の省略形の2文字の文字列を受け入れるフィールドがある場合、ユーザー(このコンテキストではプログラマ)が完全な国名を入力することを期待する理由は考えられません。「アンティグアバーブーダ」(AG)または「ハード島とマクドナルド島」(HM)を入力したくないので、データベースレイヤーでは入力できません。また、一部のプログラマーは、設計ドキュメント(確かに存在する)をまだRTFM しておらず、これを行わないことを知っている可能性があります。

2文字を受け入れるようにフィールドを設定し、RDBMSがそれを処理できるようにします(切り捨てによって適切に処理されるか、エラーでSQLを拒否することによって適切に処理されません)。

特定の長さを超える理由がない実際のデータの例:

  • カナダの郵便番号の形式はA1A1A1で、サンタクロースの場合でも常に6文字です(6文字は読みやすくするために指定できるスペースを除きます)。
  • メールアドレス -@の前に最大64バイト、その後に最大255バイト。インターネットを壊さないようにしてください。
  • 北米の電話番号は10桁を超えてはなりません(国コードを除く)。
  • Windows(の最新バージョン)を実行しているコンピューターは、63バイトを超えるコンピューター名を持つことはできませんが、15を超えることは推奨されておらず、Windows NTサーバーファームを破壊します。
  • 州の略称は2文字です(上記の国コードのように)
  • UPSの追跡番号は、18、12、11、または9文字の長さです。18文字の数字は「1Z」で始まり、11文字の数字は「T」で始まります。これは、文字と数字の違いがわからない場合に、それらすべてのパッケージをどのように配送するのか不思議に思うことを意味します。

等々...

時間をかけてデータとその制限について考えてください。建築家、開発者、またはプログラマーであれば、結局のところ、それがあなたの仕事です。

varchar(255)の代わりにvarchar(n)を使用することで、ユーザー(エンドユーザー、プログラマー、他のプログラム)が予期せぬ長いデータ入力して、後でコードを悩ませる問題を排除できます。

また、アプリケーションで使用されるビジネスロジックコードにもこの制限を実装しないでください。


5
カナダの郵便番号は実際には7桁で、中央のスペースは重要であり、宛名ラベルに表示する必要があります。北アメリカの電話番号は、拡張がある場合、10桁を超えることがあります。電話番号の内線番号を保存できない場合は、10桁で問題ありませんが、おそらく後悔するでしょう。
Kibbee

3
データの整合性を制限する場合は間違いなくあります。ただし、制限が厳しすぎることは依然として簡単です。管理するデータに制限を課し、管理できないデータ要件に適切な制限を課します。あなたの電話番号と電子メールの制限は正気です(あなたが国際化しないことを前提としています)。2文字の国コードを切り捨てることが「優雅な」ことであるというあなたの要件は狂気です。あなたはエラーがあったことを知っています、切り詰めて受け入れないでください。切り捨てると、非常に高い確率で国コードが正しくなくなります。
coderjoe 2009年

ほとんどのアプリケーションでは、データベースに送信する前にデータの検証が行われます...
Cobby

2
承知しました。最も。しかし、ここでは、既存のデータベースの新しいアプリケーションを開発している開発者がデータの制限を認識していると想定しているように思います(私たちはすべてのタイプのデータの専門家ではなく、どのようにすべてのデータベースにデータを実装するかを知っているわけではありません) )。アプリケーションでデータを検証できるからといって、そうしたわけではありません。
シャフラー

3
the design documentation (which surely exists)ああ。:D
カミロマーティン

14

同感です。細部へのうるさい注意は首の痛みであり、価値が限られています。

むかしむかし、ディスクは貴重な商品であり、私たちはそれを最適化するために弾丸を発汗させていました。ストレージの価格が1,000分の1に下がったため、すべてのバイトをスクイーズするために費やされる時間の価値が下がりました。

CHARフィールドのみを使用すると、固定長の行を取得できます。これにより、フィールドに正確なサイズを選択した場合、ディスクの再設定を節約できます。より密にパックされたデータ(テーブルスキャンのI / Oが少ない)と高速な更新(更新と挿入のためにブロック内のオープンスペースを見つけるのが簡単)が得られる場合があります。

ただし、サイズを過大に見積もったり、実際のデータサイズが可変である場合は、CHARフィールドでスペースを浪費することになります。データは密集せずに巻き上げられます(大きな検索のI / Oが多くなります)。

一般に、可変フィールドにサイズを設定しようとすることによるパフォーマンス上のメリットはわずかです。VARCHAR(255)をCHAR(x)と比較することで簡単にベンチマークを行い、違いを測定できるかどうかを確認できます。

ただし、「小」、「中」、「大」のヒントを提供する必要がある場合があります。したがって、サイズには16、64、255を使用します。


13

今日、それが本当に重要であるとは想像できません。

可変長フィールドを使用すると計算オーバーヘッドが発生しますが、今日のCPUが過剰であるため、検討する価値すらありません。I / Oシステムは非常に遅いため、varcharを効果的に処理するための計算コストが存在しません。実際、varcharの価格は、計算上、固定長フィールドではなく可変長フィールドを使用することで節約されるディスク容量の量を上回ります。行密度が高い可能性があります。

現在、varcharフィールドの複雑さは、レコード番号を介してレコードを簡単に見つけることができないことです。(フィールドが固定長の)固定長の行サイズがある場合、行IDが指すディスクブロックを計算するのは簡単です。可変長の行サイズを使用すると、その種類はウィンドウの外に出ます。

したがって、他の主キーと同様に、ある種のレコード番号インデックスを維持する必要があります。または、詳細(ブロックなど)を識別子にエンコードする堅牢な行識別子を作成する必要があります。ただし、その場合、行が永続ストレージに移動されると、IDを再計算する必要があります。大したことではありません。すべてのインデックスエントリを書き直して、a)それをコンシューマに公開しないか、b)数値が信頼できると断言しないようにしてください。

しかし、今日はvarcharフィールドがあるため、varchar(255)に対するvarchar(16)の唯一の値は、DBがvarchar(16)に16文字の制限を適用することです。DBモデルが実際に物理データモデルを表すと想定されている場合、フィールド長があると価値があります。ただし、「モデルとストレージ」ではなく、単に「ストレージ」の場合は、何も必要ありません。

次に、インデックス付けが可能なテキストフィールド(varcharなど)とそうでないもの(テキストフィールドやCLOBフィールドなど)を区別する必要があります。インデックス付け可能なフィールドは、インデックスを容易にするためにサイズに制限がある傾向がありますが、CLOBフィールドは(理由の範囲内で)制限されません。


5

私の経験では、255文字のデータ型を許可すると、一部の愚かなユーザー(または一部の経験豊富なテスター)が実際にデータを埋めてしまいます。

次に、レポートのフィールドやアプリケーションの画面表示にどのくらいのスペースを確保できるかなど、あらゆる種類の問題が発生します。データベース内のデータの行ごとの制限を超える可能性があることは言うまでもありません(これらの255文字のフィールドがいくつかある場合)。

最初に適切な制限を選択する方がはるかに簡単で、アプリケーションとデータベースを介してそれを強制します。


0

必要なものに少しだけ割り当てることをお勧めします。電話番号がこれほど大きくなることは決してありません。

1つの理由は、大きなエントリに対して検証しない限り、間違いなく誰かがすべてを使用することです。次に、行のスペースが不足する可能性があります。MySQLの制限についてはわかりませんが、MS SQLの最大行サイズは8060です。

より通常のデフォルトは50 imhoであり、必要性が証明するところで増加します。


ありがとう。私はそれが良い習慣であることについては間違いなく同意します。それは私が明確にしたいパフォーマンスの側面です
Olly

0

mysqlには最大値があるため、mysqlコンテキストでは、上記のvarchar列のインデックスを操作するときに重要になる可能性があります。インデックス行あたり767バイトの制限。

これは、いくつかのvarchar 255列にインデックスを追加すると、上記の回答で指摘されているように、utf8またはutf8mb4列でこの制限にかなり速く/さらに速く到達できることを意味します

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