Seperti halnya kueri apa pun, metode yang paling efisien adalah "itu tergantung". Ada banyak variabel yang dimainkan - jumlah baris dalam tabel, panjang baris, apakah ada indeks, RAM di server, dll.
Cara terbaik yang dapat saya pikirkan untuk menangani masalah semacam ini (berpikir tentang pemeliharaan dan pendekatan efisiensi yang baik) adalah dengan menggunakan CTE, yang memungkinkan Anda membuat hasil sementara dan menggunakan kembali hasil itu di seluruh kueri Anda. CTE menggunakan kata kunci WITH, dan pada dasarnya alias hasil sebagai tabel, sehingga Anda dapat BERGABUNG melawannya beberapa kali:
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)
;
Manfaat melakukannya dengan cara ini adalah:
- Setiap CTE dapat memanfaatkan indeks pada predikat GABUNG yang sesuai dan mengembalikan hasil hanya untuk subset itu lebih cepat, daripada meminta perencana eksekusi untuk menyelesaikan serangkaian predikat kompleks
- CTE dapat dipertahankan satu per satu, membuat pemecahan masalah dengan subset menjadi lebih mudah
- Anda tidak melanggar prinsip KERING
- Jika CTE memiliki nilai di luar kueri, Anda dapat memindahkannya ke prosedur tersimpan dan merujuknya sebagai gantinya