特にパフォーマンスに関して、GUIDを主キーとして使用するためのベストプラクティスは何ですか?


336

ほとんどすべてのテーブルで主キーとしてGUIDを使用するアプリケーションがあり、GUIDを主キーとして使用するとパフォーマンスに関する問題があることを読みました。正直なところ、問題はありませんでしたが、新しいアプリケーションを開始しようとしていて、GUIDを主キーとして使用したいのですが、複合主キー(GUIDと別のフィールド)を使用することを考えていました。 。)

「本番」、「テスト」、「開発」データベースなどの異なる環境があり、データベース間のデータの移行にも適しているため、GUIDを使用しています。

Entity Framework 4.3を使用し、データベースに挿入する前に、アプリケーションコードでGuidを割り当てたいと思います。(つまり、SQLにGuidを生成させたくありません)。

このアプローチに関連する想定されるパフォーマンスへの影響を回避するために、GUIDベースの主キーを作成するためのベストプラクティスは何ですか?


20
問題は想定されていません。PKがクラスター化されている場合、ほとんどすべての挿入がページ分割を引き起こす可能性があります。SQL Serverの最新バージョンでは、これはNEWSEQUENTIALID()で「修正」されていましたが、事前に計算できるという利点がありません。これは質問が広すぎて、何時間も続く宗教的な戦いを招く可能性があるため、他の場所でGUIDを読むことを強くお勧めします...
Aaron Bertrand

4
私はまた、ワードことを追加したいサーバがであいまいです、私は上のGUIDを割り当てる サーバ 側(いけないGUIDを作成するためにSQLを聞かせたいです)
エリックフィリップス

この質問は、この「SQL-SERVER-GUID-ソートアルゴリズム-なぜ」に類似している stackoverflow.com/questions/7810602/...
クリントン区

回答:


494

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

あなたは本当に2つの問題を分けておく必要があります:

  1. 主キーは、一意かつ確実に、テーブル内のすべての行を識別すること、候補キーのいずれか-論理的構築物です。これは本当に何でもかまいません。INTGUID文字列が-あなたのシナリオのための最も理にかなっているものを選びます。

  2. クラスタ化キー(表の「クラスタ化インデックス」を定義する列または列) -これは、物理 -ストレージ関連のもの、そしてここで、小型、安定した、増え続けるデータ型は、あなたの最高のピックであるINTか、BIGINTあなたのようデフォルトのオプション。

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

以下のようキンバリーメーカーTripp -インデックスの女王-などが非常に多くの時間を述べている- GUIDクラスタリング・キーは、そのランダム性に起因しているため、最適ではないとして、それは大規模なページとインデックスの断片に、一般的に悪いパフォーマンスにつながります。

はい、知っています-あります newsequentialid()ています。SQLServer 2005以降にもありますが、それでも完全にシーケンシャルではなく、したがって、同じ問題がGUID-それほど顕著ではありません。

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

クイック計算- INTGUID一次およびクラスタリングのキーのように:

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

合計:25 MB対106 MB-これは1つのテーブルにあります!

もう少し考えるべき食べ物-Kimberly Trippによる優れたもの-読んで、もう一度読んで、消化してください!SQL Serverのインデックス作成の福音です。

PS:もちろん、数百行または数千行だけを扱っている場合、これらの引数のほとんどは実際にはそれほど大きな影響を与えません。ただし、数万行または数十万行に到達した場合、または数百万行でカウントを開始した場合これらのポイントは非常に重要であり、理解することが非常に重要になります。

更新:あなたはあなたの持っているしたい場合はPKGUID、あなたの主キー(はなく、あなたのクラスタリング・キー)、および別の列としての列をMYINTINT IDENTITY)あなたのクラスタ化キーとして-これを使用します:

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

基本的には、PRIMARY KEY制約であることを明示的に伝える必要がありますNONCLUSTERED(そうでない場合は、デフォルトでクラスター化インデックスとして作成されます)。次に、次のように定義されている2番目のインデックスを作成します。CLUSTERED

これは機能します-パフォーマンスのために「再設計」する必要がある既存のシステムがある場合、これは有効なオプションです。新しいシステムの場合、ゼロから始めて、レプリケーションシナリオでない場合は、常にID INT IDENTITY(1,1)クラスター化された主キーとして選択します-何よりもはるかに効率的です!


2
これは素晴らしい答えです。私が言及する1つのことは、挿入前にキーを生成できることは頻繁に役立つことです。「newsequentialid()」を使用するとクラスタリングに役立ちますが、SQLへの追加のラウンドトリップが必要です。したがって、「代理キー」アプローチのもう1つの利点は、クライアント側で新しいIDを生成でき、インデックスの断片化の懸念が少ないことです。
Andrew Theken

2
これを読む方法は、クラスター化されていないuniqueidentifier列とint identity列の両方を持つため、FKもuniqueidentifierである必要がありますか?その場合、実際にID列を直接使用するのはいつですか、そうでないのですか?
pinkfloydx33 2014年

2
少し質問ですが、今やGUIDは結合で使用する必要がありますか、それともint IDですか?私の本能ではGUIDを使用する必要があると言われていますが、int idを使用した技術的な問題は確認できません...
Nicolas Belley

3
@marc_sですが、レプリケーションシナリオでは、int列がIDである場合、int列はデバイス間で繰り返すことができるため、GUIDを使用するべきではありませんか?
Nicolas Belley、2015年

6
@Kipei:主な問題はあるのIF - [はい、あなたは主キーとして使用することができますが、このような自然の価値を持っています。しかし:のような値DATETIMEインスタンスのはありません、彼らは唯一の3.33msの精度を持っているので、重複が存在することができるため、クラスタリング・キーに便利。このような場合には、あなたはまだ*必要INT IDENTITY代わりに-ので、私は通常、デフォルトでそれを使用し、経験のfrmo私の20年以上以来、本当に使える自然キーはめったに本当に存在していない....
marc_s

51

私は2005年以来、GUIDをPKとして使用しています。この分散データベースの世界では、分散データをマージするのが絶対に最善の方法です。結合されたテーブル間でintが一致することを心配することなく、マージテーブルを起動して忘れることができます。GUID結合は心配することなくコピーできます。

これはGUIDを使用するための私のセットアップです:

  1. PK = GUID。GUIDには文字列と同様にインデックスが付けられるため、行数が多いテーブル(5,000万を超えるレコード)では、テーブルのパーティション分割またはその他のパフォーマンステクニックが必要になる場合があります。SQL Serverは非常に効率的になっているため、パフォーマンスの懸念はますます少なくなります。

  2. PK Guidは非クラスター化インデックスです。NewSequentialIDでない限り、GUIDをクラスター化しないでください。しかし、それでも、サーバーを再起動すると、注文に大きな障害が発生します。

  3. ClusterID Intをすべてのテーブルに追加します。これはCLUSTEREDインデックスです...テーブルを注文します。

  4. ClusterID(int)での結合の方が効率的ですが、私は2,000万〜3,000万のレコードテーブルを使用しているため、GUIDでの結合はパフォーマンスに目に見える影響を与えません。最大のパフォーマンスが必要な場合は、ClusterIDの概念を主キーとして使用し、ClusterIDで結合します。

これが私のメールテーブルです...

CREATE TABLE [Core].[Email] (
    [EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,        
    [EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,        
    [CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,      
    [ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)

PK_Email制約について説明できますか?... Nonclustered(ClusterID ASC)の代わりに... NonClustered(EmailID ASC)があるのはなぜですか?
Phil

2
あなたは賭けます。インデックスで行われる2つの主なこと:1. ClusterIDでクラスター化-ディスク上でテーブルを並べ替えます(断片化0%)。2. EmailIDで非クラスター化-EmailIDフィールドにインデックスを付けて、GUID IDの検索を高速化します。GUIDフィールドの検索は文字列のように動作するため、インデックスがないと、EmailIDの検索が遅くなります。
ロバートJ.グッド

@ RobertJ.Goodこの方法が前に説明されていること、つまり、代理のintキーをクラスタに追加するのを見たことがあります。しかし、ヒープを使用するよりも代理キーのクラスター化インデックスを使用することでパフォーマンスが向上することを示す場所はどこにもありません。ベンチマークデータへのリンクはありますか?
デールK

1
こんにちは@DaleBurrell、クラスター化インデックスはテーブルの断片化を防ぐためのものです。テーブルはディスク上で自然に順番に成長し、断片化が少ないため、パフォーマンスが向上します。
ロバートJ.グッド

@ RobertJ.GoodそれはWebアプリケーションですか?urls / hrefsで何を使用していますか?GUIDまたはINT?
dariol

10

現在、EF Coreを使用してWebアプリケーションを開発しています。使用するパターンは次のとおりです。

すべてのクラス(テーブル)とint PKおよびFK。非クラスター化インデックスを含む、タイプGuid(c#コンストラクターによって生成された)の追加の列があります。

EF内のテーブルのすべての結合はintキーを通じて管理されますが、外部(コントローラー)からのすべてのアクセスはGuidで行われます。

このソリューションでは、URLにintキーを表示せずに、モデルを整然と高速に保つことができます。


データ注釈のように、整数pKをクラスター化して構成するために必要なことはありますか?それとも自動的に構成されますか?
アレン王

Guidの物件にはどのような名前を付けていますか?
トロンファン

3

GUIDを主キーとして使用し、クラスター化インデックスを作成する場合は、デフォルトのNEWSEQUENTIALID()値を使用することをお勧めします


どうしてそうするか?
本物のfafa

3

このリンクは、私ができるよりも優れていることを示しており、私の意思決定に役立ちました。特別な必要がない限り、通常は主キーとしてintを選択します。また、特別な理由がない限り、SQLサーバーにこのフィールドを自動生成/維持させます。実際には、パフォーマンスの問題は、特定のアプリに基づいて決定する必要があります。ここでは、予想されるDBサイズ、適切なインデックス付け、効率的なクエリなど、さまざまな要素が影響します。人々は反対するかもしれませんが、私は多くのシナリオでどちらのオプションでも違いに気付かないと思います、そしてあなたはあなたのアプリにとってより適切なものとあなたがより簡単に、より速くそしてより効果的に開発することを可能にするものを選ぶべきです(アプリを決して完成しないなら)残りはどう違いますか:)

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

PSなぜ複合PKを使用するのか、あるいはそれがあなたにどのような利点をもたらすと信じているのか、私にはわかりません。


完全に同意する!!しかし、それは、GUIDをPKとして、またはGUIDを使用した複合PKと他のフィールドが同じである場合はどうなるのでしょうか。
VAAA 2012

1
PK(インデックス)は2つの列で構成されますが、これを行うためのビジネス固有の理由がない限り、これは不要のようです。
マット

1
ところで、この質問は、世間で最も二極化して議論されている質問の1つであるため、100%快適に感じることになるので、答えを得るのは非常に困難です。どちらの方法にもトレードオフがあるので、幸運を祈ります:)
Matt


0

シーケンシャルIDがあると、ハッカーやデータマイナーがサイトやデータを危険にさらすのが容易になります。WebサイトのPKを選択するときは、そのことを覚えておいてください。


この主張を裏付ける論理または証拠を提供できますか?シーケンシャルIDがセキュリティを危険にさらす可能性があるかどうかを確認するのに苦労しています。
ジョナグロン

もちろん、ID番号が整数であることがわかっている場合は、DBのレコードを順番に推測できます。したがって、1つのアイテムをクエリする場合、次のアイテムはpk + 1であると言えます。ランダムなGUIDSがある場合、それはパターンに従いません。以前に照会したレコード(およびPKを知っている)以外のレコードを照会することはほぼ不可能です。
DaBlue

1
ハッカーがすでに危険にさらされているデータベースにクエリを実行できる場合、シーケンシャルIDが状況を悪化させる方法を確認できません。
ジョナグロン

1
ユーザーが1012を別の番号に切り替えて、必要のないデータを表示できる場合、非常に深刻なセキュリティの問題があります。その問題は主キーの選択が原因ではなく、それによって悪化します。私はあなたの要点を理解しています、それを綴ってくれてありがとう。
ジョナグロン

2
GUIDを使用して、Webページでレコードを見つけることができます。これは、テーブルのPKではありません。Webサイトでクエリパラメータを使用しても、DBスキーマの構造を定義するべきではありません。PKは、UIまたはバックエンドシステムの入力およびパラメーターとは関係ありません。
Panos Roditakis
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.