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

複数の結合の最適化

    クエリを最適化する際には、常に2つの考慮事項があります。

    • 使用できるインデックス(インデックスの作成が必要になる場合があります)
    • クエリの記述方法(クエリオプティマイザーが適切なインデックスを見つけられるようにし、データを重複して再読み込みしないようにするには、クエリを変更する必要がある場合があります)

    いくつかの所見:

    • 日付を結合する前に、日付操作を実行しています。原則として、これにより、クエリオプティマイザがインデックスが存在する場合でもインデックスを使用できなくなります。式の片側にインデックス付きの列が変更されずに存在するように、式を作成するようにしてください。

    • サブクエリは、generate_seriesと同じ日付範囲にフィルタリングされています 。これは重複であり、最も効率的な最適化を選択するオプティマーの能力を制限します。オプティマイザーが日付列(body_time)のインデックスを使用できなかったため、パフォーマンスを向上させるために書き込まれた可能性があります。 )?

    • :実際には、Body.body_timeのインデックスを使用したいと思います。

    • ORDER BY サブクエリ内はせいぜい冗長です。最悪の場合、クエリオプティマイザーが結合する前に結果セットをソートするように強制される可能性があります。これは、クエリプランにとって必ずしも良いとは限りません。むしろ、最終的な表示のために最後に注文を適用するだけです。

    • LEFT JOINの使用 あなたのサブクエリでは不適切です。 NULLにANSI規則を使用していると仮定します 振る舞い(そしてあなたはそうあるべきです)、どんな外側 envelopeに参加します envelope_command=NULLを返します 、したがって、これらは条件envelope_command=?によって除外されます。 。

    • サブクエリo およびi envelope_commandを除いてほぼ同じです 価値。これにより、オプティマイザーは同じ基になるテーブルを2回スキャンするように強制されます。 ピボットテーブルを使用できます データに1回結合し、値を2列に分割する手法。

    ピボット手法を使用する次の方法を試してください。

    SELECT  p.period,
            /*The pivot technique in action...*/
            SUM(
            CASE WHEN envelope_command = 1 THEN body_size
            ELSE 0
            END) AS Outbound,
            SUM(
            CASE WHEN envelope_command = 2 THEN body_size
            ELSE 0
            END) AS Inbound
    FROM    (
            SELECT  date '2009-10-01' + s.day AS period
            FROM    generate_series(0, date '2009-10-31' - date '2009-10-01') AS s(day)
            ) AS p 
            /*The left JOIN is justified to ensure ALL generated dates are returned
              Also: it joins to a subquery, else the JOIN to envelope _could_ exclude some generated dates*/
            LEFT OUTER JOIN (
            SELECT  b.body_size,
                    b.body_time,
                    e.envelope_command
            FROM    body AS b 
                    INNER JOIN envelope e 
                      ON e.message_id = b.message_id 
            WHERE   envelope_command IN (1, 2)
            ) d
              /*The expressions below allow the optimser to use an index on body_time if 
                the statistics indicate it would be beneficial*/
              ON d.body_time >= p.period
             AND d.body_time < p.period + INTERVAL '1 DAY'
    GROUP BY p.Period
    ORDER BY p.Period
    

    編集 :TomHによって提案されたフィルターを追加しました。



    1. MySQLのタイムゾーンを変更しますか?

    2. SQL-複数の列にカウント

    3. Oraclesqldeveloper-コマンドラインからDBに接続する方法

    4. MySqlでの動的な列名の選択