Ich habe eine einfache Blog-Datenbank in postgres-8.4, die zwei Tabellen enthält, articles
und comments
. Ich habe eine Abfrage (generiert von Django), die den neuesten Artikel vom Typ 'NEWS' abrufen und auch die Anzahl der Kommentare für diesen Artikel ermitteln möchte. Dies geschieht mit der folgenden Abfrage:
SELECT "articles"."id", "articles"."datestamp", "articles"."title", "articles"."shorttitle", "articles"."description", "articles"."markdown", "articles"."body", "articles"."idxfti", "articles"."published", "articles"."type", COUNT("comments"."id") AS "comment__count"
FROM "articles"
LEFT OUTER JOIN "comments" ON ("articles"."id" = "comments"."article_id")
WHERE ("articles"."type"='NEWS')
GROUP BY "articles"."id", "articles"."datestamp", "articles"."title", "articles"."shorttitle", "articles"."description", "articles"."markdown", "articles"."body", "articles"."idxfti", "articles"."published", "articles"."type"
ORDER BY "articles"."datestamp" DESC
LIMIT 1;
Keine dieser Tabellen ist besonders groß, und dennoch dauert diese Abfrage 46 ms. Der Ausführungsplan lautet:
Limit (cost=119.54..119.58 rows=1 width=1150) (actual time=46.479..46.481 rows=1 loops=1)
-> GroupAggregate (cost=119.54..138.88 rows=455 width=1150) (actual time=46.475..46.475 rows=1 loops=1)
-> Sort (cost=119.54..120.68 rows=455 width=1150) (actual time=46.426..46.428 rows=2 loops=1)
Sort Key: articles.datestamp, articles.id, articles.title, articles.shorttitle, articles.description, articles.markdown, articles.body, articles.idxfti, articles.published, articles.type
Sort Method: quicksort Memory: 876kB
-> Hash Left Join (cost=11.34..99.45 rows=455 width=1150) (actual time=0.513..2.527 rows=566 loops=1)
Hash Cond: (articles.id = comments.article_id)
-> Seq Scan on articles (cost=0.00..78.84 rows=455 width=1146) (actual time=0.017..0.881 rows=455 loops=1)
Filter: ((type)::text = 'NEWS'::text)
-> Hash (cost=8.93..8.93 rows=193 width=8) (actual time=0.486..0.486 rows=193 loops=1)
-> Seq Scan on comments (cost=0.00..8.93 rows=193 width=8) (actual time=0.004..0.252 rows=193 loops=1)
Total runtime: 46.574 ms
In der Artikeltabelle ist (unter anderem) folgender Index definiert:
idx_articles_datestamp" btree (datestamp DESC) CLUSTER
Bevor ich es gruppierte, entsprach die Ausführung der Abfrage eher den Schätzungen (ca. 119 ms).
Für mein ungeübtes Auge sieht es so aus, als würde die Sorte hier am meisten Zeit in Anspruch nehmen. Es scheint auch auf allen GROUP zu versuchen , von Feldern zu sortieren, das Problem ist , dass es versucht , auf drei relativ große Felder zu sortieren, body
, markdown
und idx_fti
.
Meine Frage lautet: Ist dies eine unangemessene Zeit, die diese Abfrage in Anspruch nimmt, oder gibt es etwas Offensichtliches, das ich verpasst habe, um diese Abfrage zu beschleunigen? Alle anderen von dieser Blog-Site angeforderten Abfragen benötigen ca. 1-5 ms, um ausgeführt zu werden. Daher dauert diese Abfrage sehr lange. Ich schätze, dass es einen OUTER JOIN und einen SORT gibt, die nicht wirklich helfen. Ich bin jedoch kein Experte. Wenn also jemand Vorschläge hat, wäre das äußerst nützlich.
quelle
Eine andere Möglichkeit, die Abfrage mit einer Inline-Unterabfrage neu zu schreiben:
quelle
comments(article)
und dem oben genannten Index anarticles(type, datestamp DESC)
. Die Abfrage wird verwendetLIMIT 1
, daher sollten nur relevante Zeilen abgerufenarticle
und gezählt werden.Wenn articles.type weniger als 10% der Tabelle ausmacht, können Sie von einem Index für diese Spalte profitieren. Sie können mit ziemlicher Sicherheit von einem Index für comment.article_id profitieren, falls Sie noch keinen haben.
Wenn Sie die Kostenfaktoren in Ihrer Konfiguration nicht angepasst haben, können Sie außerdem versuchen, sie
random_page_cost
auf einen Wert zwischen 1,0 und 2,0 zu senken . wenn Ihre aktive Datensatz vollständig zwischengespeichert wird, sollen Sie wahrscheinlich , dass nehmen undseq_page_cost
bis zu 0,1. Sie sollten wahrscheinlichcpu_tuple_cost
auf einen Wert zwischen 0,03 und 0,05 ansteigen .effective_cache_size
sollte die Summe vonshared_buffers
und was auch immer Ihr Betriebssystem als Cache-Speicherplatz anzeigt.quelle
comments.article_id
, und das Hinzufügen eines Indexarticles.type
schien nicht viel zu bewirken. Ich werde versuchen, einige der Servereinstellungen zu optimieren, danke dafür.Möglicherweise möchten Sie versuchen, die Gruppe durch zu entfernen und eine Fensterfunktion zum Zählen zu verwenden. Dadurch entfällt die Notwendigkeit, alle Spalten nach / sort zu gruppieren:
quelle
(type ASC, datestamp DESC)
würde die Leistung zusätzlich verbessern, nicht wahr?GROUP BY
die Primärschlüsselspalte (n) haben, müssen Sie keine der anderen Spalten aus dieser Tabelle einschließen.create index idx_articles_type_datestamp on articles(type ASC, datestamp DESC)
aber das schien keinen großen Unterschied zu machen. Ich werde sehen, was ich tun kann, um Django zu einem zu zwingenCOUNT OVER
, aber habe ich Recht, wenn ich denke, dass das Pg-spezifisch ist?Vielleicht könnten Sie einige Tests durchführen, um den Wert von work_mem zu ändern . Dort finden Sie Anweisungen, wie viel Speicher für die Sortiervorgänge verwendet wird.
quelle