広範なPKを使用する場合と、個別の合成キーおよびUQを使用する場合のパフォーマンスに関する考慮事項は何ですか?


10

レコードがいくつかの広範なビジネス分野で一意に識別できるいくつかのテーブルがあります。過去に、これらのフィールドをPKとして使用しましたが、これらの利点を考慮しています。

  • シンプルさ。無関係なフィールドはなく、インデックスは1つだけです
  • クラスタリングにより、高速マージ結合と範囲ベースのフィルターが可能になります

ただし、合成IDENTITY INTPK を作成し、代わりに別のUNIQUE制約を使用してビジネスキーを強制するケースについて聞いたことがあります。利点は、PKが狭いため、セカンダリインデックスがはるかに小さくなることです。

テーブルにPK以外のインデックスない場合、2番目のアプローチを採用する理由はありませんが、大きなテーブルでは、インデックスが将来必要になる可能性があると想定して、狭い合成PKを採用することをお勧めします。 。考慮事項が不足していますか?

ちなみに、私はデータウェアハウスで合成キーを使用することに反対しているのではなく、単一の広いPKを使用する場合と、狭いPKと広いUKを使用する場合にのみ関心があります。


1
あなたが見つけることがこのまたはこのサイト上の他の質問の中で便利に
ジャックはtopanswers.xyzしようと言う

回答:


11

クラスタ化インデックスとして自然キーを使用しても、大きな欠点はありません。

  • 非クラスター化インデックスはありません
  • このテーブルを参照する外部キーはありません(これは親行です)

データ挿入が最後ではなくデータ全体に分散されるため、欠点はページ分割が増えることです。

FKまたはNCインデックスがある場合、狭い、数値の、増加するクラスター化インデックスを使用することには利点があります。NCまたはFKエントリごとに数バイトのデータを繰り返すだけであり、whileビジネス/自然キーではありません。

理由については、Googleの5つの記事も読んでください。

「主キー」の使用は避けました。

サロゲートキーにクラスタ化インデックスを設定できますが、ビジネスルールのPKは保持しますが、非クラスタ化として保持できます。クラスター化されたものが一意であることを確認してください。SQLは「一意化子」を追加するためです。

最後に、代理キーを用意することは理にかなっているかもしれませんが、すべてのテーブルに盲目的にではありません。多くのテーブルには必要ありません。または、親テーブルの複合キーで十分です。


索引付けにおける参照Mrs Trippの優れた記事の+1。
Fabricio Araujo

2
+1は、パフォーマンスが主キーとは関係なく、インデックスとはすべて関係があるという点です。
nvogel

4

自明のことですが、IDキーで検索する必要がある場合は、代理キーのインデックス(IDキー)が役立ちます。ユーザーはID番号を処理しません。彼らは人間が読めるテキストを扱います。したがって、テキストとそのID番号を何度も渡す必要があるため、ユーザーインターフェイスでテキストを表示し、ID番号を操作できます。

dbmsは、そのように定義すると、その種類のインデックスを使用して外部キーをサポートします。

ID番号を外部キーとして使用することでパフォーマンスを改善できる場合がありますが、これは絶対的な改善ではありません。私たちのOLTPシステムでは、自然キーを使用した外部キ​​ーは、約130の(私が思うに)代表的なクエリのテストスイートで、ID番号を使用した外部キ​​ーよりも優れていました。(重要な情報はキーに含まれることが多いため、自然キーを使用すると多くの結合が回避されます。)速度の中央値は85倍でした(ID番号を使用した結合では、行を返すまでに85倍の時間がかかりました)。

テストでは、特定のテーブルが数百万行に達するまで、ID番号の結合がデータベース内の自然キーの読み取りよりも速く実行されないことが示されました。行の幅はそれと関係があります。行が広いと、ページに収まる行が少なくなるため、「n」行を取得するには、より多くのページを読み取る必要があります。ほとんどすべてのテーブルは5NFです。ほとんどのテーブルはかなり狭いです。

結合が始まると、ここで単純な読み取りが実行され始め、重要なテーブルとインデックスをソリッドステートディスクに配置すると、パフォーマンスが数億行に達する可能性があります。


3

クラスタリング+ pkのID列を使用して設計されたoltpデータベース全体があります。挿入/シークではかなり高速に動作しますが、いくつかの問題が発生しました
。1。挿入はインデックスの最後までしか発生しないため、インデックスの塗りつぶしオプションは役に立ちません
。私は数千万のレコードを持つテーブルを持っており、1つのintはそれ自体でスペースを占めます。pkのID列を持つ各テーブルには、ビジネスシーク用に別のインデックスが必要なので、さらに多くのストレージが必要です。
3.スケーラビリティ。これが最悪の問題です。すべての挿入はインデックスの末尾に移動するため、各挿入はインデックスの末尾のみに負荷をかけます(割り当て、書き込みのioなど)。ビジネスキーをクラスタリングキーとして使用することで、挿入をインデックスに均等に分散できます。つまり、大きなホットスポットを排除したということです。インデックスには、より多くのファイルを簡単に使用できます。各ファイルは個別のドライブにあり、各ドライブは個別に動作します。

テーブルをID列から自然キーに変更し始めました(クラスタリングとpkで別々になっている可能性があります)。気分が良くなりました。

次のことをお勧めします(少なくともoltp dbの場合):
1.クラスター化キーとして正しい列を正しい順序で
使用して、最も頻繁なクエリを最適化します2. pkを使用して、テーブルに適した正しい列を作成します

クラスター化されたキーが単純ではなく、文字(char []、varchar、nvarchar)が含まれている場合、答えは「依存する」と思うので、各ケースを個別に分析する必要があります。

私は次の原則を守っています。最悪のシナリオを最小限に抑えながら、最も一般的なクエリを最適化します。

私は一例をほとんど忘れていました。自分自身を参照するテーブルがいくつかあります。そのテーブルに主キーのID列がある場合、1つの行を挿入すると更新が必要になる場合があり、一度に複数の行を挿入することは不可能ではないにしても難しい場合があります(テーブルの設計によって異なります)。


4
あなたの「ホットスポット」の概念は神話です:dba.stackexchange.com/questions/1584/…そして、「今はただ今気分が良くなった」と言うとき。ベンチマークをしましたか?
gbn

4
はい、書き込みは直接ディスクではなくメモリで行われます。ページに20個の新しい行を書き込む場合、チェックポイントが発生したときにデータファイルに物理的に書き込まれるのは1つだけです。
mrdenny、2011年

インデックスの最後にすべてを書き込む十分な挿入がある@mrdennyは、すべてのio書き込み要求を同じファイルに送信します。通常のoltpトランザクションを使用すると、このシナリオは再現が困難になると思いますが、レコードの一括/一括挿入などの特別なシナリオを使用し、ssisを使用してビジネスデータを移動すると、そこに到達します。
Catalin Adler

1
@ user973156はいすべてのリクエストは同じファイルに対して行われますが、書き込みは実際には1分ごと(デフォルト)にのみ発生するチェックポイントまで、または書き込みバッファーが50%満たされるまでディスクに送信されません。このルールが適用されるデータをどのように書き込むかは関係ありません。
mrdenny、2011年

2
@ user973156ランダムに分散されたクラスタリングキーを使用すると、インデックスの断片化が発生します。インデックスの断片化はパフォーマンスの問題を引き起こします。そして、テーブルは十分に大きくなり、インデックスの最適化を実行すると「長い時間」がかかり、ログ領域と潜在的にtempDB領域が消費されます。Kimberly Trippのような人に、それが良いアイデアだと言われたときは、耳を傾けます。(sqlskills.com/BLOGS/KIMBERLY/post/...
マットM

2

パフォーマンスの観点から、どのキーが「主」キーであるかを選択しても、まったく違いはありません。PRIMARY KEYとUNIQUE制約を使用してキーを強制する場合に違いはありません。

パフォーマンスは、インデックスの選択とタイプ、その他のストレージオプション、およびクエリとコードでのキーの使用方法によって決まります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.