web-dev-qa-db-ja.com

大きなクエリを複数の小さなクエリに分割する方が良いですか?

目的の結果を生成するために、いくつかのテーブルをサブ選択ステートメントと一緒に結合する非常に大きなクエリを必要とする状況があります。

私の質問は、複数の小さなクエリの使用を検討し、複数の呼び出しでDBにクエリを実行することで論理演算をアプリケーションレイヤーに組み込む必要があるか、それともすべてを一度に実行する方が良いですか?
たとえば、次のクエリを考えてみましょう:

SELECT *
FROM   `users`
WHERE  `user_id` IN (SELECT f2.`friend_user_id`
                     FROM   `friends` AS f1
                            INNER JOIN `friends` AS f2
                              ON f1.`friend_user_id` = f2.`user_id`
                     WHERE  f2.`is_page` = 0
                            AND f1.`user_id` = "%1$d"
                            AND f2.`friend_user_id` != "%1$d"
                            AND f2.`friend_user_id` NOT IN (SELECT `friend_user_id`
                                                            FROM   `friends`
                                                            WHERE  `user_id` = "%1$d"))
       AND `user_id` NOT IN (SELECT `user_id`
                             FROM   `friend_requests`
                             WHERE  `friend_user_id` = "%1$d")
       AND `user_image` IS NOT NULL
ORDER  BY Rand() 
LIMIT %2$d

それを行う最良の方法は何ですか?

13
Hamed Momeni

ここでは、datagodを使用した大規模で複雑なクエリに同意しません。私はこれらがまとまりがない場合にのみ問題と見なします。パフォーマンスに関しては、プランナーが情報の取得方法をより自由にできるため、これらはほとんど常に優れています。ただし、大規模なクエリは、保守性を考慮して作成する必要があります。一般に、単一のクエリが200行以上続く場合でも、単純で適切に構造化されたSQLはデバッグが容易であることがわかりました。これは、通常、どのような問題を扱っているかをかなりよく理解しているため、クエリ内に確認する必要がある領域がわずかしかないためです。

SQLの構造が壊れると、メンテナンスの問題であるIMEが発生します。副ビューの長く複雑なクエリは、インラインビューと同様に、可読性とトラブルシューティングを損なうため、長いクエリではこれらの両方を回避する必要があります。代わりに、可能な場合はVIEWを使用し(MySQLを使用している場合、ビューはそれほどうまく機能しませんが、他のほとんどのデータベースでは機能します)、それらが機能しない一般的なテーブル式を使用します(MySQLはこれらをサポートしていません)ところで)。

長く複雑なクエリは、where句をシンプルに保つ保守性とパフォーマンスの両方のケースと、副選択ではなく結合を使用してできる限り多くのことを行う場合の両方で、非常にうまく機能します。目標は、「レコードが表示されない」ようにして、クエリ内の非常に具体的な場所をいくつか確認できるようにすることです(結合でドロップされるか、where句でフィルターで除外されますか?)。したがって、メンテナンスチーム実際に物事を維持することができます。

スケーラビリティに関しては、プランナーの柔軟性が高いほど良いことです。

編集:あなたはこれがMySQLであることを言及しているので、ビューがそれをうまく実行する可能性は低く、CTEは問題外です。さらに、与えられた例は特に長くも複雑でもないので問題ありません。

14
Chris Travers

これらの大きくて複雑なクエリをサポート/クリーンアップする必要がある人として、私はそれらをいくつかの小さな理解しやすいチャンクに分割する方がはるかに良いと思います。これは必然的にパフォーマンスの観点からは優れていませんが、少なくともSQLに適切なクエリプランを作成する機会を与えています。

あなたをフォローしている人々の生活を楽にし、彼らはあなたについて良いことを言うでしょう。彼らを厳しくしなさい、そうすれば彼らはあなたをののしる。

8
datagod

2つのキーワードのクエリパフォーマンスとスケーラビリティに対する私の2セント:

Query-Performance: SQL Serverの並列処理は、クエリをマルチスレッド検索に分割するのに非常に優れているため、クエリのパフォーマンスをどの程度向上させることができるかわかりません。 SQLサーバー。ただし、実行計画を見て、実行時にどの程度の並列処理が得られるかを確認し、結果を両方の方法で比較する必要があります。同じまたはより良いパフォーマンスを得るためにクエリヒントを使用する必要がある場合、クエリヒントは後で最適化されない可能性があるため、IMOを使用する価値はありません。

スケーラビリティ: datagodが述べているように、クエリを読み取る方が簡単かもしれません。新しいクエリを他の領域でも使用できるが、それらを使用しない場合は、クエリを個別のクエリに分割することは理にかなっています。他の呼び出しについても、1つのタスクを管理するためのストアドプロシージャはさらに多くなり、IMOはスケーラビリティに貢献しません。

5
Ali Razeghi

場合によっては、大きく複雑なクエリを小さなクエリに分割するしかありません。これを判断する最良の方法は、EXPLAINステートメントをSELECTステートメントと組み合わせて使用​​することです。データベースがデータをフェッチするために行うトレース/スキャンの数は、EXPLAINクエリによって返された「行」の値の積です。この例では、10個のテーブルを結合するクエリがありました。特定のレコードについては、トレースは409Mに達し、DBをブログに記録し、DBサーバーのCPU使用率を300%以上押し上げました。クエリをはるかに速く分割することで、同じ情報を取得することができました。

つまり、要するに、複雑なクエリや大きなクエリを分割することが理にかなっている場合もありますが、多くの場合、パフォーマンスや保守性の問題が発生する可能性があるため、ケースバイケースで処理する必要があります。

2
user140665