391

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

GUID を使用しているのは、"運用"、"テスト"、"開発" データベースなどのさまざまな環境がある場合や、データベース間のデータの移行に適しているため、管理が簡単だからです。

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

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

4

9 に答える 9

565

GUID は主キーの自然な選択のように思われるかもしれません。どうしても必要な場合は、テーブルの PRIMARY KEY に GUID を使用することをお勧めします。特に使用しないように指示しない限り、SQL Server はデフォルトでこれを行います

2 つの問題を区別する必要があります。

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

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

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

インデックス作成の女王であるKimberly Trippや他の人が何度も述べているGUIDように、クラスター化キーは最適ではありません。これは、そのランダム性が原因で、大量のページとインデックスの断片化が発生し、一般的にパフォーマンスが低下するためです。

はい、私は知っnewsequentialid()ています-SQL Server 2005以降にあります-しかし、それでさえ真に完全にシーケンシャルではなく、したがって、と同じ問題に苦しんでいますGUID-少し目立たないだけです.

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

クイック計算 - INTvs.GUIDをプライマリ キーおよびクラスタリング キーとして使用:

  • 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列を主キー (クラスタリング キーではなく) として使用し、別の列MYINT( INT 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)

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

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

于 2012-08-13T16:34:59.417 に答える
76

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

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

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

  2. PK Guid は非クラスター化インデックスです。NewSequentialID でない限り、GUID のクラスター インデックスを作成しないでください。ただし、その場合でも、サーバーの再起動により、順序付けが大幅に中断されます。

  3. すべてのテーブルに ClusterID Int を追加します。これは、テーブルを注文する CLUSTERED Index です。

  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)
于 2015-03-31T21:27:41.800 に答える
4

このリンクは、私ができるよりもうまく言い、意思決定に役立ちました。特に必要がない限り、私は通常、主キーとして int を選択します。また、特別な理由がない限り、SQL サーバーにこのフィールドを自動生成/維持させます。実際には、特定のアプリに基づいてパフォーマンスの問題を判断する必要があります。ここでは、予想されるデータベース サイズ、適切なインデックス作成、効率的なクエリなど、多くの要因が関与していますが、これらに限定されません。人々は同意しないかもしれませんが、多くのシナリオではどちらのオプションの違いにも気付かないので、アプリにとってより適切なものと、開発をより簡単に、より迅速に、より効果的に行えるものを選択する必要があると思います (アプリを完成させない場合残りはどのような違いがありますか:)。

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

PS 複合 PK を使用する理由や、複合 PK がもたらす利点についてはわかりません。

于 2012-08-13T16:22:51.007 に答える
1

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

于 2012-08-13T16:47:42.267 に答える
0

データが数百万行に達しない場合は問題ありません。あなたが私に尋ねると、たとえあなたが頭に散弾銃を使って設計するように強制したとしても、私は PK を含むあらゆるタイプのデータベース ID 列として GUID を使用しません。

GUID を主キーとして使用することは、決定的なスケーリング ストッパーであり、重要なストッパーです。データベース ID とシーケンス オプションを確認することをお勧めします。シーケンスはテーブルに依存せず、ニーズに応じたソリューションを提供する場合があります (MS SQL にはシーケンスがあります)。

テーブルが数千万行、たとえば 5,000 万行に達し始めると、適切なタイミングで情報の読み取り/書き込みができなくなり、標準的なデータベース インデックスのメンテナンスでさえ不可能になります。

次に、パーティショニングを使用し、5 億行または 10 億行から 20 億行までスケーラブルにする必要があります。途中でパーティショニングを追加するのは簡単なことではありません。すべての読み取り/書き込みステートメントにパーティション列を含める必要があります (完全なアプリの変更!)。

もちろん、これらの数 (5000 万と 5 億) は、軽い選択用途向けです。複雑な方法で情報を選択する必要がある場合、および/または多数の挿入/更新/削除が必要な場合、非常に要求の厳しいシステムでは、代わりに 100 万から 200 万や 5000 万になることさえあります。完全復旧モデル、高可用性、メンテナンス期間なしなど、最新のシステムに共通する要素も追加すると、事態は非常に見苦しくなります。

この時点で、20 億は見栄えの悪い int 制限ですが、int は 4 分の 1 であり、シーケンシャル型のデータであり、小さいサイズとシーケンシャル型がデータベースのスケーラビリティの最大の要因であることに注意してください。そして、数百万行または数十億行になると、シーケンシャルは本当に致命的に重要であり、サイズよりもさらに重要です。

GUID もクラスター化されている場合、事態はさらに悪化します。新しい行を挿入するだけで、実際には物理的な位置のどこにでもランダムに格納されます。

PK や PK 部分ではなく、単なる列であっても、インデックスを作成するだけでは面倒です。断片化の観点から。

GUID 列を持つことは、PK 部分として使用しない限り、また一般的にテーブルを結合するためのキー列として使用しない限り、任意の varchar 列と同様に完全に問題ありません。データベースには独自の PK 要素が必要であり、それらを使用してデータをフィルタリングおよび結合します。後で GUID によるフィルタリングも問題ありません。

于 2021-04-02T11:00:33.727 に答える