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


13

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

私の質問は、複数の小さなクエリを使用することを検討し、複数の呼び出しで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

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

回答:


14

ここでは、datagodを使用した大規模で複雑なクエリに反対します。私はこれらが混乱している場合にのみ問題と見なします。パフォーマンスの面では、プランナーが情報を取得する方法にはるかに自由があるため、これらはほとんど常に優れています。ただし、保守性を考慮して大規模なクエリを作成する必要があります。一般に、単一のクエリが200行以上続く場合でも、シンプルで適切に構造化されたSQLをデバッグしやすいことがわかりました。これは、通常、どのような種類の問題を扱っているかについてかなり良い考えを持っているため、チェックする必要があるクエリの領域がわずかしかないためです。

メンテナンスの問題であるIMEは、SQLの構造が壊れたときに発生します。副照会内の長く複雑な照会は、インラインビューと同様に、読みやすさとトラブルシューティングを損ないます。これらの両方は、長い照会では避けてください。代わりに、可能であればVIEWを使用します(MySQLを使用している場合、ビューはそれほどうまく機能しませんが、他のほとんどのデータベースでは機能します)。ところで)。

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

スケーラビリティについては、プランナーの柔軟性が高いほど良いことにも留意してください。...

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


注:生成されたクエリプランが最適ではないほど長く、複雑なクエリ(MySQLではなく、まだ...)がありました。これらの場合、実際には、1つの非常に複雑なクエリを2つのそれほど複雑でないクエリに分割することで、より速い結果を得ることができます。そうは言っても、それはまれであり、一般的に複雑なクエリを記述し、クエリを先制的に小さなチャンクに分割するのではなく、問題があるかどうかを調べます。
RDFozz

8

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

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


2
ただし、一連の単純なクエリの欠点は、クエリ全体で状態が大幅に変化し、アプリケーションの全体的なデバッグがより複雑になることです。つまり、大きなSQLクエリをツリーとして頻繁にデバッグできますが、アプリケーションコードは、ステートメントの状態がどのように変化するかをチェックするステートメントによってデバッグされます。本当の問題は、副問い合わせやインライン・ビューは、独自の木.....であるという事実としなければならない
クリス・トラヴァース

私の場合、DBとコードを管理する必要があるのは自分だけです。そして、ほとんどの私の質問は、クエリのパフォーマンスポイントに関するものでした。
ハメドモメニ

皆さんは、大規模なバッチプロセスの記述方法を確認する必要があります。非常に読みやすいシンプルなクエリに分けてください。最終的に整理しようとするクエリは、通常1000行を超えるため、偏見があります。
datagod

5

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

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

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


2
RE:「SQL Serverの」リファレンスOPが特定のRDBMSを指定していないが、私は彼らが戻ってからMySQLの上にある容疑者はダニとLIMIT
マーティン・スミス

@MartinSmithあなたは正しく疑っています。MySQLです。
ハメドモメニ

2

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.