PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Besser als mehrere SELECT-Anweisungen?

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:

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.