SQL で VARCHAR ではなく CHAR を選択するユースケースは何ですか?

StackOverflow https://stackoverflow.com/questions/59667

  •  09-06-2019
  •  | 
  •  

質問

すべての値が固定幅の場合、CHAR が推奨されることがわかりました。でも、だから何?安全のために、すべてのテキストフィールドに VARCHAR を選択してみてはいかがでしょうか。

役に立ちましたか?

解決

一般的に選ぶ チャー すべての行が 同じ長さ. 。選ぶ VARCHAR いつ 長さは異なります 大幅。CHAR はすべての行が同じ長さであるため、少し高速になる場合もあります。

DB 実装によって異なりますが、通常、VARCHAR は実際のデータに加えて、さらに 1 バイトまたは 2 バイトのストレージ (長さまたは終了用) を使用します。したがって、(1バイト文字セットを使用していると仮定して)「FooBar」という単語を保存します。

  • CHAR(6) = 6 バイト (オーバーヘッドなし)
  • VARCHAR(10) = 8 バイト (2 バイトのオーバーヘッド)
  • CHAR(10) = 10 バイト (4 バイトのオーバーヘッド)

結論は チャー できる もっと早く もっと スペース効率の良い 比較的同じ長さのデータ (長さの差が 2 文字以内) の場合。

注記:Microsoft SQL には、VARCHAR に対して 2 バイトのオーバーヘッドがあります。これは DB によって異なる場合がありますが、一般に、VARCHAR の長さまたは EOL を示すために少なくとも 1 バイトのオーバーヘッドが必要です。

コメントで Gaven が指摘したように、UTF8 のようなマルチバイトの可変長文字セットを使用している場合、CHAR は文字数を格納するのに必要な最大バイト数を格納します。したがって、UTF8 が文字を格納するために最大 3 バイトを必要とする場合、たとえ latin1 文字のみを格納する場合でも、CHAR(6) は 18 バイトに固定されます。したがって、この場合、VARCHAR がより良い選択肢になります。

他のヒント

あなたが私と一緒に仕事をしていて、Oracle と仕事をしているなら、私はおそらくあなたに次のものを使用させるでしょう。 varchar ほぼあらゆる状況で。という仮定 char よりも少ない処理能力を使用します varchar それは真実かもしれません...今のところ...しかし、データベース エンジンは時間の経過とともに改良されており、この種の一般規則は将来の「神話」を生み出す可能性があります。

別物:誰かがこれを使用することに決めたためにパフォーマンスの問題が発生したことは一度もありません varchar. 。優れたコード (データベースへの呼び出しが少なくなる) と効率的な SQL (インデックスがどのように機能するか、オプティマイザーがどのように意思決定を行うか、なぜ exists よりも速い in いつもの...)。

最終的な考え:の使用に関するあらゆる種類の問題を見てきました CHAR, 、' ' を探すべきときに ' を探している人、または 'FOO (スペースの束)' を探すべきときに 'FOO' を探している人、または末尾の空白をトリミングしていない人、または Powerbuilder のバグOracle プロシージャから返される値には最大 2000 個の空白が追加されます。

パフォーマンス上の利点に加えて、 CHAR すべての値を示すために使用できます。 すべき 同じ長さであること (例: 米国の列)状態の略語。

Char の方が少し速いため、特定の長さになることがわかっている列がある場合は、char を使用してください。たとえば、性別については (M)ale/(F)emale/(U)nknown、または米国の州については 2 文字を保存します。

NChar または Char は、var の代替よりもパフォーマンスが優れていますか?

素晴らしい質問です。簡単な答えは、特定の状況では「はい」です。これが説明できるかどうか見てみましょう。

当然のことですが、varchar(255) の列 (この列を myColumn と呼びます) を持つテーブルを作成し、100 万行を挿入し、各行の myColumn に数文字だけを挿入すると、テーブルははるかに小さくなります (全体的に)。 myColumn を char(255) として作成した場合よりも、ストレージ エンジンが必要とするデータ ページの数)。そのテーブルで操作 (DML) を実行し、大量の行をリクエストするときは常に、myColumn が varchar の場合、その必要がないため高速になります。 動く 最後の「余分な」スペースをすべて囲みます。SQL Server が個別操作や結合操作中などの内部並べ替えを実行するとき、またはクエリ プラン中にマージを選択した場合などに移動します。移動とは、サーバーからローカル PC、別のコンピューター、またはデータが使用される場所にデータを取得するのにかかる時間を意味する場合もあります。

ただし、varchar を使用すると、ある程度のオーバーヘッドが発生します。SQL Server は、各行で、特定の行の myColumn に何バイトあるかを知るために、2 バイトのインジケーター (オーバーヘッド) を使用する必要があります。問題は余分な 2 バイトではなく、各行の myColumn 内のデータの長さを「デコード」する必要があることです。

私の経験では、クエリで結合される列には varchar ではなく char を使用するのが最も合理的です。たとえば、テーブルの主キーや、インデックスが作成される他の列などです。人口統計テーブルの CustomerNumber、デコード テーブルの CodeID、あるいは注文テーブルの OrderNumber。char を使用すると、クエリ エンジンは、ページを読み取るときにポインターを可変バイト量移動する必要がなく、直接ポインター演算 (決定論的) を実行できるため、より迅速に結合を実行できます。最後の一言であなたを失ったかも知れません。SQL Serverに参加すると、「Prendicates」のアイデアに基づいています。述語は状態です。たとえば、myColumn = 1、または OrderNumber < 500 です。

したがって、SQL Server が DML ステートメントを実行していて、結合される述語、つまり「キー」が固定長 (char) である場合、クエリ エンジンは、あるテーブルの行を別のテーブルの行と照合するためにそれほど多くの作業を行う必要はありません。別のテーブル。行内のデータの長さを調べて、文字列をたどって最後を見つける必要はありません。どれも時間がかかります。

ここで、これは簡単に実装が不十分になる可能性があることに留意してください。オンライン システムの主キー フィールドに char が使用されているのを見たことがあります。幅は小さく保つ必要があります。char(15) または適切なもの。また、通常は少数の行のみを取得または更新/挿入するため、オンライン システムで最も効果的に機能します。そのため、結果セットに含まれる末尾のスペースを「rtrim」する必要は、何百万もの行を結合する必要があるのとは対照的に簡単な作業です。あるテーブルの行を別のテーブルの数百万行に転送します。

オンライン システムでは CHAR が varchar よりも合理的であるもう 1 つの理由は、ページ分割が削減されることです。char を使用すると、基本的にそのスペースを「予約」する (そして無駄にする) ことになるため、後からユーザーがその列にさらにデータを追加した場合、SQL はすでにそのスペースを割り当てており、そこにデータが入ります。

CHAR を使用するもう 1 つの理由は 2 番目の理由と似ています。プログラマやユーザーが、たとえばメモ フィールドに文章を追加して数百万行の「バッチ」更新を行ったとしても、夜中に DBA からドライブがいっぱいになった理由を尋ねる電話を受けることはありません。言い換えれば、データベースのサイズの増大がより予測可能になるということです。

以上が、オンライン (OLTP) システムで varchar ではなく char のメリットを享受できる 3 つの方法です。ウェアハウス/分析/OLAP シナリオで char を使用することはほとんどありません。通常、大量のデータがあり、これらの char 列をすべて追加すると、多くの無駄なスペースが発生する可能性があるためです。

char を使用するとデータベースが大幅に大きくなる可能性がありますが、ほとんどのバックアップ ツールにはデータ圧縮があるため、バックアップのサイズは varchar を使用した場合とほぼ同じになる傾向があることに注意してください。たとえば、LiteSpeed や RedGate SQL Backup です。

もう 1 つの用途は、データを固定幅ファイルにエクスポートするために作成されたビューです。メインフレームで読み取るために、いくつかのデータをフラット ファイルにエクスポートする必要があるとします。固定幅(区切りなし)です。私は、データを「ステージング」テーブルに varchar として保存し (そのため、データベース上のスペースの消費が少なくなります)、ビューを使用して、すべてをその列の固定幅の幅に対応する長さの char に相当するものにキャストするのが好きです。 。例えば:

create table tblStagingTable (
pkID BIGINT (IDENTITY,1,1),
CustomerFirstName varchar(30),
CustomerLastName varchar(30),
CustomerCityStateZip varchar(100),
CustomerCurrentBalance money )

insert into tblStagingTable
(CustomerFirstName,CustomerLastName, CustomerCityStateZip) ('Joe','Blow','123 Main St Washington, MD 12345', 123.45)

create view vwStagingTable AS
SELECT CustomerFirstName = CAST(CustomerFirstName as CHAR(30)),
CustomerLastName = CAST(CustomerLastName as CHAR(30)),
CustomerCityStateZip = CAST(CustomerCityStateZip as CHAR(100)),
CustomerCurrentBalance = CAST(CAST(CustomerCurrentBalance as NUMERIC(9,2)) AS CHAR(10))

SELECT * from vwStagingTable

varchar を使用しているため、データが内部的に占有するスペースが少なくなるので、これは素晴らしいことです。しかし、DTS や SSIS を使用する場合、あるいは SSMS からメモ帳にカット アンド ペーストする場合でも、ビューを使用して適切な数の末尾のスペースを取得できます。DTS には、以前は「サジェスト列」か何かの名前だったと思うのですが、忘れました。SSIS では、それはもうできません。フラット ファイル接続マネージャーを面倒に定義する必要があります。ただし、ビューが設定されているため、SSIS は各列の幅を認識できるため、データ フロー タスクを構築するときに時間を大幅に節約できます。

結論から言えば…varchar を使用します。char を使用する理由は非常に少数ですが、パフォーマンス上の理由のみです。何億行ものシステムがある場合、述語が決定的 (char) であれば顕著な違いが見られますが、ほとんどのシステムでは char を使用することは単にスペースを無駄にしているだけです。

それが役立つことを願っています。ジェフ

パフォーマンス上の利点はありますが、言及されていない利点は次のとおりです。行の移行。char を使用すると、スペース全体を事前に予約します。つまり、char(1000) があり、10 文字を保存すると、1000 文字すべてのスペースを使い果たすことになります。varchar2(1000) では、10 文字のみを使用します。問題はデータを変更するときに発生します。列を更新して 900 文字が含まれるようになったとします。varchar を展開するためのスペースが現在のブロックにない可能性があります。その場合、DB エンジンは行を別のブロックに移行し、元のブロック内に新しいブロック内の新しい行へのポインターを作成する必要があります。このデータを読み取るには、DB エンジンは 2 ブロックを読み取る必要があります。
varchar と char のどちらが優れているかを明確に言える人はいません。特にデータが増大する可能性が高い場合には、時間のトレードオフや、データが更新されるかどうかを考慮する余地があります。

初期のパフォーマンスの最適化と、ベスト プラクティス タイプのルールの使用には違いがあります。常に固定長フィールドを持つ新しいテーブルを作成する場合は、CHAR を使用するのが合理的であり、その場合は CHAR を使用する必要があります。これは初期の最適化ではなく、経験則 (またはベスト プラクティス) の実装です。

つまり- 2 文字の状態フィールドがある場合は、CHAR(2) を使用します。実際の状態名を含むフィールドがある場合は、VARCHAR を使用します。

米国の州コードのような固定値を列に格納する場合を除き、私は varchar を選択します。これは常に 2 文字の長さであり、有効な米国の州コードのリストは頻繁に変更されません :)。

それ以外の場合は、ハッシュされたパスワード (固定長) を保存する場合でも、varchar を選択します。

理由 -- char 型の列は常にスペースで埋められ、列が作成されます。 私の列 比較内に値 'ABC' を持つ char(5) として定義されます。

my_column = 'ABC' -- my_column stores 'ABC  ' value which is different then 'ABC'

間違い。

これ 特徴 開発中に多くの迷惑なバグが発生する可能性があり、テストが困難になります。

フィールド内のすべてのデータ値が同じ長さの場合、CHAR は VARCHAR よりも占有する記憶領域が少なくなります。おそらく 2009 年現在、800 GB のデータベースは、VARCHAR を CHAR に変換した場合の 810 GB とまったく同じですが、短い文字列 (1 文字または 2 文字) の場合、CHAR は依然として業界の「ベスト プラクティス」であると私は言います。

ここで、整数だけでも、ほとんどのデータベースが提供するさまざまなデータ型 (bit、tiny、int、bigint) を見ると、どちらかを選択する理由があります。毎回 bigint を選択するだけでは、実際にはこのフィールドの目的と用途について少し無知であることになります。フィールドが単純に人の年齢を年単位で表す場合、bigint は過剰です。それは必ずしも「間違っている」わけではありませんが、効率的ではありません。

しかし、これは興味深い議論であり、データベースが時間の経過とともに改善されるにつれて、CHAR と VARCHAR の関連性が薄れると主張する可能性があります。

私はジム・マッキースのコメントを支持します。

また、テーブルに CHAR 列しかない場合、インデックス作成とテーブル全体のスキャンが高速になります。基本的に、オプティマイザは、CHAR 列しかない場合、各レコードの大きさを予測できますが、すべての VARCHAR 列のサイズ値をチェックする必要があります。

さらに、VARCHAR 列を以前の内容よりも大きいサイズに更新すると、データベースにインデックスの再構築を強制する可能性があります (データベースにディスク上のレコードを物理的に移動させるため)。CHAR 列の場合、そのようなことは決して起こりません。

ただし、テーブルが巨大でない限り、パフォーマンスへの影響はおそらく気にならないでしょう。

ジクストラの賢明な言葉を思い出してください。早期のパフォーマンス最適化が諸悪の根源です。

値の正確な長さがわかっている場合、CHAR を使用するといくつかの利点があると多くの人が指摘しています。しかし、現在、米国の州を CHAR(2) として保存するのは優れていますが、営業から「オーストラリアへの最初の販売を行ったところです」というメッセージを受け取ると、非常に苦痛になります。私は常に、将来のイベントに備えて「正確な」推測を行うのではなく、フィールドに必要な長さを過大評価するために送信します。VARCHAR を使用すると、この分野でより柔軟な対応が可能になります。

列値に実際に必要なサイズを計算し、Varchar にスペースを割り当てる際には、若干の処理オーバーヘッドが発生します。そのため、値が常にどのくらいの長さになるか確実にわかっている場合は、Char を使用してヒットを回避することをお勧めします。

これは、スペースとパフォーマンスの古典的なトレードオフです。

MS SQL 2005 では、Varchar (または 1 文字あたり 2 バイトを必要とする言語、つまり中国語の場合は NVarchar) は可変長です。ハードディスクに書き込まれた後に行に追加すると、データが元の行とは連続しない場所に配置され、データ ファイルの断片化が発生します。これはパフォーマンスに影響します。

したがって、スペースが問題にならない場合は、Char の方がパフォーマンスの点で優れていますが、データベースのサイズを抑えたい場合は、varchar の方が優れています。

あなたの場合、おそらく Varchar を選択しない理由はないと思います。これにより柔軟性が得られ、多くの回答者が言及したように、非常に特殊な状況を除いて、(Google DBA とは対照的に) 私たち凡人が違いに気付かないほどのパフォーマンスになっています。

DB タイプに関して注目に値する興味深い点は、sqlite (非常に優れたパフォーマンスを備えた人気のあるミニ データベース) がすべてを文字列としてデータベースに入れ、その場で型を作成することです。

私は常に VarChar を使用し、通常は厳密に必要なサイズよりもはるかに大きくします。例えば。あなたが言うように、安全のためだけではない理由は何ですか?

断片化。Char はスペースを予約しますが、VarChar は予約しません。varchar への更新に対応するためにページ分割が必要になる場合があります。

私は決して文字を使いません。私は多くの人とこの議論をしてきましたが、彼らはいつも char のほうが速いという使い古された決まり文句を持ち出します。さて、どれくらい速いでしょうか?ここで私たちが話しているのは何ですか、ミリ秒、秒、そしてもしそうなら何秒ですか?誰かが数ミリ秒速くなったと主張しているから、修正が難しいバグをシステムに大量に導入すべきだと言っているのでしょうか?

そこで、遭遇する可能性のあるいくつかの問題を次に示します。

すべてのフィールドがパディングされるため、あらゆる場所に RTRIMS が含まれるコードが永久に残ることになります。これは、長いフィールドにとっては膨大なディスク容量の無駄でもあります。

ここで、1 文字だけの char フィールドの典型的な例があるとしますが、このフィールドはオプションです。誰かがそのフィールドに空の文字列を渡すと、それは 1 つのスペースになります。したがって、別のアプリケーション/プロセスがクエリを実行すると、rtrim を使用しない場合、単一のスペースが取得されます。XML ドキュメント、ファイル、その他のプログラムでは、オプションのフィールドにスペースを 1 つだけ表示すると、内容が壊れてしまいます。

したがって、char フィールドに空の文字列ではなく null を渡していることを確認する必要があります。しかし、それは null の正しい使用法ではありません。ここでは null を使用します。ベンダーからファイルを入手したとします。

名前|性別|市区町村

ボブ||ロサンゼルス

性別が指定されていない場合は、テーブルに「Bob」、「空の文字列」、「Los Angeles」と入力します。ここで、ファイルを取得すると、その形式が変更され、性別が含まれなくなりましたが、過去には含まれていたとします。

名前|市区町村

ボブ|シアトル

さて、性別は含まれていないので、null を使用します。Varchar はこれを問題なくサポートします。

一方、シャアは違います。常に null を送信する必要があります。空の文字列を送信すると、フィールドにスペースが含まれることになります。

約 20 年間の開発の中で、文字から修正しなければならなかったすべてのバグを延々とやり続けることができました。

Varchar値を使用する場合、SQL Serverは1行あたり2バイトを追加する必要がありますその列に関する情報を保存するのは、charを使用する場合は必要ありません。

一部の SQL データベースでは、オフセットを最適化するために VARCHAR が最大サイズまでパディングされます。これは、テーブル全体のスキャンとインデックスを高速化するためです。

このため、VARCHAR(200) を使用した場合、CHAR(200) を使用した場合と比較してスペースは節約されません。

CHAR (NCHAR) と VARCHAR (NVARCHAR) を使用すると、データベース サーバーがデータを格納する方法に違いが生じます。最初のものは末尾の空白を導入します。SQL SERVER 関数で LIKE 演算子と一緒に使用すると問題が発生しました。したがって、常に VARCHAR (NVARCHAR) を使用して安全にする必要があります。

たとえば、テーブルがあるとします。 TEST(ID INT、ステータス CHAR(1)), そして、次のような特定の値を持つすべてのレコードをリストする関数を作成します。

CREATE FUNCTION List(@Status AS CHAR(1) = '')
RETURNS TABLE
AS
RETURN
SELECT * FROM TEST
WHERE Status LIKE '%' + @Status '%'

この関数では、デフォルトのパラメータを指定するとすべての行が返されることが期待されますが、実際にはそうではありません。@Status データ型を VARCHAR に変更すると、問題が解決します。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top