外部キーはクエリのパフォーマンスを向上させますか?


149

ProductsとProductCategoriesという2つのテーブルがあるとします。両方のテーブルは、CategoryIdに関係があります。そしてこれがクエリです。

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category
FROM Products p
INNER JOIN ProductCategories c ON p.CategoryId = c.CategoryId
WHERE c.CategoryId = 1;

実行プランを作成すると、予想どおり、テーブルProductCategoriesがクラスターインデックスのシークを実行します。しかし、テーブル製品の場合、クラスターインデックススキャンを実行するので、疑問に思います。FKがクエリのパフォーマンス向上に役立たないのはなぜですか?

したがって、Products.CategoryIdにインデックスを作成する必要があります。再度実行プランを作成すると、両方のテーブルがインデックスシークを実行します。また、推定されるサブツリーのコストが大幅に削減されます。

私の質問は:

  1. FKは関係の制約に役立ちますが、他に何か便利なことはありますか?クエリのパフォーマンスは向上しますか?

  2. すべてのテーブルのすべてのFK列(Products.CategoryIdなど)にインデックスを作成する必要がありますか?

回答:


186

外部キーは参照整合性ツールであり、パフォーマンスツールではありません。少なくともSQL Serverでは、FKを作成しても関連するインデックスは作成されません。ルックアップ時間を改善するには、すべてのFKフィールドにインデックスを作成する必要があります。


40
優れたモデルは(一般的に)パフォーマンスが向上します。
ケニーエビット2011年

10
「外部キーはリレーショナル整合性ツールです」-「リレーショナル」という言葉は注意して使用してください。外部キーはデータベースの概念であり、参照整合性制約の省略形です。これらは、リレーショナルモデルの一部ではありません。あなたはタイプミスをしたと思います。
2013年

7
@ケニーよくありますが、より良いモデルの方がコストがかかる場合があります。適例:外部キーにより、処理がより多くではなく、より多く発生します。
Hans

8
外部キー少なくともMySQLではパフォーマンスを向上させます。さらに、FKを作成してもインデックスは作成されません。FKの作成が必要とインデックス
フェリックス・ガニオン-グルニエ

15
この答えは質問に答えないため、ほとんど役に立ちません。外部キーがパフォーマンスに(プラスの)影響を与えること意図していないことを知るのは素晴らしいことですが、問題は意図ではなく現実に関するものでした。
John

58

外部キーはパフォーマンスを改善(および害)する可能性があります

  1. ここで述べたように:外部キーはパフォーマンスを向上させます

  2. 検索を減らすために、常にFK列にインデックスを作成する必要があります。SQL Serverはこれを自動的に行いません。

編集する

リンクが無効になっているように見える(気づくためにChrisにkudosしている)ため、以下に外部キーがパフォーマンスを改善(および害)する理由の要点を示します。

外部キーはパフォーマンスを改善できますか

外部キー制約は、データの読み取り時のパフォーマンスを向上させますが、同時に、データの挿入/変更/削除時のパフォーマンスを低下させます。

クエリを読み取る場合、外部キー制約は事前宣言されたルールであるため、オプティマイザは外部キー制約を使用して、より効率的なクエリプランを作成できます。たとえば、オプティマイザは外部キー制約のためにプランの特定の部分を実行する必要がないことを確認できるため、これには通常、クエリプランの一部をスキップすることが含まれます。


3
ここで彼らは、性能低下することのできる詳細な方法そのリンクだdevx.com/getHelpOn/10MinuteSolution/16595/0/page/2を
cmsjr

3
それは理にかなっていますが、大量の削除ステートメントを使用するだけでこれに遭遇します。おそらく、OLAP環境ではインデックス付けされていないFKによってパフォーマンスが向上し、OLTP環境ではパフォーマンスが低下するという結論になるはずです。
Lieven Keersmaekers、2009

1
この回答のリンクは無効です。これは、FKがパフォーマンスを向上させるための唯一の引数であるため、残念です。
Chris Moschini、2011年

1
@ChrisMoschini-私は今まであなたのコメントに気づきませんでした。あなたが述べたように、リンクは死んでいますが、その要点は私が投稿した新しいリンク(詳細を含む)で述べられています。
Lieven Keersmaekers 2012年

2
Win!のWayback Machine リンク この記事は、SQLMag.com(こちら)にもあります
John Eisbrener、2016年

15

外部キーは、データベースの整合性を確保するためのDBMSの概念です。

パフォーマンスへの影響/改善は、使用されているデータベーステクノロジーに固有のものであり、外部キーの目的に二次的なものです。

SQL Serverでは、すべての外部キーに少なくとも非クラスター化インデックスが設定されていることを確認することをお勧めします。

これで問題が解決することを願っていますが、詳細をリクエストしてください。


9
@Kenny Evitt整合性がない場合、データは役に立ちません。私はそれが非常に簡単に売れるのを見つけます。
HLGEM、2011

@HLGEMたまに404エラーが発生しても、それでも十分耐えられます。安価なリソースとそれほど複雑でないシステムを使用して見返りに優れたスループットを実現し、非常に簡単に販売できるようになりました。あなたはCAP定理に興味があるかもしれません。
Daniel Dinnyes、2011年

8
@Daniel Dinnyes、データの整合性は404エラーを取得することではありません。それは、使用可能なデータを持つことです。たとえば、開発者の能力不足のため、レポートの注文や財務データが失われないようにするためです。外部キーを使用しない理由はありません。
HLGEM 2011年

2
HLGEMに同意します。コードで整合性を処理できるようにすることは、常に良い考えとは限りません。多くの場合、データは意思決定に使用されますが、データが破損している場合、その決定は正確ではありません。
lepe

1
「外部キーはリレーショナル整合性ツールです」-「リレーショナル」という言葉は注意して使用してください。外部キーはデータベースの概念であり、参照整合性制約の省略形です。これらは、リレーショナルモデルの一部ではありません。あなたはタイプミスをしたと思います。
2013年

4

パフォーマンスの最善策は、頻繁に使用するフィールドでインデックスを使用することです。SQL Serverを使用する場合、プロファイラーを使用して特定のデータベースをプロファイリングし、出力するファイルを取得して、チューニングウィザードを使用して、インデックスを配置する場所に関する推奨事項を受け取ることができます。また、プロファイラーを使用して実行時間の長いストアドプロシージャをフラッシュするのも好きです。毎週公開している最悪の違反者リストのトップ10を持っています。


3

これを使用して、クエリをより効率的にすることができます。SQL Serverでクエリを再構築して、内部結合の代わりに外部結合を使用することができます。これにより、SQLサーバーが列にnullがあるかどうかを確認する必要がなくなります。外部キーの関係がすでにそれを強制しているので、その修飾子を入れる必要はありません。

したがって、この:

    select p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
from Products p inner join ProductCategories c on p.CategoryId = c.CategoryIdwhere c.CategoryId = 1;

これになる:

SELECT p.ProductId, p.Name, c.CategoryId, c.Name AS Category 
FROM ProductCategories c 
LEFT OUTER JOIN Products P ON
c.CategoryId = p.CategoryId 
WHERE c.CategoryId = 1;

これは必ずしも小さなクエリで大きなパフォーマンスを発揮するわけではありませんが、テーブルが大きくなると、より効率的になります。


3
だけでなく、一般的に外部結合されている以下の内側には(参加するよりも効率的stackoverflow.com/a/2726683/155892あなたは暗黙的に内部結合にあなたの外部結合を有効にするには、データベースに頼っている(パフォーマンスを復元):今、あなたのクエリが誤解されています、)だけではなく、明示的にそれを行うの
マークSowulを

2

MySQL 5.7の場合、複数の結合を含むクエリを驚くほど高速化できます。

'explain'を使用してクエリを理解し、キーがまったく使用されていない4〜5個のテーブルを結合していることがわかりました。これらのテーブルに外部キーを追加するだけで、ロード時間は90%短縮されました。5秒以上かかったクエリの所要時間が500ミリ秒以下になりました。

それはすごい改善です!

そして、他の人が述べたように、関係の完全性を保証するという追加のボーナスを得ます。

これに加えて、参照整合性を保証することには、それ自体のパフォーマンス上の利点もあります。これには、外部キーを持つテーブルが外部テーブルで「最新」であることを保証するという2次的な効果があります。ユーザーテーブルとコメントテーブルがあり、コメントテーブルで統計を行っているとします。おそらく、ユーザーを完全に削除すると、ユーザーのコメントも不要になります。


追加する前に、テーブルに外部キーを生成するために必要なインデックスがありましたか?
ジョージ

1

テーブルに外部キーを追加しても、パフォーマンスは向上しません。単に、ProductCategoriesテーブルデータベースにレコードを挿入する場合、外部キー列が製品テーブルの主キー値に存在する値を見つけようとすると、このルックアップは、操作は、ProductCategoriesテーブルに新しいエントリを追加するたびにデータベースのオーバーヘッドになります。したがって、外部キーを追加してもデータベースのパフォーマンスは向上しませんが、データベースの整合性は考慮されます。はい、プログラム内のデータベースにレコードが存在することを確認するために多くのクエリを実行する代わりに、外部キーを使用して整合性を確認している場合は、dbのパフォーマンスが向上します。


0

SQLサーバーについてはあまり知りませんが、Oracleの場合、外部キー列があると、データ読み込みのパフォーマンスが低下します。これは、データベースが挿入ごとにデータの整合性をチェックする必要があるためです。そして、はい、既に述べたように、外部キー列にインデックスを付けることは良い習慣です。


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