PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Lepszy sposób niż wiele instrukcji SELECT?

Większość kosztów można umieścić w jednym głównym zapytaniu w CTE i użyj wyniku kilka razy.
Zwraca pojedynczy wiersz z trzema kolumnami nazwane po każdym type (zgodnie z żądaniem w komentarzu ):

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;

Powinien działać w Postgresie 9.3. W Postgresie 9.4 możesz użyć nowego agregatu FILTER klauzula:

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

Szczegóły obu wariantów składni:

Warunek oznaczony jako problem? może być dużym problemem z wydajnością, w zależności od typu danych cai.end_time . Po pierwsze, nie jest sargable . A jeśli jest to timestamptz typ, wyrażenie jest trudne do zindeksowania, ponieważ wynik zależy od aktualnego ustawienia strefy czasowej sesji - co może również prowadzić do różnych wyników w przypadku wykonania w różnych strefach czasowych.

Porównaj:

Musisz tylko nazwać strefę czasową, która ma określać twoją datę. Na przykładzie mojej strefy czasowej w Wiedniu:

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'

Możesz podać prosty timestamptz wartości. Możesz nawet po prostu:

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

Ale pierwszy wariant nie zależy od aktualnego ustawienia strefy czasowej.
Szczegółowe wyjaśnienie w powyższych linkach.

Teraz zapytanie może korzystać z Twojego indeksu i powinno być znacznie szybsze, jeśli w Twojej tabeli jest wiele różnych dni.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Rails Activerecord Relacja:użycie podzapytania jako tabeli dla instrukcji SQL select

  2. Ustaw Kolejność według, aby ignorować interpunkcję na podstawie kolumn

  3. Co nowego w PostgreSQL 12

  4. Błąd składni przy lub w pobliżu END z nazwą kolumny END

  5. Ustawienia Django konfigurują bazy danych z dwoma silnikami