Ich benutze Postgres 9.4.
Das messages
hat das folgende Schema: messages gehört zu feed_id und hat posted_at, auch Nachrichten können eine übergeordnete Nachricht haben (bei Antworten).
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)
Ich möchte alle von bestellten Nachrichten zurückgeben share_count
, aber für jede parent_id
möchte ich nur eine Nachricht zurückgeben. Wenn also mehrere Nachrichten dieselbe haben parent_id
, wird nur die letzte ( posted_at
) zurückgegeben. Das parent_id
kann null sein, Nachrichten mit null parent_id
sollten alle zurückkehren.
Die Abfrage, die ich verwendet habe, ist:
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;
Hier ist die http://sqlfiddle.com/#!15/588e5/1/0 , in der SQL Fiddle habe ich das Schema, die genaue Abfrage und das erwartete Ergebnis definiert.
Die Leistung der Abfrage ist jedoch langsam, sobald die Nachrichtentabelle groß wird. Ich habe versucht, mehrere Sortierindizes hinzuzufügen, aber der Index scheint nicht verwendet zu werden. Hier ist die Erklärung: http://explain.depesz.com/s/Sv2
Wie kann ich einen korrekten Index erstellen?
feed_id
und ab posted_at
und Sie haben überhaupt nicht erwähnt metadata
, was ein JSON-Typ zu sein scheint? Bitte reparieren Sie Ihre Frage, um sie konsistent zu machen. Sie wählen im CTE> 500k Zeilen aus ... Wie viele Zeilen enthält die Tabelle? Wie viel Prozent der Zeilen wählen Sie normalerweise im CTE aus? Wie viel Prozent der Zeilen hat parent_id IS NULL
? Beachten Sie die Informationen im Tag [postgresql-performance] für Leistungsfragen.
parent_id
? (min / avg / max)
metadata
. share_count war tatsächlich im Laden . Derzeit enthält die Nachrichtentabelle 10 Mil-Daten, steigt jedoch schnell an. Ich denke, in Partitionstabellen für jede feed_id zu trennen. Da ich nur pro Feed-ID abrufe. Der Prozentsatz von parent_id null vs not null beträgt ungefähr 60% / 40%. Ein typischer Abruf liegt bei 1-2% der Tabelle. (ca. 100K Nachrichten) Die Leistung für 100K beträgt ca. 1s, aber sobald 500K + erreicht sind, wird der Bitmap-Index verwendet und normalerweise 10s.
ORDER BY
in der Unterabfrage völlig nutzlos. Darüber hinaus kann der verknüpfte Plan nicht das Ergebnis der veröffentlichten Abfrage sein - beispielsweise wird dies nicht erwähntmetadata
.