2016-04-27 14 views
1

私はテーブルcallscalls_statisticsを持っています。 callsには、外部キーであるcalls_idのプライマリキーがcalls_statisticsにあります。PostgreSQL array_agg panously slow

コールには現在16k個のエントリが含まれています。

私は

SELECT c.*, 
array_agg(cs.mean) AS statistics_means 
FROM calls AS c 
LEFT JOIN calls_statistics AS cs ON c.calls_id = cs.calls_id 
GROUP BY c.calls_id 
order by caller_id ASC, call_time ASC LIMIT 100; 

を実行すると、私はarray_aggを無効にし、それが私のインデックスを使用するクエリを実行すると、クエリが、しかし、およそ622ミリ

Limit (cost=11947.99..11948.24 rows=100 width=551) (actual time=518.921..518.941 rows=100 loops=1) 
    -> Sort (cost=11947.99..11989.07 rows=16429 width=551) (actual time=518.918..518.928 rows=100 loops=1) 
     Sort Key: c.caller_id, c.call_time 
     Sort Method: top-N heapsort Memory: 126kB 
     -> HashAggregate (cost=11114.73..11320.09 rows=16429 width=551) (actual time=461.869..494.761 rows=16429 loops=1) 
       -> Hash Right Join (cost=6234.65..10705.12 rows=81922 width=551) (actual time=79.171..257.498 rows=81922 loops=1) 
        Hash Cond: (cs.calls_id = c.calls_id) 
        -> Seq Scan on calls_statistics cs (cost=0.00..2627.22 rows=81922 width=12) (actual time=3.534..26.778 rows=81922 loops=1) 
        -> Hash (cost=6029.29..6029.29 rows=16429 width=547) (actual time=75.578..75.578 rows=16429 loops=1) 
          Buckets: 2048 Batches: 1 Memory Usage: 9370kB 
          -> Seq Scan on calls c (cost=0.00..6029.29 rows=16429 width=547) (actual time=13.806..42.446 rows=16429 loops=1) 
Total runtime: 622.537 ms 

を取ります

SELECT c.*, 
cs.mean 
FROM calls AS c 
LEFT JOIN calls_statistics AS cs ON c.calls_id = cs.calls_id 
order by caller_id ASC, call_time ASC LIMIT 100; 

クエリは0.565msかかります!

Limit (cost=0.70..52.93 rows=100 width=551) (actual time=0.077..0.320 rows=100 loops=1) 
    -> Nested Loop Left Join (cost=0.70..42784.95 rows=81922 width=551) (actual time=0.075..0.304 rows=100 loops=1) 
     -> Index Scan using calls_caller_id_call_time_calls_id_idx on calls c (cost=0.29..22395.06 rows=16429 width=547) (actual time=0.042..0.091 rows=25 loops=1) 
     -> Index Scan using calls_stats_calls_idx on calls_statistics cs (cost=0.42..1.18 rows=6 width=12) (actual time=0.003..0.005 rows=4 loops=25) 
       Index Cond: (c.calls_id = calls_id) 
Total runtime: 0.565 ms 

配列に集約するのは時間がかかりすぎることはありませんか?私は間違って何をしていますか?

私はPostgres 9.3を使用しています。

+0

私はまた 'sort'が16429行を期待だけで100どういうわけか、クエリプランナは、あなたが2番目のクエリでby''グループを削除 – user3207838

+4

...自分自身をだまされます。と指摘それはおそらく時間を支配しているでしょう。 –

+0

@ GordonLinoffええ、私は知っているが、それは私の質問の全体のポイントです。 – user3207838

答えて

1

テーブルcallsから100行を選択してから、calls_statisticsを結合して集計する方法もあります。

ような何か:

WITH top_calls as (SELECT c.* 
FROM calls AS c 
ORDER BY caller_id ASC, call_time ASC 
LIMIT 100) 
SELECT c.*, 
array_agg(cs.mean) AS statistics_means 
FROM top_calls AS c 
LEFT JOIN calls_statistics AS cs ON c.calls_id = cs.calls_id 
GROUP BY c.calls_id 
order by caller_id ASC, call_time ASC; 

それはあなたの最初のクエリとまったく同じ出力をお渡しします。

0

すべての情報とライブシステムがなくてもクエリを最適化するのはちょっと難しいかもしれませんが、私はこれを撮影します。制限をサブクエリに移動することができますし、はるかに高速に動作するはずです。

SELECT c.*, 
array_agg(cs.mean) AS statistics_means 
FROM 
    (SELECT * 
    FROM calls AS c 
    ORDER BY caller_id ASC, call_time ASC 
    LIMIT 100) AS c 
LEFT JOIN calls_statistics AS cs ON c.calls_id = cs.calls_id 
GROUP BY c.calls_id;