個々のクエリは結合よりも高速ですか?


44

概念的な質問:個々のクエリは結合よりも高速ですか、またはクライアント側で必要なすべての情報を1つの SELECTステートメントに絞り込もうとするか、便利だと思われるだけ使用する必要がありますか?

TL; DR:結合されたクエリに個々のクエリを実行するよりも時間がかかる場合これは私のせいですか、これは予想されることですか?

まず、データベースに精通していないので、私だけかもしれませんが、複数のテーブルから情報を取得する必要がある場合、個々のテーブルで複数のクエリを使用してこの情報を取得する方が「多くの場合」高速であることに気付きました単純な内部結合を含む)、1つのクエリですべてのデータを取得できる(複雑な)結合クエリを作成しようとするクライアント側でデータをパッチします。

私は非常に単純な例を1つまとめようとしました。

SQLフィドル

スキーマのセットアップ

CREATE TABLE MASTER 
( ID INT NOT NULL
, NAME VARCHAR2(42 CHAR) NOT NULL
, CONSTRAINT PK_MASTER PRIMARY KEY (ID)
);

CREATE TABLE DATA
( ID INT NOT NULL
, MASTER_ID INT NOT NULL
, VALUE NUMBER
, CONSTRAINT PK_DATA PRIMARY KEY (ID)
, CONSTRAINT FK_DATA_MASTER FOREIGN KEY (MASTER_ID) REFERENCES MASTER (ID)
);

INSERT INTO MASTER values (1, 'One');
INSERT INTO MASTER values (2, 'Two');
INSERT INTO MASTER values (3, 'Three');

CREATE SEQUENCE SEQ_DATA_ID;

INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.5);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 1, 1.7);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 2, 2.3);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.14);
INSERT INTO DATA values (SEQ_DATA_ID.NEXTVAL, 3, 3.7);

クエリA

select NAME from MASTER
where ID = 1

結果

| NAME |
--------
|  One |

クエリB

select ID, VALUE from DATA
where MASTER_ID = 1

結果

| ID | VALUE |
--------------
|  1 |   1.3 |
|  2 |   1.5 |
|  3 |   1.7 |

クエリC

select M.NAME, D.ID, D.VALUE 
from MASTER M INNER JOIN DATA D ON M.ID=D.MASTER_ID
where M.ID = 1

結果

| NAME | ID | VALUE |
---------------------
|  One |  1 |   1.3 |
|  One |  2 |   1.5 |
|  One |  3 |   1.7 |

もちろん、これらのパフォーマンスは測定しませんでしたが、次のことを観察できます。

  • クエリA + Bは、クエリCと同じ量の使用可能な情報を返します。
  • A + Bは1 + 2x3 == 7「データセル」をクライアントに返す必要があります
  • Cは、3x3 == 9「データセル」をクライアントに返す必要があります。これは、結合により、結果セットに冗長性が自然に含まれるためです。

これから一般化する(これまでの限り取得):

結合されたクエリは、常に同じ量の情報を受け取る個々のクエリよりも多くのデータを返す必要があります。データベースはデータをまとめる必要があるため、大規模なデータセットの場合、(少なくとも)より多くのデータをクライアントに返す必要があるため、データベースは個々のクエリよりも単一の結合クエリでより多くの作業を行う必要があると想定できます。

これから、クライアント側のクエリを複数のクエリに分割するとパフォーマンスが向上することがわかった場合、これは単なる方法であり、結合されたクエリを台無しにすることを意味しますか?


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
ジャックダグラス

1
ベンチマークを実行し、Mediumの記事に結果を投稿しまし。ここに回答を追加しますが、別の質問既に回答しているため、同じ回答を複数の質問に投稿することは嫌になります
ベンジャミン

回答:


45

個々のクエリは結合よりも高速ですか、または、クライアント側で必要なすべての情報を1つのSELECTステートメントに絞り込もうとするか、または便利だと思われる数だけ使用する必要がありますか?

パフォーマンスのシナリオでは、する必要がテストし、測定高速であるかを確認するためのソリューションを

ただし、適切に調整されたデータベースからの結合された結果セットは、ソース行をクライアントに返してそこに結合するよりも高速で拡張性が高い場合がほとんどです。特に、入力セットが大きく、結果セットが小さい場合、両方の戦略のコンテキストで次のクエリを検討してください:それぞれが5 GBの2つのテーブルを結合し、結果セットを100行にします。それは極端ですが、あなたは私のポイントを参照してください。

複数のテーブルから情報を取得する必要がある場合、個々のテーブル(単純な内部結合を含む可能性があります)で複数のクエリを介してこの情報を取得し、クライアント側でデータをパッチする方が「多くの場合」高速であることに気付きました1つのクエリですべてのデータを取得できる(複雑な)結合クエリを作成します。

データベーススキーマまたはインデックスを改善して、投げかけているクエリをより適切に処理できる可能性が高いです。

結合クエリは、常に同じ量の情報を受け取る個々のクエリよりも多くのデータを返す必要があります。

通常、これは当てはまりません。ほとんどの場合、入力セットが大きい場合でも、結果セットは入力の合計よりもはるかに小さくなります。

アプリケーションに応じて、クライアントに返される非常に大きなクエリ結果セットは即座に赤旗になります。データベースの近くでは実行できないこのような大きなデータセットでクライアントは何をしているのでしょうか。1,000,000行をユーザーに表示することは、控えめに言っても非常に疑わしいです。ネットワーク帯域幅も有限のリソースです。

データベースはデータをまとめる必要があるため、大規模なデータセットの場合、(少なくとも)より多くのデータをクライアントに返す必要があるため、データベースは個々のクエリよりも単一の結合クエリでより多くの作業を行う必要があると想定できます。

必ずしも。データのインデックスが正しく作成されていれば、大量のデータをスキャンする必要なく、データベースで結合操作がより効率的に実行される可能性が高くなります。さらに、リレーショナルデータベースエンジンは、結合のために低レベルで特別に最適化されています。クライアントスタックはそうではありません。

これから、クライアント側のクエリを複数のクエリに分割するとパフォーマンスが向上することがわかった場合、これは単なる方法であり、結合されたクエリを台無しにすることを意味しますか?

データベースに関しては未熟だと言っていたので、データベースの設計とパフォーマンスの調整についてさらに学ぶことをお勧めします。ここに問題があるのは確かです。非効率的なSQLクエリも可能ですが、単純なスキーマを使用することで問題が発生する可能性は低くなります。

今、それはパフォーマンスを改善する他の方法がないと言っているわけではありません。何らかのキャッシュメカニズムを使用することが意図されている場合は、中規模から大規模のデータセットをスキャンし、クライアントに返すことを選択できるシナリオがあります。キャッシングは素晴らしいものですが、設計が複雑になります。キャッシングは、アプリケーションに適さない場合もあります。

どこにも言及されていないことの1つは、データベースから返されるデータの一貫性を維持することです。別のクエリを使用する場合、スナップショット分離の形式がクエリのすべてのセットに使用されない限り、(多くの要因により)一貫性のないデータが返される可能性が高くなります。


ネットワーク帯域幅の+1も有限のリソースです。
ハリハーカー

OPは、JOINされたデータ結果セットは常に大きいと言っています。>結合されたクエリは常に、個々のクエリよりも多くのデータを返す必要があります。これは客観的には正しいと思います(> =の場合)。たとえば、結果セットのサイズが異なるため、ネットワーク上のデータが多くなります。これが当てはまらない例はありますか?Authors-> Postsに参加し、Authorsに "biography"というフィールドがあり、1MBのJSONフィールドで、100件の投稿のAuthorに対して、100MB対1MBを送信します。これは間違っていますか?
hytromo

6

もちろん、私はこれらでパフォーマンスを測定しませんでした

いくつかの良いサンプルコードを作成します。SQL Fiddleのタイミングを見ましたか?簡単な非科学的なパフォーマンステストでも、デモのクエリ3がクエリ1または2を個別に実行するのとほぼ同じ時間がかかることがわかります。1と2を組み合わせた場合、3倍の時間がかかり、クライアント側の結合が実行される前です。

データを増やすと、クエリ1とクエリ2の速度は異なりますが、データベースの結合はさらに高速になります。

また、内部結合がデータを削除している場合に何が起こるかを考慮する必要があります。


2

クエリオプティマイザーも検討する必要があります。その役割は、宣言型SQLを取得して、手順ステップに変換することです。手続き的な手順の最も効率的な組み合わせを見つけるために、インデックスの使用、並べ替え、中間結果セットのキャッシュ、その他のあらゆる種類の組み合わせも調べます。置換の数は、非常に単純なクエリのように見える場合でも、非常に多くなる可能性があります。

最適なプランを見つけるために行われる計算の多くは、テーブル内のデータの分散によって決まります。これらの分布はサンプリングされ、統計オブジェクトとして保存されます。これらが間違っている場合、オプティマイザーが不適切な選択をするように導きます。計画の早い段階での不適切な選択は、雪だるま式の効果の後でさらに悪い選択につながります。

適度な量のデータを返す中規模のクエリの実行に数分かかることは不明ではありません。正しいインデックスと適切な統計により、これはミリ秒に短縮されます。


-3

複数のクエリを使用する方法です。そのような単純なシナリオを処理する場合-クエリオプティマイザーのコストオーバーヘッドが要因です。データが増えると、ネットワークの非効率的な結合(冗長な行)が発生します。効率が向上するのは、データが多い場合のみです。

最後に、あなたが経験するのは多くの開発者が見るものです。DBAは常に「いいえ、結合します」と言いますが、現実はそうです。この場合、複数の単純な選択を行う方が速いです。


5
結合に「ネットワークの非効率性」はありません-それはすべてデータベースサーバーで発生するため、ネットワークは関与しません(dbリンクを介して結合している場合を除きます!)
Chris Saxon

2
ネットワーク層に圧縮があるかどうかを検討できます。OracleのSQL * Netは、同じ列で繰り返される値が効率的に圧縮されるという点で機能します。
デビッドアルドリッジ

3
@TomTomにはポイントがある場合とない場合があります(David Aldridgeのポイントのように、圧縮が重要です)が、言葉遣いが混乱しています。「参加のネットワークの非効率」?本当に、あなたが何を意味するのかが明白になるように修正してください。
ypercubeᵀᴹ

@ChrisSaxonは確かに存在します。レポート用のテーブル「title-> base-> table-rows」があり、これら3つのテーブルを内部結合するためにすべての行が必要です。各テーブルには長いvarcharが含まれているため、これらの長いvarcharを繰り返しているすべての行に対して何が起こるかがわかります。アプリケーション層は、これらのすべての文字列にメモリを割り当て、モデルに合わせてグループ化する必要があります。私は彼が何を意味するのかだと思いますので、より多くのデータが送信されます
MIKE

結合ではなく、選択した式に依存する@MIKE。また、ネットワーク圧縮が存在する場合があります。OracleデータベースのSQLで* Netの削除し、重複する値が繰り返さnicetheory.io/2018/01/11/...
クリス・サクソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.