Ich habe eine PostgreSQL 9.2-Instanz, die auf einem RHEL 6.3-Computer mit 8 Kernen und 16 GB RAM ausgeführt wird. Der Server ist dieser Datenbank zugeordnet. Angesichts der Tatsache, dass die Standardeinstellung für postgresql.conf in Bezug auf die Speichereinstellungen recht konservativ ist, hielt ich es für eine gute Idee, Postgres mehr Speicher zur Verfügung zu stellen. Zu meiner Überraschung hat das Befolgen von Ratschlägen auf wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server praktisch jede Abfrage, die ich ausführe, erheblich verlangsamt, was jedoch bei komplexeren Abfragen offensichtlich auffälliger ist.
Ich habe auch versucht, pgtune auszuführen, was die folgende Empfehlung mit mehr Parametern ergab, aber das hat nichts geändert. Es werden Shared_Buffer von 1/4 der RAM-Größe vorgeschlagen, was anscheinend mit anderen Empfehlungen (insbesondere in PG-Wiki) übereinstimmt.
default_statistics_target = 50
maintenance_work_mem = 960MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 11GB
work_mem = 96MB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 3840MB
max_connections = 80
Ich habe versucht, die gesamte Datenbank nach dem Ändern der Einstellungen neu zu indizieren (mithilfe von reindex database
), aber das hat auch nicht geholfen. Ich habe mit shared_buffers und work_mem rumgespielt. Wenn Sie die sehr konservativen Standardwerte (128 KB / 1 MB) schrittweise ändern, sinkt die Leistung allmählich.
Ich habe EXPLAIN (ANALYZE,BUFFERS)
ein paar Fragen beantwortet und der Schuldige scheint zu sein, dass Hash Join bedeutend langsamer ist. Mir ist nicht klar warum.
Um ein konkretes Beispiel zu nennen: Ich habe die folgende Abfrage. Es wird in der Standardkonfiguration in ~ 2100 ms und in der Konfiguration mit erhöhten Puffergrößen in ~ 3300 ms ausgeführt:
select count(*) from contest c
left outer join contestparticipant cp on c.id=cp.contestId
left outer join teammember tm on tm.contestparticipantid=cp.id
left outer join staffmember sm on cp.id=sm.contestparticipantid
left outer join person p on p.id=cp.personid
left outer join personinfo pi on pi.id=cp.personinfoid
where pi.lastname like '%b%' or pi.firstname like '%a%';
EXPLAIN (ANALYZE,BUFFERS)
für die Abfrage oben:
- Standardpuffer: http://explain.depesz.com/s/xaHJ
- Größere Puffer: http://explain.depesz.com/s/Plk
Die Frage ist, warum ich eine verringerte Leistung beobachte, wenn ich die Puffergröße erhöhe. Der Maschine geht definitiv nicht der Speicher aus. Zuweisung, wenn Shared Memory im Betriebssystem ( shmmax
und shmall
) auf sehr große Werte gesetzt ist, sollte dies kein Problem sein. Ich bekomme auch keine Fehler im Postgres-Log. Ich verwende Autovacuum in der Standardkonfiguration, aber ich erwarte nicht, dass das irgendetwas damit zu tun hat. Alle Abfragen wurden im Abstand von wenigen Sekunden auf demselben Computer ausgeführt, nur mit geänderter Konfiguration (und neu gestartetem PG).
Edit: Ich fand gerade eine besonders interessante Tatsache: Wenn ich den gleichen Test auf meinem iMac Mitte 2010 (OSX 10.7.5) auch mit Postgres 9.2.1 und 16 GB RAM durchführe, spüre ich keine Verlangsamung. Speziell:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Wenn ich genau die gleiche Abfrage (die oben genannte) mit genau den gleichen Daten auf dem Server durchführe, erhalte ich 2100 ms mit work_mem = 1 MB und 3200 ms mit 96 MB.
Der Mac verfügt über eine SSD, ist also verständlicherweise schneller, zeigt aber ein Verhalten, das ich erwarten würde.
Siehe auch die nachfolgende Diskussion zu pgsql-performance .
quelle
Antworten:
Denken Sie zunächst daran, dass work_mem pro Operation ausgeführt wird und daher sehr schnell zu viel wird. Im Allgemeinen würde ich work_mem so lange in Ruhe lassen, bis Sie es brauchen, wenn Sie keine Probleme damit haben, langsam zu sein.
Wenn ich mir Ihre Abfragepläne ansehe, fällt mir auf, dass die Puffertreffer bei beiden Plänen sehr unterschiedlich sind und dass sogar die sequentiellen Scans langsamer sind. Ich vermute, dass das Problem mit Read-Ahead-Caching und weniger Platz dafür zu tun hat. Dies bedeutet, dass Sie den Speicher für die Wiederverwendung von Indizes und gegen das Lesen von Tabellen auf der Festplatte vorbelasten.
Nach meinem Verständnis sucht PostgreSQL nach einer Seite im Cache, bevor es sie von der Festplatte liest, da es nicht genau weiß, ob der Cache des Betriebssystems diese Seite enthält. Da die Seiten dann im Cache verbleiben und dieser Cache langsamer als der Cache des Betriebssystems ist, werden die Arten von Abfragen, die schnell sind, gegenüber den Arten, die langsam sind, geändert. Abgesehen von work_mem-Problemen sieht es so aus, als ob alle Ihre Abfrageinformationen aus dem Cache stammen, es ist jedoch eine Frage des Cache.
work_mem : Wie viel Speicher können wir für eine Sortier- oder verwandte Verknüpfungsoperation reservieren ? Dies erfolgt pro Operation, nicht pro Anweisung oder pro Back-End, sodass eine einzelne komplexe Abfrage ein Vielfaches dieses Speicherplatzes beanspruchen kann. Es ist nicht klar, ob Sie diese Grenze erreichen, aber es lohnt sich, darauf hinzuweisen und sich dessen bewusst zu sein. Wenn Sie dies zu weit erhöhen, verlieren Sie Speicher, der möglicherweise für den Lesecache und die gemeinsam genutzten Puffer verfügbar ist.
shared_buffers : Wie viel Speicher muss der tatsächlichen PostgreSQL-Seitenwarteschlange zugewiesen werden ? Im Idealfall verbleibt der interessante Satz Ihrer Datenbank im Arbeitsspeicher, der hier und in den Lesepuffern zwischengespeichert ist. Dadurch wird jedoch sichergestellt, dass die am häufigsten verwendeten Informationen in allen Backends zwischengespeichert und nicht auf die Festplatte geschrieben werden. Unter Linux ist dieser Cache erheblich langsamer als der Festplatten-Cache des Betriebssystems, bietet jedoch die Garantie, dass der Festplatten-Cache des Betriebssystems nicht vorhanden ist und für PostgreSQL transparent ist. Dies ist ziemlich klar, wo Ihr Problem ist.
Wenn wir also eine Anfrage haben, überprüfen wir zuerst die gemeinsam genutzten Puffer, da PostgreSQL über umfassende Kenntnisse dieses Caches verfügt, und suchen nach den Seiten. Wenn sie nicht vorhanden sind, bitten wir das Betriebssystem, sie aus der Datei zu öffnen. Wenn das Betriebssystem das Ergebnis zwischengespeichert hat, gibt es die zwischengespeicherte Kopie zurück (dies ist schneller als die gemeinsam genutzten Puffer, aber Pg kann nicht feststellen, ob sie zwischengespeichert oder aktiviert ist Datenträger, und Datenträger ist viel langsamer, so dass PostgreSQL diese Chance normalerweise nicht wahrnimmt). Beachten Sie, dass dies auch Auswirkungen auf den zufälligen oder den sequentiellen Seitenzugriff hat. So können Sie mit niedrigeren Einstellungen für shared_buffers eine bessere Leistung erzielen.
Ich gehe davon aus, dass Sie in Umgebungen mit hoher Parallelität und größeren Einstellungen für den gemeinsamen Puffer wahrscheinlich eine bessere oder zumindest konsistentere Leistung erzielen. Denken Sie auch daran, dass PostgreSQL diesen Speicher belegt und speichert. Wenn also andere Dinge auf dem System ausgeführt werden, enthalten die Lesepuffer Dateien, die von anderen Prozessen gelesen wurden. Es ist ein sehr großes und komplexes Thema. Größere gemeinsamen Puffer Einstellungen bieten eine bessere Garantien der Leistung kann aber weniger Leistung in einigen Fällen liefern.
quelle
Abgesehen von dem scheinbar paradoxen Effekt, dass eine Erhöhung
work_mem
die Leistung verringert ( @Chris könnte eine Erklärung haben), können Sie Ihre Funktion auf mindestens zwei Arten verbessern.LEFT JOIN
mitJOIN
. Dies könnte den Abfrageplaner verwirren und zu minderwertigen Plänen führen.pi.firstname
undpi.lastname
, um nicht verankerteLIKE
Suchvorgänge zu unterstützen. (Kürzere Muster wie'%a%'
werden ebenfalls unterstützt, aber ein Index hilft wahrscheinlich nicht bei nicht selektiven Prädikaten.):Oder ein mehrspaltiger Index:
Sollte Ihre Anfrage etwas schneller machen. Dazu müssen Sie das Zusatzmodul pg_trgm installieren . Details unter diesen verwandten Fragen:
Haben Sie auch versucht, die Einstellungen
work_mem
lokal vorzunehmen - nur für die aktuelle Transaktion ?Dies verhindert, dass gleichzeitige Transaktionen auch mehr RAM verbrauchen und sich gegenseitig hungern.
quelle