postgresqlとpsycopg2を使用して小さな在庫システムを構築しました。コンテンツの集計された要約/レポートを作成したい場合を除いて、すべてがうまく機能しますが、count()と並べ替えのためにパフォーマンスが非常に悪くなります。
DBスキーマは次のとおりです。
CREATETABLEホスト (( idシリアル主キー、 名前VARCHAR(255) ); CREATETABLEアイテム (( idシリアル主キー、 説明テキスト ); CREATE TABLE host_item (( idシリアル主キー、 host INTEGER REFERENCES hosts(id)ON DELETE CASCADE ON UPDATE CASCADE、 item INTEGER REFERENCES items(id)ON DELETE CASCADE ON UPDATECASCADE );
他にもいくつかのフィールドがありますが、それらは関係ありません。
2つの異なるレポートを抽出したい:-アイテム数が多いすべてのホストのリスト、カウントの高いものから低いものへ-ホストの数が多いすべてのアイテムのリスト、カウントの高いものから低いものへの順序
私は目的のために2つのクエリを使用しました:
ホスト数のあるアイテム:
SELECT i.id、i.description、COUNT(hi.id)AS count アイテムからi LEFT JOIN host_item AS hi オン(i.id = hi.item) GROUP BY i.id ORDER BY count DESC 制限10;
アイテム数のあるホスト:
SELECT h.id、h.name、COUNT(hi.id)AS count ホストからASh LEFT JOIN host_item AS hi オン(h.id = hi.host) GROUP BY h.id ORDER BY count DESC 制限10;
問題は、データを返す前にクエリが5〜6秒間実行されることです。これはWebベースのアプリケーションであるため、6秒は受け入れられません。データベースには、約5万のホスト、1000のアイテム、および400 000のホスト/アイテムの関係が大量に存在し、アプリケーションを使用する場合(または使用する場合)に大幅に増加する可能性があります。
遊んだ後、「ORDER BY count DESC」の部分を削除することで、両方のクエリが遅延なく即座に実行されることがわかりました(クエリを完了するのに20ミリ秒未満)。
これらのクエリを最適化して、遅延なく結果を並べ替えることができる方法はありますか?さまざまなインデックスを試していましたが、カウントが計算されるので、これにインデックスを利用することができます。postgresqlでのcount()の実行が遅いことを読みましたが、問題の原因となっている並べ替えです...
私の現在の回避策は、上記のクエリを1時間ごとのジョブとして実行し、結果を新しいテーブルに入れて、カウント列にインデックスを付けてすばやく検索することです。
私はPostgresql9.2を使用しています。
更新:注文どおりのクエリプラン:)
EXPLAIN ANALYZE
SELECT h.id, h.name, COUNT(hi.id) AS count
FROM hosts AS h
LEFT JOIN host_item AS hi
ON (h.id=hi.host)
GROUP BY h.id
ORDER BY count DESC
LIMIT 10;
Limit (cost=699028.97..699028.99 rows=10 width=21) (actual time=5427.422..5427.424 rows=10 loops=1)
-> Sort (cost=699028.97..699166.44 rows=54990 width=21) (actual time=5427.415..5427.416 rows=10 loops=1)
Sort Key: (count(hi.id))
Sort Method: top-N heapsort Memory: 25kB
-> GroupAggregate (cost=613177.95..697840.66 rows=54990 width=21) (actual time=3317.320..5416.440 rows=54990 loops=1)
-> Merge Left Join (cost=613177.95..679024.94 rows=3653163 width=21) (actual time=3317.267..5025.999 rows=3653163 loops=1)
Merge Cond: (h.id = hi.host)
-> Index Scan using hosts_pkey on hosts h (cost=0.00..1779.16 rows=54990 width=17) (actual time=0.012..15.693 rows=54990 loops=1)
-> Materialize (cost=613177.95..631443.77 rows=3653163 width=8) (actual time=3317.245..4370.865 rows=3653163 loops=1)
-> Sort (cost=613177.95..622310.86 rows=3653163 width=8) (actual time=3317.199..3975.417 rows=3653163 loops=1)
Sort Key: hi.host
Sort Method: external merge Disk: 64288kB
-> Seq Scan on host_item hi (cost=0.00..65124.63 rows=3653163 width=8) (actual time=0.006..643.257 rows=3653163 loops=1)
Total runtime: 5438.248 ms
EXPLAIN ANALYZE
SELECT h.id, h.name, COUNT(hi.id) AS count
FROM hosts AS h
LEFT JOIN host_item AS hi
ON (h.id=hi.host)
GROUP BY h.id
LIMIT 10;
Limit (cost=0.00..417.03 rows=10 width=21) (actual time=0.136..0.849 rows=10 loops=1)
-> GroupAggregate (cost=0.00..2293261.13 rows=54990 width=21) (actual time=0.134..0.845 rows=10 loops=1)
-> Merge Left Join (cost=0.00..2274445.41 rows=3653163 width=21) (actual time=0.040..0.704 rows=581 loops=1)
Merge Cond: (h.id = hi.host)
-> Index Scan using hosts_pkey on hosts h (cost=0.00..1779.16 rows=54990 width=17) (actual time=0.015..0.021 rows=11 loops=1)
-> Index Scan Backward using idx_host_item_host on host_item hi (cost=0.00..2226864.24 rows=3653163 width=8) (actual time=0.005..0.438 rows=581 loops=1)
Total runtime: 1.143 ms
更新:この質問に対するすべての回答は、Postgresがどのように機能するかを学び理解するのに非常に役立ちます。この問題に対する明確な解決策はないようですが、あなたが提供してくれたすべての優れた回答に本当に感謝しています。Postgresqlでの今後の作業でそれらを使用します。たくさんの人に感謝します!