PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

По-добър начин от множество изрази SELECT?

Можете да групирате по-голямата част от разходите в една основна заявка в CTE и използвайте повторно резултата няколко пъти.
Това връща един ред с три колони именуван след всеки type (както е поискано в коментар ):

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;

Трябва да работи за Postgres 9.3. В Postgres 9.4 можете да използвате новия агрегат FILTER клауза:

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

Подробности за двата варианта на синтаксис:

Условието, отбелязано с problem? може да е голям проблем с производителността, в зависимост от типа данни на cai.end_time . От една страна, не е sargable . И ако това е timestamptz тип, изразът е труден за индексиране, тъй като резултатът зависи от текущата настройка на часовата зона на сесията - което също може да доведе до различни резултати, когато се изпълнява в различни часови зони.

Сравнете:

Просто трябва да посочите часовата зона, която трябва да определя вашата дата. Вземам моята часова зона във Виена като пример:

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'

Можете да предоставите прост timestamptz ценности също. Можете дори просто:

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

Но първият вариант не зависи от текущата настройка на часовата зона.
Подробно обяснение във връзките по-горе.

Сега заявката може да използва вашия индекс и трябва да бъде много по-бърза, ако има много различни дни в таблицата ви.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Concat редове в Postgres

  2. Как да актуализирам всички колони с INSERT ... ON CONFLICT ...?

  3. Създайте голямо цяло число от големия край на uuid в PostgreSQL

  4. Как да използвате функцията под низ в PostgreSQL и Redshift

  5. Какво означава autocommit в postgresql и psycopg2?