12

次の表の例を検討してください (SQL Server 2005 を想定):

create table product_bill_of_materials
(
    parent_product_id int not null,
    child_product_id int not null,
    quantity int not null
)

個別の一意の ID 列ではなく、2 つの product_id 列を含む複合主キーを検討しています (一意の制約が必要なのは間違いありません)。問題は、パフォーマンスの観点から、その主キーをクラスター化する必要があるかどうかです。

外部キーの検索が高速になるように、各 ID 列にもインデックスを作成する必要がありますか? このテーブルは、書き込みよりも読み取りの方がはるかに多くヒットすると思います。

4

5 に答える 5

16

他の何人かがすでに言っているように、それはあなたがテーブルにアクセスする方法に依存します。ただし、RDBMSは、その列が最初に表示される限り、クラスター化インデックスを使用して単一の列で検索できる必要があることに注意してください。たとえば、クラスター化されたインデックスが(parent_id、child_id)にある場合、(parent_id)に別のインデックスは必要ありません。

最善の策は、(parent_id、child_id)のクラスター化インデックスであり、これは主キーでもあり、(child_id)に別個の非クラスター化インデックスがあります。

最終的には、データベースへのアクセス方法を理解した後で、インデックス作成に対処する必要があります。可能であれば、いくつかの標準的なパフォーマンスストレステストを考え出し、プロファイリングツール(SQLServer用のSQLProfiler)を使用して動作を分析し、そこからパフォーマンスを調整します。事前にそれを行うための専門知識や知識がない場合は、アプリケーションの(できれば限定された)リリースを試して、パフォーマンスメトリックを収集し、パフォーマンスを改善する必要がある場所を確認し、どのインデックスが役立つかを把握してください。

正しく行うと、データベースへのアクセス方法の「一般的な」プロファイルをキャプチャできるはずです。その後、さまざまなインデックス作成アプローチを試しながら、テストサーバーでそれを何度も再実行できます。

あなたの場合、おそらく最初にクラスター化されたPKを(parent_id、child_id)に配置し、それによって助けられるパフォーマンスの問題が見つかった場合にのみ、非クラスター化インデックスを追加します。

于 2008-12-23T17:35:08.740 に答える
6

「最も頻繁にクエリを実行する対象」は、クラスタリング用のインデックスを選択する最善の理由とは限りません。最も重要なのは、複数の行を取得するために何を照会するかです。クラスタリングは、最小限のディスク読み取り回数で複数の行を効率的に取得するための適切な戦略です。

最良の例は、顧客の販売履歴です。

Sales テーブルに 2 つのインデックスがあり、1 つは Customer にあるとします (おそらく日付ですが、要点はどちらにも当てはまります)。CustomerID で最も頻繁にテーブルをクエリする場合は、すべての顧客の Sales レコードをまとめて、すべてのレコードに対して 1 つまたは 2 つのディスク読み取りを行う必要があります。

主キーの OTOH は、代理キーまたは SalesId である可能性がありますが、いずれにしても一意の値です。これがクラスター化されている場合、通常の一意のインデックスと比較してメリットはありません。

編集: 議論のためにこの特定のテーブルを取り上げましょう - それはさらに微妙な点を明らかにします.

「自然な」主キーは、おそらくparentid + childidです。しかし、どの順序で?Parentid + childid は、childid + parentid よりも一意ではありません。クラスタリングの目的で、どの順序がより適切ですか? 「特定のアイテムについて、その構成要素は何ですか」と尋ねたいので、parentid + childid でなければならないと考える人もいるでしょう。しかし、それとは逆に、「特定の構成要素について、それはどの項目のコンポーネントですか?」と尋ねたいとは思わないのではないでしょうか。

クエリを満たすために必要なすべての情報をインデックス内に含む「カバリング インデックス」の考慮事項を追加します。そうであれば、残りのレコードを読む必要はありません。したがって、クラスタリングは何のメリットもありません。インデックスを読むだけで十分です。(ちなみに、これは、同じフィールドのペアに反対の順序で 2 つのインデックスを付けることを意味します。これは、このような場合に適切なことかもしれません。または、少なくとも一方に複合インデックス、もう一方に単一フィールド インデックス。 )

しかし、それでもクラスタ化する必要があるということにはなりません。これは最終的に、実際にはどのクエリが Quantity フィールドのレコードを取得する必要があるかによって決定されます。

このような明確な例であっても、他のインデックスについては、実際のデータでテストできるようになるまで (明らかに運用前に) 決定を下すのが原則として最善です。しかし、ここで推測を求めることは無意味です。テストは常に適切な答えを提供します。

問題が発生するまで (ほとんどの場合、発生することはありません)、挿入を遅くすることを心配する必要はありません。また、測定可能な利益のために有用なインデックスを放棄することを確認するためにテストできます。

ただし、このようなジャンクション テーブルは他の多くの種類のクエリにも頻繁に関与するため、まだ確実ではありません。そのため、アプリケーションがゲル化し、テスト用のデータ量が利用可能になったときに、必要に応じて 1 つを選択してテストします。

ところで、parentid + childid の PK で終わると思います。childid の一意でないインデックス。そして最初にクラスター化されました。サロゲート PK を使用する場合でも、parentid + childid にクラスター化された一意のインデックスが必要です。代理キーのクラスタリングが最適である可能性はほとんどありません。

于 2008-12-23T16:48:04.387 に答える
2

ここでの本当の質問は、何を最も多く照会するかということです。常に両方の値を探している場合は、クラスター化されたものがペアになっている必要があります。どちらか一方に対してより多くのクエリを実行する場合は、その特定のものにクラスター化する必要があります。

于 2008-12-23T16:32:40.470 に答える
0

あなたの最後の発言に焦点を合わせたいと思います。「このテーブルは、書き込みよりも読み取りの方がはるかに影響を受けると思います。」この場合は、インデックスを多用することをお勧めします。すべてでインデックスを多用しない理由は、テーブルへの更新と挿入に対してパフォーマンスのペナルティを支払うためです。書き込みよりも多くの読み取りを提供するテーブルがある場合は、インデックスの代償を払います。

何をクラスター化するかについては、テーブルがどのように最適に使用されるかを考える必要があります。テーブルが多くの範囲クエリ (WHERE col1 IS BETWEEN a AND b) の影響を受ける場合は、テーブルをクラスタ化して、範囲クエリがディスク上で順番に設定されるようにします。SQL Server では、PK を使用して無料でクラスターを取得することがあり、最初にクラスター化するのに最適なものを忘れてしまいます。

テーブルの FK 制約については、書き込みよりも読み取りの方が多いと述べたので、これは許容できる場合があります。これが多くの挿入を伴うテーブルであった場合、各 FK 制約は親テーブルに対する検証を必要とし、それでは希望するパフォーマンスが得られない可能性があります。

素晴らしい質問です。

于 2008-12-23T16:41:30.377 に答える
-1

「複合主キーを検討している」とおっしゃっているので、考えを変える時間はまだあるかもしれません。私は多くの複合キーを使用してきましたが、使用したくない理由を見つけ続けています。多分他の人は私に同意しないでしょう。

ミッチェルの答えに同意します。クラスターは、最も頻繁にクエリを実行します。

于 2008-12-23T16:40:04.840 に答える