0

私は、MPP に適合した PostgreSQL 8.2 の分岐バージョンを使用しています。私は基本的に、2 つの大きなテーブルからタイスタンプの範囲の最大下限を計算しようとしています。前述のテーブルの例を次に示します。

Table A
|source_ip (inet type)  |s_time (date type)    |
------------------------------------------------
|10.50.43.200           | 2013-02-21 01:47:08  |
|10.50.43.200           | 2013-02-21 01:47:38  |
|10.50.43.200           | 2013-02-21 01:47:41  |
|10.50.43.200           | 2013-02-25 17:05:00  |
|10.50.43.200           | 2013-02-25 17:05:03  |
|10.50.43.200           | 2013-02-25 17:05:04  |
|10.50.43.200           | 2013-02-25 17:05:34  |
|10.50.43.200           | 2013-02-25 17:10:01  |
|10.50.43.200           | 2013-02-25 17:12:52  |

Table B
|source_ip (inet type)  |mac (macaddr type)   |l_time (date type)    |
----------------------------------------------------------------------
|10.50.43.200           | 00:24:d7:99:e9:0c   | 2013-02-20 22:33:47  |
|10.50.43.200           | 00:24:d7:99:e9:0c   | 2013-02-20 23:07:32  |
|10.50.43.200           | 00:24:d7:99:e9:0c   | 2013-02-20 23:13:04  |
|10.50.43.200           | 00:24:d7:99:e9:0c   | 2013-02-21 00:02:56  |
|10.50.43.200           | 00:24:d7:99:68:14   | 2013-02-25 17:04:56  |
|10.50.43.200           | 00:24:d7:99:68:14   | 2013-02-25 17:04:59  |
|10.50.43.200           | 00:24:d7:99:68:14   | 2013-02-25 17:26:15  |

table の各行についてA、 Table の各タイムスタンプの「最大下限」である追加の列を結合したいと考えていますB。つまり、テーブル B のすべての値の中で最大の時間を含み、テーブル の対応する時間以下の列が必要ですA。私が期待している出力は、次のようになります。

 OUTPUT
 ------------------------------------------------------------
 |10.50.43.200  |2013-02-21 01:47:38  |2013-02-21 00:02:56  |
 |10.50.43.200  |2013-02-21 01:47:41  |2013-02-21 00:02:56  |
 |10.50.43.200  |2013-02-25 17:05:00  |2013-02-25 17:04:59  |
 |10.50.43.200  |2013-02-25 17:05:03  |2013-02-25 17:04:59  |
 |10.50.43.200  |2013-02-25 17:05:04  |2013-02-25 17:04:59  |
 |10.50.43.200  |2013-02-25 17:05:34  |2013-02-25 17:04:59  |

次のクエリは私が思いついたものですが、max()集計関数を使用することがこれを実現する最適な方法であるかどうかはわかりません。

それで、私の質問は -max()大規模なデータ セット (1 億以上の範囲) で高速化するために使用せずに、以下のクエリを書き直すことはできますか?

SELECT a.source_ip,
a.s_Time, max(b.l_Time) AS max_time
    FROM table_a AS a
    INNER JOIN
    table_b AS b
    ON (a.source_ip = b.source_ip AND a.s_time > b.l_time)
    GROUP BY a.source_ip, b.sourcemac, a.s_time
    ORDER BY a.s_time asc;

説明計画は次のとおりです。

                                                    QUERY PLAN
-------------------------------------------------------------------------------------------------------------------
 Gather Motion 72:1  (slice1; segments: 72)  (cost=1519175930.51..1519305453.91 rows=143915 width=48)
   ->  HashAggregate  (cost=1519175930.51..1519305453.91 rows=143915 width=48)
         Group By: a.source_ip, a.s_time
         ->  Hash Join  (cost=991681.79..1169135585.55 rows=648222862 width=23)
               Hash Cond: a.source_ip = b.source_ip
               Join Filter: a.s_time > b.l_time
               ->  Append-only Columnar Scan on  a  (cost=0.00..1083707.12 rows=1439149 width=15)
               ->  Hash  (cost=487360.24..487360.24 rows=560358 width=15)
                     ->  Seq Scan on  b  (cost=0.00..487360.24 rows=560358 width=15)
(9 rows)

source_ip結合を高速化するために、-s を bigints にハッシュできることを認識しています。また、結合で使用される列のインデックス作成を試す価値があるかもしれないと考えていましたが、最善の最適化戦略が何であるかはわかりません。StackOverflow コミュニティの優れた専門家グループからの情報をお待ちしています. ウィンドウ関数も試しましたrank()が、使用している実装に問題があり、テストしたこのタイプのクエリではパフォーマンスが最も悪い関数であるため、理想的な戦略ではウィンドウ関数を回避することをお勧めします。

編集:テーブルの にインデックスを追加しsource_ip、投稿の推奨事項を使用してクエリを書き直しました:start_yimeALIMIT 1

                                                           QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------
 Gather Motion 72:1  (slice2; segments: 72)  (cost=1624120.24..7442384075819.75 rows=145921 width=48)
   ->  HashAggregate  (cost=1624120.24..7442384075819.75 rows=145921 width=48)
         Group By: a.src, a.start_time
         ->  Append-only Columnar Scan on a  (cost=0.00..1098806.16 rows=1459206 width=15)
         SubPlan 1
           ->  Limit  (cost=708374.49..708374.51 rows=1 width=15)
                 ->  Limit  (cost=708374.49..708374.49 rows=1 width=15)
                       ->  Sort  (cost=708374.49..708376.35 rows=11 width=15)
                             Sort Key (Limit): b.source_ip, b.start_time
                             ->  Result  (cost=708339.65..708347.10 rows=11 width=15)
                                   Filter: $0 = b.source_ip AND $1 > b.start_time
                                   ->  Materialize for deadlock safety  (cost=708339.65..708347.10 rows=11 width=15)
                                         ->  Broadcast Motion 72:72  (slice1; segments: 72)  (cost=0.00..708338.90 rows=11 width=15)
                                               ->  Seq Scan on b  (cost=0.00..708338.90 rows=11 width=15)
4

2 に答える 2

1
SELECT a.src,
    a.s_Time,
    (SELECT b.l_time AS max_time 
       FROM table_b AS b WHERE a.source_ip = b.source_ip
         AND a.s_time > b.l_time 
         ORDER BY b.source_ip DESC, b.l_time DESC /* index on (source_ip, l_time) */
         LIMIT 1)
FROM table_a AS a
ORDER BY a.start_time;

a.s_timea.src が表示されず、とa.start_timeが異なる列であるかどうかわからないため、GROUP BY を省略しました。

とにかく、PG はインデックス付きクエリについて非常に賢いという考えLIMIT 1です (少なくとも、最近のバージョンはそうです; 8.2 を保証するものではありません)。ごく最近のバージョンは、必要に応じて同等のクエリに変換するのに十分スマートかもしれませんが、8.2 以降であることはほぼ確実です。MAXLIMIT 1

于 2013-05-29T07:21:40.617 に答える