Puede agrupar la mayor parte del costo en una sola consulta principal en un CTE
y reutilice el resultado varias veces.
Esto devuelve una fila única con tres columnas nombrado después de cada type
(según lo solicitado en el comentario
):
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;
Debería funcionar para Postgres 9.3. En Postgres 9.4 puede usar el nuevo agregado FILTER
cláusula:
count(*) FILTER (WHERE key = 'disable_student_nav' AND value = 'False') AS spn
, count(*) FILTER (WHERE key = 'pacing' AND value = 'teacher') AS tp
Detalles para ambas variantes de sintaxis:
La condición marcada como problem?
puede ser un gran problema de rendimiento, según el tipo de datos de cai.end_time
. Por un lado, no es sargable
. Y si es un timestamptz
tipo, la expresión es difícil de indexar, porque el resultado depende de la configuración de la zona horaria actual de la sesión, lo que también puede generar resultados diferentes cuando se ejecuta en diferentes zonas horarias.
Comparar:
- Sustract dos consultas de la misma tabla
- Restar horas del ahora( ) función
- Ignorar las zonas horarias por completo en Rieles y PostgreSQL
Solo tiene que nombrar la zona horaria que se supone que define su fecha. Tomando mi zona horaria en Viena como ejemplo:
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'
Puede proporcionar timestamptz
simple valores también. Incluso podrías simplemente:
WHERE cai.end_time >= '2015-09-12'::date
AND cai.end_time < '2015-09-12'::date + 1
Pero la primera variante no depende de la configuración de la zona horaria actual.
Explicación detallada en los enlaces de arriba.
Ahora la consulta puede usar su índice y debería ser mucho más rápida si hay muchos días diferentes en su tabla.