U kunt de meeste kosten bundelen in een enkele hoofdquery in een CTE
en hergebruik het resultaat meerdere keren.
Dit retourneert een enkele rij met drie kolommen genoemd naar elk type
(zoals gevraagd in de reactie
):
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;
Zou moeten werken voor Postgres 9.3. In Postgres 9.4 kunt u het nieuwe aggregaat FILTER
. gebruiken clausule:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Details voor beide syntaxisvarianten:
De voorwaarde gemarkeerd problem?
kan een groot prestatieprobleem zijn, afhankelijk van het gegevenstype van cai.end_time
. Ten eerste is het niet sargable
. En als het een timestamptz
. is type, is de uitdrukking moeilijk te indexeren, omdat het resultaat afhangt van de huidige tijdzone-instelling van de sessie - wat ook kan leiden tot verschillende resultaten wanneer uitgevoerd in verschillende tijdzones.
Vergelijk:
- Trek twee query's uit dezelfde tabel
- Huren af van het nu( ) functie
- Tijdzones volledig negeren in Rails en PostgreSQL
U hoeft alleen maar de tijdzone te noemen die uw datum moet definiëren. Als ik mijn tijdzone in Wenen als voorbeeld neem:
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'
U kunt eenvoudige timestamptz
waarden ook. Je zou zelfs gewoon:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Maar de eerste variant is niet afhankelijk van de huidige tijdzone-instelling.
Gedetailleerde uitleg in de links hierboven.
De zoekopdracht kan nu uw index gebruiken en zou veel sneller moeten zijn als er veel verschillende dagen in uw tabel zijn.