web-dev-qa-db-ja.com

Uniqueidentifier vs. IDENTITY vs. Material Code-主キーに最適な選択はどれですか?

SQL Serverの主キーに最適なのはどれですか?
いくつかのサンプルコードがあります:

一意の識別子

例:

CREATE TABLE new_employees
   (employeeId   UNIQUEIDENTIFIER      DEFAULT NEWID(),
   fname      VARCHAR(20) )
GO
INSERT INTO new_employees(fname) VALUES ('Karin')
GO

ID列

例:

 CREATE TABLE new_employees
 (
  employeeId int IDENTITY(1,1),
  fname varchar (20)
 );

 INSERT new_employees
    (fname)
 VALUES
    ('Karin');

[材料コード](または材料のIDであるビジネスコード。例:顧客識別子)

例:

CREATE TABLE new_employees(
    [ClientId] [varchar](20) NOT NULL,
    [fName] [varchar](20) NULL      
 )

 INSERT new_employees
    (ClientID, fname)
 VALUES
    ('C0101000001',--customer identifier,e.g.'C0101000001' a user-defined code.
     'Karin');

3つのタイプID列から主キーを選択するためのアドバイス、またはその他の選択肢を教えてください。

ありがとう!

15
huoxudong125

GUIDは、主キーの自然な選択のように思われるかもしれません。本当に必要な場合は、テーブルの主キーに使用することを主張できます。私が強くお勧めするのはしないでくださいGUID列をクラスタリングキーとして使用することです。特に指定しない限り、SQLServerはデフォルトで実行します。

あなたは本当に2つの問題を区別する必要があります:

  1. 主キーは論理構造であり、テーブル内のすべての行を一意かつ確実に識別する候補キーの1つです。これは実際には何でもかまいません-INTGUID、文字列-シナリオに最も適したものを選択してください。

  2. クラスタリングキー(テーブルの「クラスター化インデックス」を定義する1つまたは複数の列)-これはphysicalストレージ関連のことです。ここでは、小さくて安定した、増え続けるデータ型が最適です-デフォルトのオプションとしてINTまたはBIGINT

デフォルトでは、SQL Serverテーブルの主キーはクラスタリングキーとしても使用されますが、そのようにする必要はありません。以前のGUIDベースのプライマリ/クラスター化キーを2つの別々のキー(GUIDのプライマリ(論理)キーと別のクラスター化(順序付け)キー)に分割すると、個人的にパフォーマンスが大幅に向上しました。 INT IDENTITY(1,1)列。

Kimberly Tripp -Queen of Indexing-などが何度も述べています-クラスタリングキーとしてのGUID '最適です。ランダムであるため、ページとインデックスの断片化が大きくなり、一般的にパフォーマンスが低下します。

はい、わかっています。SQLServer2005以降にはnewsequentialid()がありますが、それでも完全にシーケンシャルではないため、GUIDと同じ問題が発生します。顕著にそうです。

次に、考慮すべき別の問題があります。テーブルのクラスタリングキーは、テーブルのすべての非クラスター化インデックスのすべてのエントリにも追加されます。したがって、できるだけ小さくする必要があります。通常、テーブルの大部分には2億行以上のINTで十分です。また、クラスタリングキーとしてのGUIDと比較すると、ディスク上の数百メガバイトのストレージを節約できます。およびサーバーメモリ内。

迅速な計算-プライマリキーおよびクラスタリングキーとしてINTGUIDを使用:

  • 1'000'000行のベーステーブル(3.8MB対15.26MB)
  • 6つの非クラスター化インデックス(22.89MB対91.55MB)

合計:25MB対106MB-そしてそれはただ1つのテーブルにあります!

キンバリー・トリップの優れたものである、もう少し考えるべき食べ物を読んで、もう一度読んで、消化してください!本当に、それはSQLServerのインデックス作成の福音です。

非常に正当な理由がない限り、ほとんどすべての「実際の」データテーブルにINT IDENTITYをデフォルトとして使用することをお勧めします。主キー-一意であり、安定しており(変更されない)、狭く、増加し続けています-クラスタリングに必要なすべての優れたプロパティ SQL Serverテーブルの高速で信頼性の高いパフォーマンスのための鍵!

これらすべてのプロパティを持つ「自然」キー値がある場合は、代理キーの代わりにそれを使用することもできます。しかし、two最大の可変長文字列。私の意見では、それぞれ20文字はこれらの要件を満たしていません。

22
marc_s

[〜#〜]アイデンティティ[〜#〜]

[〜#〜]プロ[〜#〜]

  1. 小さなストレージフットプリント。
  2. 最適な結合/インデックスパフォーマンス(たとえば、時間範囲クエリの場合、最近挿入されたほとんどの行は限られた数のページにあります);
  3. データウェアハウジングに非常に役立ちます。
  4. oSのネイティブデータ型であり、すべての言語で簡単に操作できます。
  5. デバッグが簡単。
  6. 自動的に生成されます(割り当てられるのではなく、SCOPE_IDENTITY()を介して取得されます)。
  7. 更新できません(奇妙なことに、これは不利だと考える人もいますが)。

[〜#〜]短所[〜#〜]

  1. アプリケーションによって確実に「予測」することはできません—INSERTの後でのみ取得できます。
  2. iDENTITYは一部の形式のレプリケーションでは許可されていないため、マルチサーバー環境では複雑なスキームが必要です。
  3. pRIMARY KEYに明示的に設定されていない場合は、複製できます。
  4. テーブルのクラスター化インデックスの一部である場合、これにより挿​​入ホットスポットが作成される可能性があります。
  5. 独自仕様であり、直接ポータブルではありません。
  6. 単一のテーブル内でのみ一意。
  7. ギャップが発生する可能性があり(たとえば、ロールバックされたトランザクションで)、これによりチキンリトルスタイルのアラームが発生する可能性があります。

[〜#〜] guid [〜#〜]

[〜#〜]プロ[〜#〜]

  1. それらは{多かれ少なかれ}一意であることが保証されているため、複数のテーブル/データベース/インスタンス/サーバー/ネットワーク/データセンターがそれらを個別に生成し、衝突することなくマージできます。

  2. 一部の形式のレプリケーションに必要です。

  3. データベースの外部で(アプリケーションなどによって)生成できます。
  4. 分散値はホットスポットを防ぎます(この列をクラスター化しない限り、異常に高い断片化につながる可能性があります)。

[〜#〜]短所[〜#〜]

  1. データ型が広くなると、インデックスのパフォーマンスが低下し(クラスター化されている場合、各挿入は異なるページを「ダーティ」にすることがほぼ保証されます)、ストレージ要件が増加します。
  2. デバッグが面倒(userid = {BAE7DF4-DDF-3RG-5TY3E3RF456AS10});
  3. 更新可能(変更を伝播するか、アクティビティを完全に防止する必要があります);
  4. 特定の環境での時間のロールバックに敏感です(例:夏時間のロールバック)。
  5. GROUP BYおよびその他のセット操作では、多くの場合、CAST/CONVERTが必要です。
  6. すべての言語と環境がGUIDを直接サポートしているわけではありません。
  7. 生成された値を判別するためのSCOPE_GUID()のようなステートメントはありません。 NEWID();
5
Muhammad Nasir

テーブルを設計する際に考慮する必要があることの1つは、データをある場所から別の場所に複製、シャーディング、またはその他の方法で移動する必要があるかどうかです。たぶん、データは他のアプリケーションによって生成されており、あなたのアプリケーションと同期しておく必要があります。その一例は、データを作成してサーバーと同期するモバイルアプリです。そのようなことが当てはまる、または当てはまる可能性がある場合は、UNIQUEIDENTIFIERを主キーに使用することをお勧めします。

UNIQUEIDENTIFIERデータ型は、クラスター化インデックスとして使用するとパフォーマンスが低下します。はい、newsequentialid()を使用できますが、値が他のデバイスで生成されている場合は役に立ちません。クラスター化インデックスは、INTBIGINTのようなシーケンシャルで狭いデータ型で使用するのが最適であるというのがコンセンサスのようです。

ストレージスペースの問題に関心がない場合は、IDENTITYクラスターキーUNIQUEIDENTIFIER主キー。 cluster keyIDENTITY列を作成し、それをクラスター化インデックスに使用します(ただし、主キーとしては使用しません)。挿入は引き続き順次行われ、狭いデータ型であるという要望を満たします。これで、UNIQUEIDENTIFIERを主キーとして使用できます。これにより、必要なときにデータを移動、複製、および/またはシャーディングすることができます。

クラスターキーには、挿入をシーケンシャルに保ち、他のすべての非クラスター化インデックスがデータを検索するときに指すものにする以外の目的はありません。特定のクエリ。 クラスターキーは完全に破棄され、一意性はUNIQUEIDENTIFIER主キー。

これは、クラスター化インデックスにIDENTITYとUNIQUEIDENTIFIERを使用したときに内部で何が起こるかを示す優れた記事です。

2
rmblstrp

GUIDは大きいですが、このテーブルまたはそれ、このサーバーまたはそれなど、どこでも一意であるという利点があります。GUIDがあれば、他のすべてがわかります。それが役立つ場合は、すばらしいですが、オーバーヘッドで支払い、支払いを続け、支払い、支払いを行います。

マテリアルコードは、色や分類コードなどの小さな不変のキーに対してのみ実際に機能します。 Rは常に赤、Gは緑、1バイトなどです。

ID列は、マテリアルコードがない場合、自然キーが複数のマテリアルコードで構成されている場合、自然キーがすでに他のID列やGUIDで構成されている場合、または自然キーが変更可能である場合に独自に機能します。はい、GUIDを使用できますが、すべての点で整数列の方がはるかに効率的です。

SQL 2012で使用できるもう1つのオプションは、データベースレベルのID列のようなシーケンスです。これは、シーケンスを多くのテーブルで使用できるという意味で、GUIDとID列の中間に位置するため、特定の値から、行だけでなくテーブルも認識できますが、引き続き使用できます。データに十分だと思われる場合は、INTまたはBIGINT(またはSMALLINT!)。これは、特定の目的にとっては気の利いたものであり、OO worldのオブジェクトIDのようなものです。

多くのORMまたは軽量ORMは、テーブルに単一列の主キー、できれば整数列があることを期待しており、INT IDENTITYPK以外ではうまく機能しない可能性があることに注意してください。

1
Peter Radocchia