JOIN クエリは複数のクエリよりも高速ですか? (メイン クエリを実行し、メイン クエリの結果に基づいて他の多くの SELECT を実行します)
それらを結合すると、アプリケーションの設計が非常に複雑になるため、私は尋ねています
それらがより高速である場合、誰かがどれだけ大まかに概算できますか? 1.5倍なら気にしないけど、10倍なら気にするかな。
JOIN クエリは複数のクエリよりも高速ですか? (メイン クエリを実行し、メイン クエリの結果に基づいて他の多くの SELECT を実行します)
それらを結合すると、アプリケーションの設計が非常に複雑になるため、私は尋ねています
それらがより高速である場合、誰かがどれだけ大まかに概算できますか? 1.5倍なら気にしないけど、10倍なら気にするかな。
内部結合の場合、一致する行のみを取得するため、1 つのクエリで十分です。左結合の場合、複数のクエリの方がはるかに優れています...私が行った次のベンチマークを見てください。
5 つの結合を持つ単一のクエリ
クエリ: 8.074508 秒
結果サイズ: 2268000
連続して 5 つのクエリ
合計クエリ時間: 0.00262 秒
結果サイズ: 165 (6 + 50 + 7 + 12 + 90)
.
どちらの場合も同じ結果が得られることに注意してください (6 x 50 x 7 x 12 x 90 = 2268000)
左結合は、冗長データで指数関数的に多くのメモリを使用します。
2 つのテーブルの結合のみを行う場合、メモリ制限はそれほど悪くないかもしれませんが、通常は 3 つ以上のテーブルを結合すると、異なるクエリの価値が生じます。
ちなみに、MySQL サーバーはアプリケーション サーバーのすぐそばにあるため、接続時間はごくわずかです。接続時間が数秒の場合、おそらくメリットがあります
フランク
私は実際に自分で答えを探してこの質問に来ました。与えられた答えを読んだ後、考慮すべき変数が非常に多いため、DBクエリのパフォーマンスを比較する最良の方法は実際の数値を取得することであることに同意することができますただ、数値を比較してもほとんどの場合ダメだとも思います。私が言いたいのは、数値は常に許容可能な数値と比較されるべきであり、互いに比較されるべきではないということです.
クエリの 1 つの方法が 0.02 秒かかり、もう 1 つの方法が 20 秒かかる場合、それは大きな違いです。しかし、クエリの 1 つの方法が 0.0000000002 秒かかり、もう 1 つの方法が 0.0000002 秒かかる場合はどうなるでしょうか。どちらの場合も、一方の方法はもう一方の方法よりもなんと 1000 倍高速ですが、2 番目のケースでも本当に「なんと」なのですか?
私が個人的に見ている結論は、パフォーマンスが良い場合は、簡単な解決策を選択することです。
問題は、これらのレコードに1 対 1 の関係があるのか、それとも1対多の関係があるのかということです。
TLDR 回答:
1 対 1 の場合は、JOIN
ステートメントを使用します。
1 対多の場合SELECT
は、サーバー側コードの最適化で 1 つ (または多数) のステートメントを使用します。
最適化に SELECT を使用する理由と方法
SELECT
JOIN
'ing (結合ではなく複数のクエリを使用)は、指数関数的なメモリ リークの問題があるため、1 対多の関係に基づく大規模なレコード グループに対して最適な効率を生み出します。すべてのデータを取得し、サーバー側のスクリプト言語を使用して整理します。
SELECT * FROM Address WHERE Personid IN(1,2,3);
結果:
Address.id : 1 // First person and their address
Address.Personid : 1
Address.City : "Boston"
Address.id : 2 // First person's second address
Address.Personid : 1
Address.City : "New York"
Address.id : 3 // Second person's address
Address.Personid : 2
Address.City : "Barcelona"
ここでは、1 つの select ステートメントですべてのレコードを取得しています。JOIN
これは、別のクエリのサブコンポーネントとして、一度に 1 つずつ、これらのレコードの小さなグループを取得するよりも優れています。次に、次のようなサーバー側コードで解析します...
<?php
foreach($addresses as $address) {
$persons[$address['Personid']]->Address[] = $address;
}
?>
最適化に JOIN を使用しない場合
JOIN
1 つのレコードとの 1 対 1 の関係に基づいてレコードの大規模なグループを作成するとSELECT
、次のレコード タイプを取得するだけの複数のステートメントを次々に実行する場合と比較して、最適な効率が得られます。
ただしJOIN
、1 対多の関係でレコードを取得する場合は非効率的です。
例: データベース Blogs には、関心のある 3 つのテーブル、Blogpost、Tag、および Comment があります。
SELECT * from BlogPost
LEFT JOIN Tag ON Tag.BlogPostid = BlogPost.id
LEFT JOIN Comment ON Comment.BlogPostid = BlogPost.id;
ブログ投稿が 1 つ、タグが 2 つ、コメントが 2 つある場合、次のような結果が得られます。
Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag2, comment1,
Row4: tag2, comment2,
各レコードがどのように複製されているかに注目してください。よし、コメント2つとタグ2つで4行。4 つのコメントと 4 つのタグがある場合はどうなるでしょうか。8 行ではなく、16 行になります。
Row1: tag1, comment1,
Row2: tag1, comment2,
Row3: tag1, comment3,
Row4: tag1, comment4,
Row5: tag2, comment1,
Row6: tag2, comment2,
Row7: tag2, comment3,
Row8: tag2, comment4,
Row9: tag3, comment1,
Row10: tag3, comment2,
Row11: tag3, comment3,
Row12: tag3, comment4,
Row13: tag4, comment1,
Row14: tag4, comment2,
Row15: tag4, comment3,
Row16: tag4, comment4,
テーブルやレコードなどを追加すると、問題はすぐに何百もの行に膨れ上がり、ほとんどが冗長なデータでいっぱいになります。
これらの重複はあなたに何をもたらしますか? メモリ (SQL サーバーと重複を削除しようとするコード内) とネットワーク リソース (SQL サーバーとコード サーバーの間)。
ソース: https://dev.mysql.com/doc/refman/8.0/en/nested-join-optimization.html ; https://dev.mysql.com/doc/workbench/en/wb-relationship-tools.html
50,000 行のテーブルから 1 行を選択し、100,000 行のテーブルから 1 行と結合する簡単なテストを行いました。基本的に次のように見えました:
$id = mt_rand(1, 50000);
$row = $db->fetchOne("SELECT * FROM table1 WHERE id = " . $id);
$row = $db->fetchOne("SELECT * FROM table2 WHERE other_id = " . $row['other_id']);
対
$id = mt_rand(1, 50000);
$db->fetchOne("SELECT table1.*, table2.*
FROM table1
LEFT JOIN table1.other_id = table2.other_id
WHERE table1.id = " . $id);
2 つの選択方法では、50,000 回の読み取りに 3.7 秒かかりましたが、自宅の遅いコンピューターでは JOIN に 2.0 秒かかりました。INNER JOIN と LEFT JOIN は違いはありませんでした。複数の行をフェッチすると (たとえば、IN SET を使用して)、同様の結果が得られました。
私の経験では、特に大きなデータセットを取得する場合は、通常、複数のクエリを実行する方が高速であることがわかりました。
PHPなどの別のアプリケーションからデータベースと対話する場合、サーバーへの1回のトリップが複数回行われるという議論があります。
サーバーへのトリップ数を制限し、複数のクエリを実行する方法は他にもあります。これらのクエリは、多くの場合、高速であるだけでなく、アプリケーションを読みやすくします(mysqli_multi_queryなど)。
私はSQLに関しては初心者ではありません。開発者、特にジュニアは、見た目がスマートであるため、非常に巧妙な結合を作成するために多くの時間を費やす傾向があると思いますが、実際には、見た目が良いデータを抽出するスマートな方法があります。単純。
最後の段落は個人的な意見でしたが、これがお役に立てば幸いです。私はあなたがベンチマークするべきだと言っている他の人たちに同意します。どちらのアプローチも特効薬ではありません。
スループットの点で高速になりますか? おそらく。ただし、(データベースとスキーマによっては) 一度により多くのデータベース オブジェクトをロックする可能性もあり、それによって同時実行性が低下します。私の経験では、実際にはデータベースが同じ LAN 上にあるほとんどの OLTP システムでは、実際のボトルネックがネットワークにあることはめったにありませんが、「データベースのラウンドトリップが少ない」という議論に惑わされることがよくあります。
結合を使用する必要があるかどうかは、何よりもまず、結合が理にかなっているかどうかです。他のほとんどすべてのケースではパフォーマンスが大幅に低下するため、その時点でのみパフォーマンスを考慮する必要があります。
パフォーマンスの違いは、クエリしている情報がどの程度関連しているかに大きく関係しています。結合は機能し、データが関連付けられており、適切にインデックスを作成している場合は高速ですが、多くの場合、冗長性が生じたり、必要以上の結果が得られたりします。また、データ セットが直接関連していない場合、それらを 1 つのクエリに貼り付けると、デカルト積 (基本的には行の可能なすべての組み合わせ) と呼ばれるものが得られますが、これはほとんど望んでいないことです。
これは多くの場合、多対 1 対多の関係によって発生します。たとえば、HoldOffHunger の回答では、投稿、タグ、およびコメントに対する単一のクエリについて言及されています。コメントはタグと同様に投稿に関連していますが、タグはコメントとは無関係です。
+------------+ +---------+ +---------+
| comment | | post | | tag |
|------------|* 1|---------|1 *|---------|
| post_id |-----| post_id |-----| post_id |
| comment_id | | ... | | tag_id |
| user_id | | | | ... |
| ... | | | | ... |
+------------+ +---------+ +---------+
この場合、これが少なくとも 2 つの別個のクエリであることが明確に優れています。タグとコメントを結合しようとすると、両者の間に直接の関係がないため、タグとコメントの可能な限りの組み合わせになってしまいます。many * many == manymany
. それとは別に、投稿とタグは無関係であるため、これら 2 つのクエリを並行して実行できるため、潜在的な利益が得られます。
ただし、別のシナリオを考えてみましょう。投稿に添付されたコメントと、コメント投稿者の連絡先情報が必要です。
+----------+ +------------+ +---------+
| user | | comment | | post |
|----------|1 *|------------|* 1|---------|
| user_id |-----| post_id |-----| post_id |
| username | | user_id | | ... |
| ... | | ... | +---------+
+----------+ +------------+
これは、結合を検討する必要がある場所です。はるかに自然なクエリであることは別として、ほとんどのデータベース システム (MySQL を含む) では、多くの賢い人々がクエリを最適化するために多大な労力を費やしています。個別のクエリの場合、各クエリは前のクエリの結果に依存するため、クエリを並行して実行することはできず、合計時間はクエリの実際の実行時間だけでなく、結果のフェッチ、ふるい分けに費やされた時間にもなります。それらを介して、次のクエリの ID を取得したり、行をリンクしたりします。
ここに 100 個の便利なクエリのリンクがあります。これらは Oracle データベースでテストされていますが、SQL が標準であることを覚えておいてください。Oracle、MS SQL Server、MySQL、および他のデータベースの違いは SQL ダイアレクトです。