ほとんどすべてのテーブルでGUIDを主キーとして使用するアプリケーションがあり、GUIDを主キーとして使用するとパフォーマンスに関する問題があることがわかりました。正直なところ、私は何の問題も見ていませんでしたが、新しいアプリケーションを始めようとしており、それでも主キーとしてGUIDを使いたいのですが、複合主キーを使うことを考えていました(GUID)そして多分別の分野)
[production]、[test]、[dev]などのさまざまな環境がある場合、またデータベース間の移行データについても、管理が簡単で使いやすいため、GUIDを使用しています。
Entity Framework 4.3を使用します。データベースに挿入する前に、Guidをアプリケーションコードに割り当てます。 (つまり、SQLにGuidを生成させたくはありません)。
この方法で予想されるパフォーマンスの低下を避けるために、GUIDベースの主キーを作成するためのベストプラクティスは何ですか?
GUIDはあなたの主キーのための自然な選択のように思えるかもしれません - そしてあなたが本当に必要なら、あなたはおそらくテーブルのPRIMARY KEYのためにそれを使うことを主張することができます。 しないことがクラスタリングキーとしてGUID列を使用することを強くお勧めします。に。
2つの問題を区別する必要があります。
主キーは論理的な構成要素 - テーブル内のすべての行を一意かつ確実に識別する候補キーの1つです。これは何でもかまいません - 実際には - INT
、GUID
、文字列 - あなたのシナリオにとって最も理にかなっているものを選んでください。
クラスタリングキー(テーブルの「クラスタ化インデックス」を定義する1つまたは複数の列) - これは物理的なストレージ関連のことで、ここではちょっと安定した、増え続けるデータ型があなたの最善の選択です - INT
またはBIGINT
がデフォルトのオプションです。
既定では、SQL Serverテーブルの主キーはクラスタリングキーとしても使用されます - ただし、そのようにする必要はありません。以前のGUIDベースの主キー/クラスタ化キーを2つの別々のキー(GUIDの主(論理)キーと、別のINT IDENTITY(1,1)
列のクラスタリング(順序付け)キー)に分割すると、パフォーマンスが大幅に向上しました。
As Kimberly Tripp - 他の人が何度も言っています - クラスタリングキーとしてのGUID
は最適ではありません。そのランダムさ、それは大規模なページとインデックスの断片化と一般的に悪いパフォーマンスにつながります。
はい、私は知っています - SQL Server 2005以降にはnewsequentialid()
があります - でもそれは完全かつ完全にシーケンシャルではないのでGUID
と同じ問題に苦しんでいます - それほど目立たないように。
次に考慮すべきもう1つの問題があります。テーブル上のクラスタ化キーは、テーブル上の各非クラスタ化インデックスの各エントリにも追加されるため、できるだけ小さいことを確認したいのです。通常、20億行を含むINT
で大多数のテーブルに十分です。クラスタリングキーとしてのGUID
と比較すると、ディスク上およびサーバーメモリ内に数百メガバイトの記憶域を節約できます。
素早い計算 - INT
とGUID
を主キーとクラスタリングキーとして使用:
合計:25 MB対106 MB - そして、それはただ一つのテーブルの上にあります!
もう少し考えてみましょう - Kimberly Trippの優れたもの - それを読み、もう一度読み、ダイジェストしてください。それは本当にSQL Serverのインデックス作成の福音書です。
シモンズ:もちろん、あなたがたった数百あるいは数千の行を扱っているのであれば - これらの引数の大部分はあなたに実際にそれほど大きな影響を与えないでしょう。しかし、何万、何十万もの行に入る場合、あるいは何百万という数え始めると - then _これらの点は非常に重要になり、理解することが非常に重要になります。
あなたのPKGUID
カラムをあなたの主キーとして(しかしあなたのクラスタリングキーはそうではない)、そしてもう一つのカラムMYINT
(INT IDENTITY
)をあなたのクラスタリングキーとして使いたいなら、pdate: - これを使ってください:
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
であることを伝えればよく(そうでなければ、デフォルトではクラスタード・インデックスとして作成されます) - そしてCLUSTERED
として定義される2番目のインデックスを作成します
これはうまくいくでしょう - そしてパフォーマンスのために "再設計"する必要がある既存のシステムがあるならそれは有効なオプションです。新しいシステムの場合、最初からやり直していて、レプリケーションのシナリオにいないのであれば、私は常にID INT IDENTITY(1,1)
を私のクラスタ化された主キーとして選択します。
2005年以来、私はGUIDをPKとして使用してきました。この分散データベースの世界では、分散データをマージするための絶対的な最善の方法です。結合テーブル間で整数が一致する心配がなくても、マージテーブルを起動して忘れることができます。結合されたGUIDは心配することなくコピーできます。
これはGUIDを使用するための私の設定です:
PK = GUID GUIDは文字列と同じようにインデックス付けされているので、高い行のテーブル(5000万レコードを超える)はテーブルの分割や他のパフォーマンス技術を必要とするかもしれません。 SQL Serverは非常に効率的になっているため、パフォーマンスへの懸念はますます適用されなくなっています。
PK Guidは非クラスタ化インデックスです。 NewSequentialIDでない限り、GUIDをクラスタインデックスしないでください。それでも、サーバーを再起動すると、順序が大きく崩れます。
すべてのテーブルにClusterID Intを追加します。これはあなたのCLUSTERED Index ...あなたのテーブルを注文するものです。
ClusterIDs(int)への参加はより効率的ですが、私は2000万〜3000万件のレコードテーブルを扱うので、GUIDへの参加はパフォーマンスに目に見える影響を与えません。最大限のパフォーマンスを得たい場合は、ClusterIDの概念を主キーとして使用し、ClusterIDに参加してください。
これが私のEメールテーブルです。
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)
私は現在EF Coreを使ってWebアプリケーションを開発しています、そして私が使うパターンはここにあります:
私のすべてのクラス(テーブル)とint型のPKとFK。非クラスタ化インデックスを持つ、Guid型(c#コンストラクタによって生成される)の追加の列があります。
EF内のテーブルのすべての結合はintキーによって管理され、外部(コントローラ)からのすべてのアクセスはGuidで行われます。
この解決策では、URLにintキーを表示せず、モデルをきちんと高速に保つことができます。
主キーとしてGUIDを使用してクラスター化インデックスを作成する場合は、デフォルトのNEWSEQUENTIALID()値を使用することをお勧めします。
このリンクは、私ができるよりも優れていると私の意思決定を助けました。特に必要がない限り、主キーとしてintを選択します。特別な理由がない限り、SQL Serverにこのフィールドを自動生成/維持させます。実際には、パフォーマンスの問題は特定のアプリに基づいて判断する必要があります。ここには、予想されるデータベースサイズ、適切なインデックス作成、効率的なクエリ処理など、さまざまな要素があります。賛成できないかもしれませんが、多くのシナリオでどちらの方法でも違いに気付かず、より適切でより簡単に、より早く、より効果的に開発できるものを選択する必要があると思います。残りの違いは何ですか:)。
P.S私がなぜあなたがコンポジットPKを使うのか、あるいはそれがあなたに与えると信じているどんな利益があるのか私にはわかりません。
シーケンシャルIDを持つことで、ハッカーやデータマイナーがあなたのサイトやデータを危険にさらすことをより簡単にします。ウェブサイトのためにPKを選ぶとき、それを覚えておいてください。
ほとんどの場合、テーブルの主キーとして使用するべきではありません。データベースのパフォーマンスを著しく低下させるからです。 GUIDに関するパフォーマンス上の影響および主キーとしての有用なリンク。