web-dev-qa-db-ja.com

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

概念的な質問:個々のクエリは結合よりも速いですかまたは:クライアント側で必要なすべての情報をoneSELECTステートメントを使用するか、それとも便利なだけ使用しますか?

TL; DRmy結合クエリが個々のクエリの実行よりも時間がかかる場合、これは私の障害ですか、またはこれは予想されることですか?

まず、私はあまりデータベースに精通していないため、それは私だけかもしれませんが、複数のテーブルから情報を取得する必要がある場合、個々のテーブルに対する複数のクエリを介してこの情報を取得する方が「多くの場合」速くなることに気づきました(たぶん) 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 |

もちろん、私はこれらを使ってパフォーマンスを測定しませんでしたが、1つ観察するかもしれません:

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

これから一般化します(これまでのところ限り):

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

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

46
Martin

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

あらゆるパフォーマンスシナリオで、あなたはテストと測定どちらが速いかを確認するためのソリューションを実行する必要があります。

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

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

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

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

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

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

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

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

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

データベースに関しては経験がないとおっしゃっていたので、データベースの設計とパフォーマンスのチューニングについてもっと学ぶことをお勧めします。ここに問題があるのは間違いないと思います。非効率的なSQLクエリも可能ですが、問題になる可能性が低い単純なスキーマを使用します。

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

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

46
Jon Seigel

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

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

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

また、内部結合によってデータが削除された場合にどうなるかを検討する必要があります。

6
Leigh Riffel

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

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

適度な量のデータを返す中規模のクエリの実行に数分かかることはよく知られています。正しいインデックス作成と適切な統計により、これがミリ秒に短縮されます。

2
Michael Green