web-dev-qa-db-ja.com

1つの大きな結合または複数のクエリのどちらがパフォーマンスを向上させますか?

注文というテーブルがあります。注文の1つの列はcustomer_idです
10個のフィールドを持つcustomersというテーブルがあります

注文オブジェクトの配列を作成し、注文オブジェクトに埋め込まれているのが顧客オブジェクトである場合、2つのオプションが与えられると、2つの選択肢があります。

オプション1:

a。最初のクエリ注文テーブル。 b。レコードをループし、personsテーブルにクエリを実行して、personのレコードを取得します

これは次のようになります。

 Select * from APplications

 Select * from Customer where id = 1
 Select * from Customer where id = 2
 Select * from Customer where id = 3
 Select * from Customer where id = etc . . .

オプション2:

a。すべてのフィールドで結合を行う

1 + [numberOforders]クエリ(数百以上になる可能性があります)に対して1つのクエリしか実行していないため、これは明らかな#2です。

これは次のようになります。

 Select * from Applications a, Customers c
 Innerjoin c.id = a.customerID

私の主な質問は、注文テーブルにIDが含まれている注文テーブル(顧客と同様)から外れた他のテーブルが10個ある場合はどうなるかということです。これらの10個のテーブルを結合する単一のクエリを実行する必要がある場合、またはある時点でこれを実行するのは非効率的ですか。

任意の提案が役立ちます..高速パフォーマンスを確保するための最適化はありますか

26
leora

テーブルがたくさんある場合でも、単一の結合の方がおそらく効率的であると言っているすべての人に同意します。また、アプリケーションコードで作業を行うよりも開発作業が少なくて済みます。これは、テーブルが適切にインデックス付けされており、各外部キー列にインデックスがあり、(もちろん)各主キー列にインデックスがあることを前提としています。

最善の策は、最初に最も簡単なアプローチ(大きな結合)を試して、それがどの程度うまく機能するかを確認することです。それがうまく機能すれば、素晴らしいです-これで完了です。パフォーマンスが低い場合は、クエリのプロファイルを作成し、テーブルで欠落しているインデックスを探します。

(anijhawが述べたように)ネットワークのラウンドトリップの数が原因で、オプション#1はうまく機能しない可能性があります。これは「selectN + 1」問題と呼ばれることもあります。1つのSELECTを実行してN個のアプリケーションのリストを取得してから、ループ内でN個のSELECTを実行して顧客を取得します。この一度に記録するループは、アプリケーションプログラマーにとって自然なことです。ただし、SQLは、データセット全体を一度に操作するとはるかにうまく機能します。

インデックス作成が適切であってもオプション#2が遅い場合は、キャッシュを調べることをお勧めします。データベース(サマリーテーブルまたはマテリアライズド/インデックス付きビューを使用)、アプリケーション(十分なRAMがある場合)、またはmemcachedなどの専用キャッシュサーバーにキャッシュできます。もちろん、これはクエリ結果がどれだけ最新である必要があるかによって異なります。すべてを完全に最新にする必要がある場合は、基になるテーブルが更新されるたびにキャッシュを更新する必要があります。キャッシュは複雑になり、役に立たなくなります。

ただし、これはレポートクエリのように聞こえますが、多くの場合、レポートはリアルタイムである必要はありません。したがって、キャッシングが役立つ場合があります。

DBMSによっては、同じデータベースにアクセスする他のクエリに対するこのクエリの影響についても考慮する必要があります。 DBMSでリーダーがライターをブロックできる場合、実行に時間がかかると、このクエリによってテーブルの更新が妨げられる可能性があります。それは悪いことです。 Oracleにはこの問題はなく、「コミットされたスナップショットの読み取り」モードで実行された場合もSQLServerには問題がありません。私はMySQLについては知りません。

19
Richard Beier

このcustomer_idがcustomer-tableで一意である(そして他のIDが他のテーブルで一意である)場合、クエリはアプリケーションごとに1行しか返さないため、単一のSELECTを実行する方が確実に効率的です。

必要なすべての顧客を1つのクエリに結合することは最適化されますが、単一のSELECTを多数使用することはできません。

[〜#〜]編集[〜#〜]
これを、50.000のアプリケーションと50.000の一致する顧客を持つOracle PL/SQLで試しました。

1つのクエリですべてを選択するソリューション
0.172 s

1回のSELECTですべての顧客を選択するソリューション
1.984 s

そして、これは他のクライアントやネットワーク経由でアクセスするときに悪化する可能性が最も高いです。

7
Peter Lang

単一の結合は、2つの主な理由でより高速になるはずです。

ネットワーク経由でクエリを実行している場合、単一のクエリではなく複数のクエリを使用するとオーバーヘッドが発生します。

結合はクエリオプティマイザを使用してDBMS内で最適化されるため、複数のクエリを実行するよりも高速になります。

2
anijhaw

これらの10個のテーブルを結合する単一のクエリを実行する必要がありますか、それともある時点で非効率的ですか

これらのテーブルはすべて順序に結合されます-返されるすべてのレコードは関連しています。可能な限り少ないクエリまたは操作に関連するすべてのものを取得することについて、非効率的なことは何もありません。

個別のクエリを使用すると、クエリ間でデータが変更される可能性が高くなります。

1
OMG Ponies

私の意見では、DBMSは結合が実行される前に常にwhere句を実行するため、単一結合の方が高速です。これは、結合が発生する前に、関連するすべてのテーブルがすでに可能な最小サイズに縮小されていることを意味します。

必要なものを取得するには、ある時点でこれらすべてのテーブルから読み取る必要があるという事実が残っています...したがって、一度実行すると、さらに効率的になります。

ここで重要なのは、結合する前にテーブルがすべて最小サイズに切り詰められていることと、内部結合を使用していることです。これらの両方の条件が変化した場合(一部の外部結合は問題ありません)、問題が発生している可能性があります。

1
Sudhir Jonathan