sql >> Database >  >> RDS >> PostgreSQL

Betere manier dan meerdere SELECT-instructies?

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:

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.



  1. SELECTEER een vast aantal rijen door rijen gelijkmatig over te slaan

  2. Standaard datum/tijd met Ecto &Elixir

  3. Voer productanalyses uit met behulp van SQL Server Full-Text Search. Deel 1

  4. Ruby:mysql2-Gem werkt niet (Mac OS X Snow Leopard, Ruby 1.9.2)