CTEの単一のメインクエリに、コストの大部分をまとめることができます。
結果を数回再利用します。
これにより、3列の単一行が返されます。 各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;
Postgres9.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
のデータ型によっては、パフォーマンスの大きな問題になる可能性があります 。 1つは、 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
ただし、最初のバリアントは現在のタイムゾーン設定に依存しません。
上記のリンクの詳細な説明。
これで、クエリでインデックスを使用できるようになり、テーブルにさまざまな日がある場合ははるかに高速になります。