web-dev-qa-db-ja.com

SQL varchar列の長さに関するベストプラクティス

新しいSQLテーブルを設定したり、既存のテーブルに新しいvarcharカラムを追加するたびに、1つ不思議に思います。lengthに最適な値は何ですか。

それでは、name型のvarcharという列があるとしましょう。だから、あなたは長さを選ぶ必要があります。私は20文字以上の名前を考えることはできませんが、あなたは決して知りません。しかし、20を使用する代わりに、次の2 ^ nの数に常に切り上げます。この場合、長さとして32を選択します。コンピューター科学者の観点からすると、2 ^ nという数字は他の数字よりもevenに見えるので、その下にあるアーキテクチャーが他の数字よりもわずかに優れていると想定しているだけです。

一方、たとえばMSSQLサーバーは、varchar列を作成することを選択した場合、デフォルトの長さの値を50に設定します。それは私がそれについて考えさせます。なぜ50?それは単なる乱数なのか、それとも平均的な列の長さに基づいているのか、それとも何ですか。

また、(MySQL、MSSQL、Postgresなどの)SQLサーバーの実装ごとに異なる最善列長の値がある可能性もあります。

253
esskar

私が知っているDBMSには、2^nの長さのVARCHARが2のべき乗ではないmaxの長さのものよりもパフォーマンスが良くなるような「最適化」はありません。

SQL Serverの初期のバージョンでは、実際には長さが255のVARCHARは、最大長が長いものとは異なる方法で扱われていました。これがまだそうであるかどうか私は知りません。

ほとんどすべてのDBMSでは、必要な実際の記憶域は、定義したmaxの長さではなく、入力した文字数によってのみ決まります。そのため、ストレージの観点から(そしておそらくパフォーマンスの観点からも)、カラムをVARCHAR(100)として宣言してもVARCHAR(500)として宣言しても違いはありません。

max列に提供されるVARCHARの長さは、技術的/物理的なものではなく、一種の制約(またはビジネスルール)として示されるはずです。

PostgreSQLの場合、最善の設定は、長さの制限なしにtextを使用し、文字数をビジネスに必要なものに制限するCHECK CONSTRAINTを使用することです。

その要件が変更された場合、チェック制約を変更する方がテーブルを変更するよりもはるかに高速です(テーブルを書き換える必要がないため)。

同じことがOracleなどにも当てはまります。Oracleでは、textではなくVARCHAR(4000)になります。

VARCHAR(max)と例えばの間に物理的なストレージの違いがあるかどうかわかりません。 SQL ServerのVARCHAR(500)。しかし、どうやらvarchar(max)を使用した場合、varchar(8000)と比較してパフォーマンスへの影響があります。

このリンクを見る (コメントとしてErwin Brandstetterによって投稿された)

編集2013-09-22

Bigownのコメントについて:

Postgres 9.2より前のバージョン(私が最初の答えを書いたときには利用できませんでした)では、カラム定義の変更didテーブル全体を書き換えます。 ここに 。 9.2以降、これはもはや当てはまりません。1.2百万行のテーブルの列サイズを大きくしても0.5秒しかかからないことがクイックテストで確認されました。

Oracleにとっても、大きなテーブルのvarcharカラムを変更するのにかかる時間で判断すると、これは真実のようです。しかし、私はそのための参照を見つけることができませんでした。

MySQLの場合 このマニュアルには "と書かれています。ほとんどの場合、ALTER TABLEは元のテーブルの一時コピーを作成します。そして私自身のテストでは以下のことが確認されました。120万行のテーブルでALTER TABLEを実行して(Postgresでのテストと同じ)、列のサイズを増やすには1.5分かかりました。しかしMySQLでは、notチェック制約を使用して列内の文字数を制限するために「回避策」を使用できます。

SQL Serverの場合、これについて明確なステートメントを見つけることができませんでしたが、varchar列のサイズを増やすための実行時間(ここでも上から120万行のテーブル)は、norewriteを示します。起こる。

編集2017-01-24

私は(少なくとも部分的に)SQL Serverについて間違っていたようです。 Aaron Bertrandによるこの回答 を参照してください。これは、nvarcharまたはvarcharカラムの宣言された長さがパフォーマンスに大きな影響を与えることを示しています。

212

VARCHAR(255)VARCHAR(2)は、正確にディスク上の同じ容量を使用します。それでそれを制限する唯一の理由はあなたがそれをより小さくするための特別な必要性があるならばです。それ以外の場合は、それらすべてを255にします。

具体的には、ソートを行うとき、大きな列はより多くのスペースを取ります。そのため、パフォーマンスが低下する場合は、心配してサイズを小さくする必要があります。しかし、そのテーブルから1行しか選択しないのであれば、それらをすべて255にすることができれば問題ありません。

参照: MySQLに最適なvarcharのサイズは?

57
Ariel

新しいSQLテーブルを設定するときはいつでも、2 ^ nが「偶数」であることと同じように感じますが、ここで答えをまとめると、単にvarchar(2 ^ n)を定義するだけでストレージスペースに大きな影響はありません。あるいはvarchar(MAX)でも構いません。

そうは言っても、varchar()の上限を高く設定する場合は、ストレージとパフォーマンスに潜在的な影響があると考えてください。たとえば、フルテキストインデックスで製品の説明を保持するためのvarchar(MAX)列を作成したとします。説明の99%の長さが500文字しかない場合に、突然その説明をWikipediaの記事に置き換えた人が見つかると、予期せぬ重大なストレージとパフォーマンスの低下に気付くことがあります。

Bill Karwinから考えるべきもう1つのこと

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

基本的には、わずかに大きいサイズで妥当なビジネス上の制約とエラーを考え出すだけです。 @oneaywhenが指摘したように、英国の姓は通常1〜35文字です。あなたがそれをvarchar(64)にすることに決めたとしても、本当に何かを傷つけることはないでしょう... この男の姓を格納していない限り 最大666文字の長さと言われています。その場合は、おそらくvarchar(1028)の方が理にかなっています。

そして、役に立つ場合には、varchar 2 ^ 5から2 ^ 10までが満たされているとします。

varchar(32)     Lorem ipsum dolor sit amet amet.

varchar(64)     Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie

varchar(128)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas

varchar(256)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt

varchar(512)    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie

varchar(1024)   Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donecie
                vestibulum massa. Nullam dignissim elementum molestie. Vehiculas
                velit metus, sit amet tristique purus condimentum eleifend. Quis
                que mollis magna vel massa malesuada bibendum. Proinde tincidunt
                dolor tellus, sit amet porta neque varius vitae. Seduse molestie
                lacus id lacinia tempus. Vestibulum accumsan facilisis lorem, et
                mollis diam pretium gravida. In facilisis vitae tortor id vulput
                ate. Proin ornare arcu in sollicitudin pharetra. Crasti molestie
                dapibus leo lobortis eleifend. Vivamus vitae diam turpis. Vivamu
                nec tristique magna, vel tincidunt diam. Maecenas elementum semi
                quam. In ut est porttitor, sagittis nulla id, fermentum turpist.
                Curabitur pretium nibh a imperdiet cursus. Sed at vulputate este
                proin fermentum pretium justo, ac malesuada eros et Pellentesque
                vulputate hendrerit molestie. Aenean imperdiet a enim at finibus
                fusce ut ullamcorper risus, a cursus massa. Nunc non dapibus vel
                Lorem ipsum dolor sit amet, consectetur Praesent ut ultrices sit
36
Kit

最善の価値は、基礎となるドメインで定義されているデータに適したものです。

一部のドメインでは、VARCHAR(10)Name属性に適しています。他のドメインでは、VARCHAR(255)が最良の選択かもしれません。

30
Oded

A_horse_with_no_nameの回答に追加すると、次のような興味深い情報が見つかるかもしれません。

列をVARCHAR(100)として宣言してもVACHAR(500)として宣言しても、違いはありません。

-- try to create a table with max varchar length
drop table if exists foo;
create table foo(name varchar(65535) not null)engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length - 2 bytes for the length
drop table if exists foo;
create table foo(name varchar(65533) not null)engine=innodb;

Executed Successfully

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65533))engine=innodb;

MySQL Database Error: Row size too large.

-- try to create a table with max varchar length with nullable field
drop table if exists foo;
create table foo(name varchar(65532))engine=innodb;

Executed Successfully

長さバイトとNULL可能バイトを忘れないでください。

name varchar(100) not nullは1バイト(長さ)+最大100文字(latin1)になります

name varchar(500) not nullは2バイト(長さ)+最大500文字です(latin1)

name varchar(65533) not nullは2バイト(長さ)+最大65533文字(latin1)になります

name varchar(65532)は2バイト(長さ)+最大65532文字(latin1)+ 1ヌルバイトになります

お役に立てれば :)

14
Jon Black

常にビジネスドメインの専門家に確認してください。もしそうなら、業界標準を探してください。たとえば、問題のドメインが自然人の姓(姓)である場合、イギリスのビジネスの場合、個人情報については イギリスGovtalkデータ標準カタログ そして姓が1から35文字の間であることを発見しなさい。

5
onedaywhen

私は最近これをチェックしていませんが、JDBCドライバが結果セットを返すためにクエリの実行中にメモリのチャンクを予約することをOracleと過去に知っていました。メモリチャンクのサイズはカラムの定義とフェッチサイズに依存します。そのため、varchar2列の長さはメモリの予約量に影響します。私たちは常にvarchar2(4000)(当時の最大値)を使用していたため、これは私にとって何年も前に深刻なパフォーマンス問題を引き起こしました。

3
user1041892