Sie können die meisten Kosten in einer einzigen Hauptabfrage in einem CTE bündeln
und das Ergebnis mehrmals wiederverwenden.
Dies gibt eine einzelne Zeile mit drei Spalten zurück benannt nach jedem type
(wie gewünscht im Kommentar
):
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;
Sollte für Postgres 9.3 funktionieren. In Postgres 9.4 können Sie das neue Aggregat FILTER
verwenden Klausel:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Details für beide Syntaxvarianten:
Die Bedingung ist mit problem?
gekennzeichnet kann ein großes Leistungsproblem sein, abhängig vom Datentyp von cai.end_time
. Zum einen ist es nicht sargable
. Und wenn es ein timestamptz
ist -Typ ist der Ausdruck schwer zu indizieren, da das Ergebnis von der aktuellen Zeitzoneneinstellung der Sitzung abhängt - was auch zu unterschiedlichen Ergebnissen führen kann, wenn es in verschiedenen Zeitzonen ausgeführt wird.
Vergleichen Sie:
- Zwei Abfragen aus derselben Tabelle ziehen
- Stunden vom Jetzt subtrahieren( ) Funktion
- Ignorieren von Zeitzonen insgesamt in Rails und PostgreSQL
Sie müssen nur die Zeitzone nennen, die Ihr Datum definieren soll. Am Beispiel meiner Zeitzone in Wien:
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'
Sie können einfach timestamptz
bereitstellen auch Werte. Sie könnten sogar einfach:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Die erste Variante ist aber unabhängig von der aktuellen Zeitzoneneinstellung.
Detaillierte Erklärung in den Links oben.
Jetzt kann die Abfrage Ihren Index verwenden und sollte viel schneller sein, wenn Ihre Tabelle viele verschiedene Tage enthält.