PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Mieux que plusieurs instructions SELECT ?

Vous pouvez regrouper la plupart des coûts dans une seule requête principale dans un CTE et réutiliser le résultat plusieurs fois.
Cela renvoie une ligne unique avec trois colonnes nommé d'après chaque type (comme demandé dans le commentaire ):

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;

Devrait fonctionner pour Postgres 9.3. Dans Postgres 9.4, vous pouvez utiliser le nouvel agrégat FILTER clause :

  count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp

Détails pour les deux variantes de syntaxe :

La condition marquée problem? peut être un gros problème de performances, selon le type de données de cai.end_time . D'une part, ce n'est pas sargable . Et si c'est un timestamptz type, l'expression est difficile à indexer, car le résultat dépend du paramètre de fuseau horaire actuel de la session - ce qui peut également conduire à des résultats différents lorsqu'il est exécuté dans différents fuseaux horaires.

Comparez :

Il vous suffit de nommer le fuseau horaire censé définir votre date. En prenant mon fuseau horaire à Vienne comme exemple :

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'

Vous pouvez fournir un simple timestamptz valeurs aussi. Vous pouvez même :

WHERE  cai.end_time >= '2015-09-12'::date
AND    cai.end_time <  '2015-09-12'::date + 1

Mais la première variante ne dépend pas du paramètre de fuseau horaire actuel.
Explication détaillée dans les liens ci-dessus.

Désormais, la requête peut utiliser votre index et devrait être beaucoup plus rapide s'il y a plusieurs jours différents dans votre table.