sql >> データベース >  >> RDS >> PostgreSQL

複数のSELECTステートメントよりも良い方法はありますか?

    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
    

    ただし、最初のバリアントは現在のタイムゾーン設定に依存しません。
    上記のリンクの詳細な説明。

    これで、クエリでインデックスを使用できるようになり、テーブルにさまざまな日がある場合ははるかに高速になります。



    1. Django、アップグレード後:MySQLサーバーがなくなりました

    2. MySQL:SELECTはMAX_JOIN_SIZEを超える行を調べます

    3. ORA-01401:挿入された値がCHAR列に対して大きすぎます

    4. Mysqlストアドプロシージャはパラメータとしてテーブル名を取りません