2017-09-20 4 views
1

次のクエリは、偶数の時間間隔で分布された履歴値の平均を計算するのに役立ちます。ここで左結合により、クエリ解決の時間が大幅に増加します

EXPLAIN ANALYZE SELECT start_date as date, AVG(hcv1.value::float) as value 
FROM generate_series(cast('2017-01-01' as abstime), cast('2017-12-01' as abstime), interval '86400 seconds') start_date 
LEFT JOIN history_values hv 
ON (
    hv.variable_id = 3 AND 
    hv.created_at BETWEEN start_date AND start_date + interval '86400 seconds' 
) 
GROUP BY start_date 
ORDER BY start_date 

クエリのレポート:

EXPLAIN ANALYZE SELECT start_date as date, 
AVG(hv1.value::float) as value1, 
AVG(hv2.value::float) as value2 
FROM generate_series(cast('2017-01-01' as abstime), cast('2017-12-01' as abstime), interval '86400 seconds') start_date 
LEFT JOIN history_values hv1 
ON (
    hv1.variable_id = 2 AND 
    hv.created_at BETWEEN start_date AND start_date + interval '86400 seconds' 
) 
LEFT JOIN history_values hv2 
ON (
    hv2.variable_id = 3 AND 
    hv.created_at BETWEEN start_date AND start_date + interval '86400 seconds' 
) 
GROUP BY start_date 
ORDER BY start_date 
:今、私は別のを指して余分な列の値2を追加しようとクエリ時間が150秒に2秒から行くvariable_id場合 https://explain.depesz.com/s/q29a

ここに報告書はあります:https://explain.depesz.com/s/V1sV

なぜ誰に教えてもらえますか?私は本当に時間が約4秒になることを期待していました。

はまた、次の点に注意してください

SELECT COUNT(*) FROM history_values WHERE variable_id = 2 -- ~25k records 
SELECT COUNT(*) FROM history_values WHERE variable_id = 3 -- ~25k records 
+0

PostgreSQLのどのバージョンですか? –

+1

Apple LLVMバージョン7.0.2(clang-700.1.81)、64ビットでコンパイルされたx86_64-apple-darwin14.5.0上のPostgreSQL 9.6.1 – pnknrg

+0

最初にカレンダーテーブルを具体化し、分析する)。 2番目:タイムスタンプに適切なデータ型+関数を使用する。 – wildplasser

答えて

2

あなたが別の結合条件を追加している、余分な列を追加していません。そして、あなたはちょうどサイドノートとしてavg()

EXPLAIN ANALYZE 
SELECT start_date as date, 
    AVG(hv1.value::float) FILTER (WHERE hv1.variable_id = 1) as value1, 
    AVG(hv2.value::float) FILTER (WHERE hv1.variable_id = 2) as value2 
FROM generate_series(
    cast('2017-01-01' as abstime) 
    , cast('2017-12-01' as abstime), 
    , interval '86400 seconds' 
) AS start_date 
LEFT JOIN history_values hv1 
ON (
    hv1.created_at >= cast('2017-01-01' as abstime) AND 
    hv1.created_at <= cast('2017-12-01' as abstime) AND 
    hv1.created_at >= start_date AND 
    hv1.created_at < start_date + interval '86400 seconds' 
) 
GROUP BY start_date 
ORDER BY start_date 

をフィルタリング、あなたがこれまでabstimeを使用すべきではない、代わりに試してみてください。..余分とにかく参加すること

を必要としません。それは社内でのみ使用する必要があります。代わりに、私は将来的に..私はまた、あなたがダウンしてそれらの範囲を折りたたむことができると思うだろう

EXPLAIN ANALYZE 
SELECT start_date::date AS date, 
    AVG(hv1.value::float) FILTER (WHERE hv1.variable_id = 1) as value1, 
    AVG(hv2.value::float) FILTER (WHERE hv1.variable_id = 2) as value2 
FROM generate_series(
    timestamp with time zone '2017-01-01', 
    timestamp with time zone '2017-12-01' - interval '1 day' 
    interval '1 day' 
) AS start_date 
LEFT JOIN history_values hv1 
    ON hv1.created_at BETWEEN start_date AND (start_date + interval '1 day') 
    AND hv1.variable_id IN (1,2) 
GROUP BY start_date 
ORDER BY start_date 

EXPLAIN ANALYZE 
SELECT start_date::date AS date, 
    AVG(hv1.value::float) FILTER (WHERE hv1.variable_id = 1) as value1, 
    AVG(hv2.value::float) FILTER (WHERE hv1.variable_id = 2) as value2 
FROM generate_series(
    timestamp with time zone '2017-01-01', 
    timestamp with time zone '2017-12-01', 
    interval '1 day' 
) AS start_date 
LEFT JOIN history_values hv1 
ON (
    hv1.created_at BETWEEN (
    timestamp with time zone '2017-01-01' 
    AND timestamp with time zone '2017-12-01' 
) AND 
    hv1.created_at >= start_date AND 
    hv1.created_at < start_date + interval '1 day' AND 
    hv1.variable_id IN (1,2) 

) 
GROUP BY start_date 
ORDER BY start_date 

を使用することになり、http://dba.stackexchange.comでPostgreSQLに固有の質問をしてください。私はそこに移動するためにこれをフラグするでしょう。管理者は喜んでそれを移動します。

+0

提案されたクエリは、1と2の両方の値に対して、元のクエリよりも時間がかかります。 – pnknrg

+0

@pnknrgは、そのクエリの計画を表示します –

+0

"どうしたらうまくいくのかわかりません。どういう意味ですか?レコードの作成日がgenerate_seriesから取得できないstart_dateとnext_dateの間にある場合にのみLEFT JOINを実行するので、開始日に間隔を追加して再計算します。 – pnknrg

関連する問題