Du kan samle det meste af omkostningerne i en enkelt hovedforespørgsel i en CTE
og genbrug resultatet flere gange.
Dette returnerer en enkelt række med tre kolonner opkaldt efter hver type
(som anmodet om i kommentaren
):
WITH cte AS (
SELECT cai.id, cai.activity_id, cas.key, cas.value
FROM common_activityinstance cai
JOIN common_activityinstance_settings s ON s.activityinstance_id = cai.id
JOIN common_activitysetting cas ON cas.id = s.id
WHERE cai.end_time::date = '2015-09-12' -- problem?
AND cai.activity_type = 'QZ'
AND (cas.key = 'disable_student_nav' AND cas.value IN ('True', 'False') OR
cas.key = 'pacing' AND cas.value IN ('student', 'teacher'))
)
SELECT *
FROM (
SELECT count(*) AS spf
FROM (
SELECT c.id
FROM cte c
JOIN quizzes_quiz q ON q.id = c.activity_id
WHERE q.name <> 'Exit Ticket Quiz'
AND (c.key, c.value) IN (('disable_student_nav', 'True')
, ('pacing', 'student'))
GROUP BY 1
HAVING count(*) = 2
) sub
) spf
, (
SELECT count(key = 'disable_student_nav' AND value = 'False' OR NULL) AS spn
, count(key = 'pacing' AND value = 'teacher' OR NULL) AS tp
FROM cte
) spn_tp;
Bør fungere for Postgres 9.3. I Postgres 9.4 kan du bruge det nye aggregat FILTER
klausul:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Detaljer for begge syntaksvarianter:
Tilstanden markeret med problem?
kan være et stort ydeevneproblem, afhængigt af datatypen cai.end_time
. For det første er det ikke sargerbart
. Og hvis det er en timestamptz
type, er udtrykket svært at indeksere, fordi resultatet afhænger af sessionens aktuelle tidszoneindstilling - hvilket også kan føre til forskellige resultater, når det udføres i forskellige tidszoner.
Sammenlign:
- Træk to forespørgsler fra samme tabel
- Træk timer fra nu( ) funktion
- Ignorerer tidszoner helt i Rails og PostgreSQL
Du skal bare navngive den tidszone, der skal definere din dato. Jeg tager min tidszone i Wien som eksempel:
WHERE cai.end_time >= '2015-09-12 0:0'::timestamp AT TIME ZONE 'Europe/Vienna'
AND cai.end_time < '2015-09-13 0:0'::timestamp AT TIME ZONE 'Europe/Vienna'
Du kan angive simpel timestamptz
værdier også. Du kan endda bare:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Men den første variant afhænger ikke af den aktuelle tidszoneindstilling.
Detaljeret forklaring i linkene ovenfor.
Nu kan forespørgslen bruge dit indeks og burde være meget hurtigere, hvis der er mange forskellige dage i din tabel.