私はpostgres 9.4を使用しています。
のmessages
スキーマは次のとおりです。メッセージはfeed_idに属し、posted_atを持っています。また、メッセージには親メッセージを含めることができます(返信の場合)。
Table "public.messages"
Column | Type | Modifiers
------------------------------+-----------------------------+-----------
message_id | character varying(255) | not null
feed_id | integer |
parent_id | character varying(255) |
posted_at | timestamp without time zone |
share_count | integer |
Indexes:
"messages_pkey" PRIMARY KEY, btree (message_id)
"index_messages_on_feed_id_posted_at" btree (feed_id, posted_at DESC NULLS LAST)
で注文したすべてのメッセージを返したいのですshare_count
が、ごとparent_id
に1つのメッセージだけを返したいのです。つまり、複数のメッセージに同じがある場合parent_id
、最新のメッセージ(posted_at
)のみが返されます。parent_id
nullにすることができ、ヌルを持つメッセージはparent_id
すべて返す必要があります。
私が使用したクエリは次のとおりです。
WITH filtered_messages AS (SELECT *
FROM messages
WHERE feed_id IN (7)
AND (posted_at >= '2015-01-01 04:00:00.000000')
AND (posted_at < '2015-04-28 04:00:00.000000'))
SELECT *
FROM (SELECT DISTINCT ON(COALESCE(parent_id, message_id)) parent_id,
message_id,
posted_at,
share_count
FROM filtered_messages
ORDER BY COALESCE(parent_id, message_id), posted_at DESC NULLS LAST
) messages
ORDER BY share_count DESC NULLS LAST, posted_at DESC NULLS LAST;
これがhttp://sqlfiddle.com/#!15/588e5/1/0です。SQLFiddleで、スキーマ、正確なクエリ、および期待される結果を定義しました。
ただし、メッセージテーブルが大きくなると、クエリのパフォーマンスが低下します。複数のソートインデックスを追加しようとしましたが、インデックスを使用していないようです。これが説明です:http : //explain.depesz.com/s/Sv2
正しいインデックスを作成するにはどうすればよいですか?
feed_id
とposted_at
、あなたは言及しなかったmetadata
JSONタイプであるように思われ、すべての?一貫性を保つために質問を修正してください。CTEで500,000を超える行を選択します...テーブルには何行ありますか?CTEでは通常、何パーセントの行を選択しますか?行の何パーセントparent_id IS NULL
ですか?パフォーマンスの質問については、[postgresql-performance]タグの情報を考慮してください。
parent_id
?(最小/平均/最大)
metadata
。現在、メッセージテーブルには10 milのデータがありますが、急速に増加しています。各feed_idごとにパーティションテーブルに分けて考えています。フィードIDごとにフェッチしているだけなので。null以外のparent_id nullの割合は、約60%/ 40%です。一般的なフェッチは、テーブルの約1〜2%です。(約100Kメッセージ)100Kのパフォーマンスは約1秒ですが、500K +に達すると、ビットマップインデックスを使用し、通常は10秒かかります。
ORDER BY
と、サブクエリ内のはまったく役に立ちません。さらに、リンクされたプランを投稿されたクエリの結果にすることはできませんmetadata
。たとえば、についての言及はありません。