Die vorliegende Übersetzung wurde maschinell erstellt. Im Falle eines Konflikts oder eines Widerspruchs zwischen dieser übersetzten Fassung und der englischen Fassung (einschließlich infolge von Verzögerungen bei der Übersetzung) ist die englische Fassung maßgeblich.
io:BuffileRead und io:BuffileWrite
Die Ereignisse IO:BufFileRead
und IO:BufFileWrite
treten auf, wenn RDS für PostgreSQL temporäre Dateien erstellt. Wenn Vorgänge mehr Arbeitsspeicher benötigen, als die derzeit definierten Arbeitsspeicherparameter definieren, schreiben sie temporäre Daten in persistenten Speicher. Dieser Vorgang wird manchmal als „Verschütten auf die Festplatte“ bezeichnet.
Unterstützte Engine-Versionen
Diese Warteereignisinformationen werden für alle Versionen von RDS für PostgreSQL unterstützt.
Context
IO:BufFileRead
und IO:BufFileWrite
beziehen sich auf den Arbeitsspeicherbereich und den Wartungsarbeitsspeicherbereich. Weitere Informationen zu diesen lokalen Speicherbereichen finden Sie unter Ressourcennutzung
Der Standardwert für work_mem
ist 4 MB. Wenn eine Sitzung parallel Vorgänge ausführt, verwendet jeder Worker, der die Parallelität bearbeitet, 4 MB Speicher. Stellen Sie work_mem
daher sorgfältig ein. Wenn Sie den Wert zu stark erhöhen, verbraucht eine Datenbank mit vielen Sitzungen möglicherweise zu viel Speicher. Wenn Sie den Wert zu niedrig festlegen, erstellt RDS für PostgreSQL temporäre Dateien im lokalen Speicher. Die Festplatten-I/O für diese temporären Dateien kann die Leistung verringern.
Wenn Sie die folgende Ereignisfolge beobachten, generiert Ihre Datenbank möglicherweise temporäre Dateien:
-
Plötzlicher und starker Rückgang der Verfügbarkeit
-
Schnelle Erholung für den freien Speicherplatz
Möglicherweise sehen Sie auch ein „Kettensäge“ -Muster. Dieses Muster kann darauf hinweisen, dass Ihre Datenbank ständig kleine Dateien erstellt.
Wahrscheinliche Ursachen für erhöhte Wartezeiten
Im Allgemeinen werden diese Warteereignisse durch Vorgänge verursacht, die mehr Speicher verbrauchen, als die Parameter work_mem
oder maintenance_work_mem
zuweisen. Um dies zu kompensieren, schreiben die Vorgänge in temporäre Dateien. Häufige Ursachen für die IO:BufFileRead
- und IO:BufFileWrite
-Ereignisse sind die folgenden:
- Abfragen, die mehr Speicher benötigen als im Arbeitsspeicherbereich vorhanden
-
Abfragen mit den folgenden Merkmalen verwenden den Arbeitsspeicherbereich:
-
Hash-Verknüpfungen
-
ORDER BY
-Klausel -
GROUP BY
-Klausel -
DISTINCT
-
Fensterfunktionen
-
CREATE TABLE AS SELECT
-
Aktualisierung der materialisierten Ansicht
-
- Anweisungen, die mehr Speicher benötigen als im Arbeitsspeicherbereich für Wartungsarbeiten vorhanden
-
Die folgenden Anweisungen verwenden den Arbeitsspeicherbereich für Wartungsarbeiten:
-
CREATE INDEX
-
CLUSTER
-
Aktionen
Abhängig von den Ursachen Ihres Wait-Ereignisses empfehlen wir verschiedene Aktionen.
Themen
- Identifizieren Sie das Problem
- Untersuchen Sie Ihre Join-Anfragen
- Überprüfen Sie Ihre ORDER BY- und GROUP BY Anfragen
- Verwenden Sie den DISTINCT-Vorgang nicht
- Erwägen Sie, Fensterfunktionen anstelle von GROUP-BY-Funktionen zu verwenden
- Untersuchen Sie materialisierte Ansichten und CTAS-Aussagen
- Verwenden von pg_repack beim Neuerstellen von Indizes
- Erhöhen Sie maintenance work_mem, wenn Sie Tabellen clustern
- Optimieren Sie den Speicher, um io:BuffileRead und io:BuffileWrite zu verhindern
Identifizieren Sie das Problem
Nehmen Sie an, dass Performance Insights nicht aktiviert ist und Sie vermuten, dass IO:BufFileRead
und IO:BufFileWrite
häufiger als normal auftreten. Um die Ursache des Problems zu ermitteln, können Sie den log_temp_files
-Parameter so festlegen, dass alle Abfragen protokolliert werden, die mehr als den angegebenen Schwellenwert an temporären Dateien in KB generieren. log_temp_files
ist standardmäßig auf -1
festgelegt, wodurch diese Protokollierungsfunktion deaktiviert wird. Wenn Sie diesen Parameter auf 0
einstellen, protokolliert RDS für PostgreSQL alle temporären Dateien. Wenn der Wert 1024
ist, protokolliert RDS für PostgreSQL alle Abfragen, die temporäre Dateien erzeugen, die größer als 1 MB sind. Weitere Informationen zu log_temp_files
finden Sie unter Fehlerberichte und -protokollierung
Untersuchen Sie Ihre Join-Anfragen
Es ist wahrscheinlich, dass Ihre Abfrage Joins verwendet. Die folgende Abfrage verbindet beispielsweise vier Tabellen.
SELECT * FROM "order" INNER JOIN order_item ON (order.id = order_item.order_id) INNER JOIN customer ON (customer.id = order.customer_id) INNER JOIN customer_address ON (customer_address.customer_id = customer.id AND order.customer_address_id = customer_address.id) WHERE customer.id = 1234567890;
Eine mögliche Ursache für Spitzen bei der Verwendung temporärer Dateien ist ein Problem in der Abfrage selbst. Beispielsweise filtert eine defekte Klausel die Joins möglicherweise nicht richtig. Betrachten Sie den zweiten inneren Join im folgenden Beispiel.
SELECT * FROM "order" INNER JOIN order_item ON (order.id = order_item.order_id) INNER JOIN customer ON (customer.id = customer.id) INNER JOIN customer_address ON (customer_address.customer_id = customer.id AND order.customer_address_id = customer_address.id) WHERE customer.id = 1234567890;
Die obige Abfrage verknüpft fälschlicherweise customer.id
mit customer.id
, wodurch zwischen jedem Kunden und jeder Bestellung ein kartesisches Produkt generiert wird. Diese Art des versehentlichen Joins generiert große temporäre Dateien. Abhängig von der Größe der Tabellen kann eine kartesische Abfrage sogar Speicher füllen. Wenn die folgenden Bedingungen erfüllt sind, hat Ihre Anwendung möglicherweise kartesische Joins:
-
Sie sehen einen großen, starken Rückgang der Speicherverfügbarkeit, gefolgt von einer schnellen Wiederherstellung.
-
Es werden keine Indizes erstellt.
-
Es werden keine
CREATE TABLE FROM SELECT
-Anweisungen ausgegeben. -
Es werden keine materialisierten Ansichten aktualisiert.
Um festzustellen, ob die Tabellen mit den richtigen Schlüsseln verbunden werden, überprüfen Sie Ihre Abfrage- und objektrelationalen Mapping-Anweisungen. Denken Sie daran, dass bestimmte Abfragen Ihrer Anwendung nicht ständig aufgerufen werden und einige Abfragen dynamisch generiert werden.
Überprüfen Sie Ihre ORDER BY- und GROUP BY Anfragen
In einigen Fällen kann eine ORDER BY
-Klausel zu übermäßig vielen temporären Dateien führen. Berücksichtigen Sie die folgenden Hinweise:
-
Schließen Sie Spalten nur dann in eine
ORDER BY
-Klausel ein, wenn sie sortiert werden müssen. Diese Richtlinie ist besonders wichtig für Abfragen, die Tausende von Zeilen zurückgeben und viele Spalten in derORDER BY
-Klausel angeben. -
Ziehen Sie in Betracht, Indizes zu erstellen, um
ORDER BY
-Klauseln zu beschleunigen, wenn sie mit Spalten übereinstimmen, die dieselbe aufsteigende oder absteigende Reihenfolge aufweisen. Partielle Indizes sind vorzuziehen, da sie kleiner sind. Kleinere Indizes werden schneller gelesen und durchquert. -
Wenn Sie Indizes für Spalten erstellen, die Nullwerte akzeptieren können, überlegen Sie, ob die Nullwerte am Ende oder am Anfang der Indizes gespeichert werden sollen.
Reduzieren Sie nach Möglichkeit die Anzahl der Zeilen, die sortiert werden müssen, indem Sie die Ergebnismenge filtern. Wenn Sie
WITH
-Klausel-Anweisungen oder Unterabfragen verwenden, denken Sie daran, dass eine innere Abfrage eine Ergebnismenge generiert und an die äußere Abfrage übergibt. Je mehr Zeilen eine Abfrage herausfiltern kann, desto weniger muss die Abfrage erledigen. -
Wenn Sie nicht die vollständige Ergebnismenge abrufen müssen, verwenden Sie die
LIMIT
-Klausel. Wenn Sie beispielsweise nur die obersten fünf Zeilen benötigen, generiert eine Abfrage mit derLIMIT
-Klausel keine Ergebnisse. Auf diese Weise benötigt die Abfrage weniger Speicher und temporäre Dateien.
Eine Abfrage, die eine GROUP BY
-Klausel verwendet, kann auch temporäre Dateien erfordern. GROUP BY
-Abfragen fassen Werte mithilfe von Funktionen wie den folgenden zusammen:
-
COUNT
-
AVG
-
MIN
-
MAX
-
SUM
-
STDDEV
Befolgen Sie zum Optimieren von GROUP BY
-Abfragen die Empfehlungen für ORDER BY
-Abfragen.
Verwenden Sie den DISTINCT-Vorgang nicht
Vermeiden Sie nach Möglichkeit die Verwendung des DISTINCT
-Vorgangs, um doppelte Zeilen zu entfernen. Je mehr unnötige und doppelte Zeilen Ihre Abfrage zurückgibt, desto teurer wird der DISTINCT
-Vorgang. Fügen Sie nach Möglichkeit Filter in der WHERE
-Klausel hinzu, auch wenn Sie dieselben Filter für verschiedene Tabellen verwenden. Das Filtern der Abfrage und der korrekte Beitritt verbessern Ihre Leistung und reduziert den Ressourcennutzung. Es verhindert auch falsche Berichte und Ergebnisse.
Wenn Sie DISTINCT
für mehrere Zeilen derselben Tabelle verwenden müssen, sollten Sie einen zusammengesetzten Index erstellen. Das Gruppieren mehrerer Spalten in einem Index kann die Zeit zum Auswerten verschiedener Zeilen verbessern. Wenn Sie Version 10 von RDS für PostgreSQL oder höher verwenden, können Sie außerdem mithilfe des CREATE STATISTICS
-Befehls Statistiken zwischen mehreren Spalten korrelieren.
Erwägen Sie, Fensterfunktionen anstelle von GROUP-BY-Funktionen zu verwenden
Mit GROUP BY
ändern Sie die Ergebnismenge und rufen dann das aggregierte Ergebnis ab. Mithilfe von Fensterfunktionen aggregieren Sie Daten, ohne die Ergebnismenge zu ändern. Eine Fensterfunktion verwendet die OVER
-Klausel, um Berechnungen über die von der Abfrage definierten Mengen durchzuführen und eine Zeile mit einer anderen zu korrelieren. Sie können alle GROUP BY
-Funktionen in Fensterfunktionen verwenden, aber auch Funktionen wie die folgenden verwenden:
-
RANK
-
ARRAY_AGG
-
ROW_NUMBER
-
LAG
-
LEAD
Um die Anzahl der temporären Dateien zu minimieren, die von einer Fensterfunktion generiert werden, entfernen Sie Duplikationen für dieselbe Ergebnismenge, wenn Sie zwei verschiedene Aggregationen benötigen. Betrachten Sie folgende Abfrage.
SELECT sum(salary) OVER (PARTITION BY dept ORDER BY salary DESC) as sum_salary , avg(salary) OVER (PARTITION BY dept ORDER BY salary ASC) as avg_salary FROM empsalary;
Sie können die Abfrage mit der WINDOW
-Klausel wie folgt umschreiben.
SELECT sum(salary) OVER w as sum_salary , avg(salary) OVER w as_avg_salary FROM empsalary WINDOW w AS (PARTITION BY dept ORDER BY salary DESC);
Standardmäßig konsolidiert der Ausführungsplaner von RDS für PostgreSQL ähnliche Knoten, sodass keine Vorgänge dupliziert werden. Durch die Verwendung einer expliziten Deklaration für den Fensterblock können Sie die Abfrage jedoch einfacher pflegen. Sie können die Leistung auch verbessern, indem Sie Doppelarbeit verhindern.
Untersuchen Sie materialisierte Ansichten und CTAS-Aussagen
Wenn eine materialisierte Ansicht aktualisiert wird, wird eine Abfrage ausgeführt. Diese Abfrage kann einen Vorgang wie GROUP BY
, ORDER BY
oder DISTINCT
enthalten. Während einer Aktualisierung können Sie eine große Anzahl temporärer Dateien und die Warteereignisse IO:BufFileWrite
und IO:BufFileRead
beobachten. Wenn Sie eine Tabelle basierend auf einer SELECT
-Anweisung erstellen, führt die CREATE TABLE
-Anweisung eine Abfrage aus. Um die benötigten temporären Dateien zu reduzieren, optimieren Sie die Abfrage.
Verwenden von pg_repack beim Neuerstellen von Indizes
Wenn Sie einen Index erstellen, ordnet die Engine die Ergebnismenge an. Wenn Tabellen größer werden und die Werte in der indizierten Spalte vielfältiger werden, benötigen die temporären Dateien mehr Speicherplatz. In den meisten Fällen können Sie die Erstellung temporärer Dateien für große Tabellen nicht verhindern, ohne den Speicherbereich für Wartungsarbeiten zu ändern. Weitere Informationen zu maintenance_work_mem
finden Sie unter https://www.postgresql.org/docs/current/runtime-config-resource.html
Eine mögliche Problemumgehung beim Neuerstellen eines großen Index besteht darin, die pg_repack-Erweiterung zu verwenden. Weitere Informationen finden Sie unter Reorganisieren von Tabellen in PostgreSQL-Datenbanken mit minimalen Sperren
Erhöhen Sie maintenance work_mem, wenn Sie Tabellen clustern
Der Befehl CLUSTER
gruppiert die durch table_name angegebene Tabelle basierend auf einem vorhandenen Index, der durch index_name angegeben wird. RDS für PostgreSQL erstellt die Tabelle physisch so neu, dass sie der Reihenfolge eines bestimmten Indexes entspricht.
Als magnetische Speicherung vorherrschend war, war Clustering üblich, da der Speicherdurchsatz begrenzt war. Jetzt, da SSD-basierter Speicher üblich ist, ist Clustering weniger beliebt. Wenn Sie jedoch Tabellen clustern, können Sie die Leistung je nach Tabellengröße, Index, Abfrage usw. immer noch geringfügig steigern.
Wenn Sie den Befehl CLUSTER
ausführen und die Warteereignisse IO:BufFileWrite
und IO:BufFileRead
beobachten, stimmen Sie maintenance_work_mem
ab. Erhöhen Sie die Speichergröße auf einen ziemlich großen Betrag. Ein hoher Wert bedeutet, dass die Engine mehr Speicher für den Clustering-Vorgang verwenden kann.
Optimieren Sie den Speicher, um io:BuffileRead und io:BuffileWrite zu verhindern
In einigen Situationen müssen Sie den Speicher optimieren. Ihr Ziel ist es, mithilfe der entsprechenden Parameter den Arbeitsspeicher in den folgenden Verbrauchsbereichen wie folgt auszugleichen.
-
Der
work_mem
-Wert -
Der Speicher, der nach Abzug des Werts
shared_buffers
verbleibt -
Die maximale Anzahl geöffneter und verwendeter Verbindungen, die durch
max_connections
begrenzt ist
Weitere Informationen zum Optimieren des Arbeitsspeichers finden Sie unter Ressourcennutzung
Erhöhen Sie die Größe des Arbeitsspeicherbereichs
In einigen Situationen besteht Ihre einzige Möglichkeit darin, den von Ihrer Sitzung verwendeten Speicher zu erhöhen. Wenn Ihre Abfragen richtig geschrieben sind und die richtigen Schlüssel für Joins verwenden, sollten Sie den work_mem
-Wert erhöhen.
Um herauszufinden, wie viele temporäre Dateien eine Abfrage generiert, setzen Sie log_temp_files
auf 0
. Wenn Sie den work_mem
-Wert auf den in den Protokollen angegebenen Höchstwert erhöhen, verhindern Sie, dass die Abfrage temporäre Dateien generiert. work_mem
legt jedoch das Maximum pro Planknoten für jede Verbindung oder jeden parallelen Worker fest. Wenn die Datenbank über 5.000 Verbindungen verfügt und jede 256 MiB-Speicher verwendet, benötigt die Engine 1,2 TiB RAM. Daher kann es sein, dass Ihrer Instance der Speicher knapp wird.
Reservieren Sie ausreichend Speicher für den freigegebenen Pufferpool
Ihre Datenbank verwendet Speicherbereiche wie den freigegebenen Pufferpool, nicht nur den Arbeitsspeicherbereich. Berücksichtigen Sie die Anforderungen dieser zusätzlichen Speicherbereiche, bevor Sie work_mem
erhöhen.
Angenommen, Ihre Instance-Klasse von RDS für PostgreSQL ist db.r5.2xlarge. Diese Klasse hat 64 GiB Speicher. Standardmäßig sind 25 Prozent des Arbeitsspeichers für den freigegebenen Pufferpool reserviert. Nachdem Sie den dem Shared Memory-Bereich zugewiesenen Betrag abgezogen haben, bleiben 16.384 MB übrig. Weisen Sie den verbleibenden Speicher nicht ausschließlich dem Arbeitsspeicherbereich zu, da das Betriebssystem und die Engine ebenfalls Speicher benötigen.
Der Speicher, den Sie work_mem
zuordnen können, hängt von der Instance-Klasse ab. Wenn Sie eine größere Instance-Klasse verwenden, ist mehr Speicher verfügbar. Im vorhergehenden Beispiel können Sie jedoch nicht mehr als 16 GiB verwenden. Andernfalls ist Ihre Instance nicht verfügbar, wenn ihr der Speicher ausgeht. Um die Instance aus dem nicht verfügbaren Status wiederherzustellen, werden die Automatisierungsdienste von RDS für PostgreSQL automatisch neu gestartet.
Verwalten der Anzahl der Verbindungen
Angenommen, Ihre Datenbank-Instance hat 5.000 gleichzeitige Verbindungen. Jede Verbindung verwendet mindestens 4 MB work_mem
. Der hohe Speicherverbrauch der Verbindungen dürfte die Leistung beeinträchtigen. Als Reaktion darauf haben Sie die folgenden Optionen:
-
Aktualisieren Sie auf eine größere Instance-Klasse.
-
Verringern Sie die Anzahl gleichzeitiger Datenbankverbindungen mit einem Verbindungsproxy oder Pooler.
Berücksichtigen Sie bei Proxys Amazon RDS Proxy, PGBouncer oder einen auf Ihrer Anwendung basierenden Verbindungspooler. Diese Lösung lindert die CPU-Last. Es reduziert auch das Risiko, wenn alle Verbindungen den Arbeitsspeicherbereich benötigen. Wenn weniger Datenbankverbindungen vorhanden sind, können Sie den Wert von work_mem
erhöhen. Auf diese Weise reduzieren Sie das Auftreten der IO:BufFileRead
- und IO:BufFileWrite
-Warteereignisse. Auch die Abfragen, die auf den Arbeitsspeicherbereich warten, beschleunigen sich erheblich.