他のクエリと同様に、最も効率的な方法は「依存する」です。テーブル内の行数、行の長さ、インデックスが存在するかどうか、サーバー上のRAMなど、さまざまな変数が関係しています。
この種の問題を処理するために私が考えることができる最善の方法(保守性と効率への勇敢なアプローチを考える)は、CTEを使用することです。これにより、一時的な結果を作成し、その結果をクエリ全体で再利用できます。 CTEはWITHキーワードを使用し、基本的に結果をテーブルとしてエイリアス化するため、複数回参加できます。
WITH user_memberships AS (
SELECT *
FROM memberships
WHERE user_id = ${id}
), user_apps AS (
SELECT *
FROM apps
INNER JOIN user_memberships
ON user_memberships.team_id = apps.team_id
), user_collections AS (
SELECT *
FROM collections
INNER JOIN user_memberships
ON user_memberships.team_id = collections.team_id
), user_webhooks AS (
SELECT *
FROM webhooks
LEFT OUTER JOIN user_collections ON user_collections.id = webhooks.collection_id
INNER JOIN user_memberships
ON user_memberships.team_id = webhooks.team_id
OR user_memberships.team_id = user_collections.team_id
)
SELECT events.*
FROM events
WHERE app_id IN (SELECT id FROM user_apps)
OR collection_id IN (SELECT id FROM user_collections)
OR membership_id IN (SELECT id FROM user_memberships)
OR team_id IN (SELECT team_id FROM user_memberships)
OR user_id = ${id}
OR webhook_id IN (SELECT id FROM user_webhooks)
;
この方法で行う利点は次のとおりです。
- 各CTEは、実行プランナーが一連の複雑な述語を解決しようとするのではなく、適切なJOIN述語のインデックスを利用して、そのサブセットのみの結果をより速く返すことができます。
- CTEは個別に保守できるため、サブセットに関する問題のトラブルシューティングが容易になります
- DRYの原則に違反していません
- CTEにクエリ以外の値がある場合は、それをストアドプロシージャに移動して、代わりにそれを参照できます