2011-02-02 12 views
19

私は最近仕事をしていたデータベースのVARCHAR(1)フィールドにたくさんぶつかってきました。私は目を転がした:明らかにデザイナーは手がかりを持っていなかった。しかし、私は何かを学ぶ必要があるかもしれません。 CHAR(1)ではなくVARCHAR(1)データ型を使用すると考えられる理由はありますか?私は、RDMSが自動的に一方を他方に変換すると思います。SQLデータ型VARCHAR(1)にANY SENSEはありますか?

データベースはMS SQL 2K5ですが、戻って一日でAccessから進化しました。

答えて

16

:yはLinq2SQLを使用した場合である)劣悪なデザイン推論、IMOを伝えます。

  • 言語で定義するのが簡単です。一貫性があり、varcharを定義して1-8000が2+または3+から8000になる必要があると言うよりも簡単です。

  • VARCHAR(1)のVARying CHARacterはまさにそれです。記憶には最適ではないかもしれないが、データがNULL(不明/未分類)の代わりに1文字(教室コード)または空白(外部活動)であるという特定の意味を伝える。

ストレージは、この非常に小さな役割を果たしている - CHARのデータベーススキーマを見て(1)、あなたはほとんどそれは常に、クレジットカードなど1つのchar値は、16桁の数字を持っている必要があります持っている必要があることを期待します。それは、1つのデータでも、オプションでもないデータでもそうではありません。

CHAR対VARCHAR(1)を使用しての違い(1)+トライステート[1-charを言う人のためのNULLの組み合わせもあります| 0-char | NULL]は完全に役に立たない。あなたが同じ情報を伝えるが、微妙な違いがあることができCHAR(1)+ NULLを、使用している場合はそうでない場合は、より困難であろう

select activity + '-' + classroom 
from ... 

:それはのようなSQL文が可能になります。

varchar(1)
+1

* VARCHAR(1)の実装を禁止する実装が本当に必要ないことはわかりますが、設計上のメリットがあるかどうか尋ねています。あなたの2番目の点については、明らかにするために、VARCHAR(1)は空の文字列にすることができますが、CHAR(1)はできません。わかります; CHAR(1)に対してVARCHAR(1)を選択する曖昧な理由ですが、おそらく有効なものです。 –

+0

"•言語で定義するのが簡単です。" - あなたは抹殺できますか? –

+0

「CASE WHEN '' = ''」が実際にTRUEになる特定のエッジケースでは微妙な反応があります。つまり、単一スペース=スペースなしですが、そのようなことを十分に認識する必要があります。オフラインでデータ型を無視するだけでは、それほどスマートではありません。 2つのポイントの後のテキストは、私が実際に見たより堅実な例を示しています。 – RichardTheKiwi

10

は私の知る限り、特許

VARCHAR(1)は(ストレージサイズは、データの実際の長さは、+ 2つのバイトを入力する3バイトのストレージを必要とする。Ref

CHAR(1)が1つのバイトを必要とする。

から記憶域の観点:5文字以下であれば、固定長のcharカラムを使用することをお勧めします。

varchar(1)を避ける理由はい、それに意味があるLINQ to SQL and varchar(1) fields

+3

大まかなことではありません。固定長4のvarchar(4)の問題は、 'char(4)+ '-x''に不要なスペースがあることです。はい、トリミングすることはできますが、単純にvarchar(4)を使用するだけでは不要な複雑さが増しています。 – RichardTheKiwi

+0

@cyberkiwi:私はそれを認識しています。私はストレージの観点から話しています。 –

+0

私は質問が「保管」について具体的に質問しているとは考えていませんでした。しかし、あなたの編集はあなたの答えの範囲をより明確にします。 – RichardTheKiwi

5

はゼロ長(「空」)の文字列を格納することができます。 char(1)は、1つのスペースにパディングされているため、できません。この区別があなたにとって重要である場合は、varcharを好むかもしれません。

デザイナーは文字の大きい数は、将来的に必要とされる可能性を可能にしたい場合はそれとは別に、このための1ユースケースであってもよいです。

char(1)からchar(2)までの固定長データ型を変更すると、すべてのテーブル行を更新する必要があり、この列にアクセスするインデックスまたは制約が最初に削除されることを意味します。

本番環境で大規模なテーブルを変更すると、非常に時間がかかる作業になる可能性があります。それだけで(列を参照FK制約をドロップして再作成する必要はありませんが、インデックスを再構築またはデータページを更新する必要があります。)を変更するメタデータであるとしてvarchar(2)varchar(1)から列を変更

ははるかに簡単です。

さらに、1行に2バイトの節約が必ずしも実現されるとは限りません。行の定義がすでにかなり長い場合、これはデータ・ページに収まる行の数には必ずしも影響しません。もう1つのケースは、エンタープライズ版の圧縮機能を使用すると、データが格納される方法が、Mitchの答えに記載されている方法とはまったく異なる場合です。 varchar(1)char(1)の両方が短いデータ領域に同じ方法で保存されます。

@トーマスこのテーブルの定義を試してください。

CREATE TABLE T2 
(
Code VARCHAR(1), 
Foo datetime2, 
Bar int, 
Filler CHAR(4000), 
PRIMARY KEY CLUSTERED (Code, Foo, Bar) 
) 

INSERT INTO T2 
SELECT TOP 100000 'A', 
        GETDATE(), 
        ROW_NUMBER() OVER (ORDER BY (SELECT 0)), 
        NULL 
FROM master..spt_values v1, master..spt_values v2 

CREATE NONCLUSTERED INDEX IX_T2_Foo ON T2(Foo) INCLUDE (Filler); 
CREATE NONCLUSTERED INDEX IX_T2_Bar ON T2(Bar) INCLUDE (Filler); 

varcharにとってはvarchar(2)varchar(1)から列定義を変更するのは簡単です。これはメタデータのみの変更です。変更がchar(1)からchar(2)にある場合

ALTER TABLE T2 ALTER COLUMN Code VARCHAR(2) NOT NULL 

次の手順は起こらなければなりません。

  1. PKをテーブルから削除します。これにより、表がヒープに変換され、クラスタ化されていないすべての索引を、クラスタ化索引キーではなくRIDで更新する必要があることを意味します。
  2. 列の定義を変更します。これは、Codeが今すぐchar(2)として格納されるように、テーブル内のすべての行が更新されることを意味します。
  3. クラスタ化されたPK制約を追加し直します。 CI自体を再構築するだけでなく、非クラスタ化インデックスはすべて、RIDではなく行ポインタとしてCIキーを使用して再度更新する必要があります。
関連する問題