This is a follow-up optimization on Adding a SUM group by into a COUNT DISTINCT query (albeit with some optimizations and joins simplifications).
I wonder if it's possible to optimize the following PostgreSQL 13.1 query which took 130322.2ms
to complete. Normally if only one JOIN LATERAL
is present it does it in a few ms.
What I'm most lost is given that each JOIN LATERAL
has an ON
with a condition based on the score of its own subquery, how could I optimize the query potentially reducing the number of JOIN LATERAL
and still get the same results.
From what I see, it seems it gets slow when conditional OR
are added to some of the WHERE inside the JOIN LATERAL
instead of AND
. See:
SELECT count(*)
FROM subscriptions q
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
AND ts.tag_id = 21
) AS q62958 ON q62958.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
OR ts.tag_id = 32
) AS q120342 ON q120342.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
OR ts.tag_id = 35
) AS q992506 ON q992506.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
OR ts.tag_id = 33
) AS q343255 ON q343255.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
OR ts.tag_id = 29
) AS q532052 ON q532052.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
OR ts.tag_id = 30
) AS q268437 ON q268437.sum_score <= 1
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
AND ts.tag_id = 46
) AS q553964 ON q553964.sum_score >= 3
JOIN LATERAL (
SELECT
SUM(ts.score) AS sum_score
FROM
quiz_answers qa
JOIN answers a ON a.id = qa.answer_id
JOIN tag_scores ts ON ts.answer_id = a.id
WHERE
qa.quiz_id = q.quiz_id
AND ts.tag_id = 24
) AS q928243 ON q928243.sum_score >= 2
WHERE
q.state = 'subscribed' AND q.app_id = 4
;
The subscriptions
table has less than 15000 rows and less than 2000 matching the WHERE
clause. Both q.state
and q.app_id
have indexes.
The complete EXPLAIN ANALYZE
: https://explain.depesz.com/s/Ok0h