E/A:DataFileRead - Amazon Relational Database Service

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.

E/A:DataFileRead

Das IO:DataFileRead-Ereignis tritt auf, wenn eine Verbindung darauf wartet, dass ein Backend-Prozess eine erforderliche Seite aus dem Speicher liest, da die Seite nicht im gemeinsam genutzten Speicher verfügbar ist.

Unterstützte Engine-Versionen

Diese Warteereignisinformationen werden für alle Versionen von RDS für PostgreSQL unterstützt.

Kontext

Alle Abfragen und Datenmanipulationsvorgänge (DML) greifen auf Seiten im Pufferpool zu. Zu den Anweisungen, die Lesevorgänge auslösen können, gehören SELECT, UPDATE und DELETE. Ein UPDATE kann beispielsweise Seiten aus Tabellen oder Indizes lesen. Wenn sich die angeforderte oder aktualisierte Seite nicht im gemeinsam genutzten Pufferpool befindet, kann dieser Lesevorgang zum IO:DataFileRead-Ereignis führen.

Da der gemeinsame Pufferpool endlich ist, kann er sich füllen. In diesem Fall zwingen Anfragen nach Seiten, die sich nicht im Speicher befinden, die Datenbank dazu, Blöcke von der Festplatte zu lesen. Wenn das IO:DataFileRead-Ereignis häufig auftritt, ist Ihr gemeinsam genutzter Pufferpool möglicherweise zu klein für Ihre Workload. Dieses Problem ist bei SELECT-Abfragen akut, die eine große Anzahl von Zeilen lesen, die nicht in den Pufferpool passen. Weitere Informationen zum Pufferpool finden Sie unter Ressourcenbnutzung in der PostgreSQL-Dokumentation.

Wahrscheinliche Ursachen für erhöhte Wartezeiten

Häufige Ursachen für das Ereignis IO:DataFileRead sind die folgenden:

Verbindungsspitzen

Möglicherweise finden Sie mehrere Verbindungen, die die gleiche Anzahl von IO:DataFileRead wait-Ereignissen generieren. In diesem Fall kann eine Spitze (plötzlicher und starker Anstieg) bei IO:DataFileRead-Ereignissen auftreten.

SELECT- und DML-Anweisungen, die sequentielle Scans durchführen

Ihre Anwendung führt möglicherweise einen neuen Vorgang aus. Oder ein vorhandener Vorgang könnte sich aufgrund eines neuen Ausführungsplans ändern. Suchen Sie in solchen Fällen nach Tabellen (insbesondere großen Tabellen), die einen größeren seq_scan-Wert haben. Finden Sie sie, indem Sie pg_stat_user_tables abfragen. Verwenden Sie die Erweiterung pg_stat_statements, um Abfragen zu verfolgen, die mehr Lesevorgänge generieren.

CTAS und CREATE INDEX für große Datensätze

Ein CTAS ist eine CREATE TABLE AS SELECT-Anweisung. Wenn Sie ein CTAS mit einem großen Datensatz als Quelle ausführen oder einen Index für eine große Tabelle erstellen, kann das IO:DataFileRead-Ereignis auftreten. Wenn Sie einen Index erstellen, muss die Datenbank möglicherweise das gesamte Objekt mithilfe eines sequentiellen Scans lesen. Ein CTAS generiert IO:DataFile-Reads, wenn Seiten nicht im Speicher sind.

Mehrere Vakuumarbeiter laufen gleichzeitig

Vakuumarbeiter können manuell oder automatisch ausgelöst werden. Wir empfehlen, eine aggressive Vakuumstrategie zu verabschieden. Wenn eine Tabelle jedoch viele aktualisierte oder gelöschte Zeilen enthält, erhöhen sich die IO:DataFileRead-Wartezeiten. Nachdem der Raum zurückgewonnen wurde, nimmt die für IO:DataFileRead aufgewendete Vakuumzeit ab.

Aufnahme großer Datenmengen

Wenn Ihre Anwendung große Datenmengen aufnimmt, können ANALYZE-Vorgänge häufiger auftreten. Der ANALYZE-Prozess kann durch einen Autovacuum Launcher ausgelöst oder manuell aufgerufen werden.

Der ANALYZE-Vorgang liest eine Teilmenge der Tabelle. Die Anzahl der zu scannenden Seiten wird berechnet, indem 30 mit dem default_statistics_target-Wert multipliziert wird. Weitere Informationen finden Sie in der PostgreSQL-Dokumentation. Der Parameter default_statistics_target akzeptiert Werte zwischen 1 und 10.000, wobei der Standardwert 100 ist.

Hungertod

Wenn Netzwerkbandbreite oder CPU der Instance verbraucht werden, kann das IO:DataFileRead-Ereignis häufiger auftreten.

Aktionen

Abhängig von den Ursachen Ihres Warteereignisses empfehlen wir verschiedene Aktionen.

Überprüfen Sie Prädikatfilter auf Abfragen, die Wartezeiten generieren

Angenommen, Sie identifizieren bestimmte Abfragen, die IO:DataFileRead-Warteereignisse generieren. Sie können sie mit den folgenden Techniken identifizieren:

  • Performance Insights

  • Katalogansichten wie die der Erweiterung pg_stat_statements

  • Die Katalogansicht pg_stat_all_tables, wenn sie periodisch eine erhöhte Anzahl von physischen Lesevorgängen anzeigt

  • Die pg_statio_all_tables-Ansicht, wenn sie zeigt, dass _read-Zähler steigen

Wir empfehlen Ihnen, zu bestimmen, welche Filter im Prädikat (WHERE-Klausel) dieser Abfragen verwendet werden. Befolgen Sie diese Richtlinien:

  • Führen Sie den Befehl EXPLAIN aus. Geben Sie in der Ausgabe an, welche Arten von Scans verwendet werden. Ein sequentieller Scan weist nicht zwangsläufig ein Problem an. Abfragen, die sequenzielle Scans verwenden, erzeugen im Vergleich zu Abfragen, die Filter verwenden, natürlich mehr IO:DataFileRead-Ereignisse.

    Finden Sie heraus, ob die in der WHERE-Klausel aufgeführte Spalte indiziert ist. Wenn nicht, erwägen Sie, einen Index für diese Spalte zu erstellen. Dieser Ansatz vermeidet die sequentiellen Scans und reduziert die IO:DataFileRead-Ereignisse. Wenn eine Abfrage restriktive Filter enthält und immer noch sequenzielle Scans erzeugt, bewerten Sie, ob die richtigen Indizes verwendet werden.

  • Finden Sie heraus, ob die Abfrage auf eine sehr große Tabelle zugreift. In einigen Fällen kann das Partitionieren einer Tabelle die Leistung verbessern, sodass die Abfrage nur notwendige Partitionen lesen kann.

  • Untersuchen Sie die Kardinalität (Gesamtzahl der Zeilen) Ihrer Join-Vorgänge. Beachten Sie, wie restriktiv die Werte sind, die Sie den Filtern für Ihre WHERE-Klausel übergeben. Wenn möglich, stimmen Sie Ihre Abfrage ein, um die Anzahl der Zeilen zu reduzieren, die in jedem Schritt des Plans übergeben werden.

Minimieren Sie die Auswirkungen von Wartungsvorgängen

Wartungsvorgänge wie VACUUM und ANALYZE sind wichtig. Wir empfehlen, sie nicht zu deaktivieren, da Sie IO:DataFileRead-Warteereignisse im Zusammenhang mit diesen Wartungsvorgängen finden. Die folgenden Ansätze können die Auswirkungen dieser Vorgänge minimieren:

  • Führen Sie Wartungsvorgänge während außerhalb der Hauptverkehrszeiten manuell aus. Diese Technik verhindert, dass die Datenbank den Schwellenwert für automatische Vorgänge erreicht.

  • Erwägen Sie bei sehr großen Tabellen, die Tabelle zu partitionieren. Diese Technik reduziert den Overhead von Wartungsvorgängen. Die Datenbank greift nur auf die Partitionen zu, die gewartet werden müssen.

  • Wenn Sie große Datenmengen aufnehmen, sollten Sie die Funktion zur automatischen Analyse deaktivieren.

Die Auto-Vakuum-Funktion wird automatisch für eine Tabelle ausgelöst, wenn die folgende Formel zutrifft.

pg_stat_user_tables.n_dead_tup > (pg_class.reltuples x autovacuum_vacuum_scale_factor) + autovacuum_vacuum_threshold

Die Ansicht pg_stat_user_tables und der Katalog pg_class haben mehrere Zeilen. Eine Zeile kann einer Zeile in Ihrer Tabelle entsprechen. Diese Formel geht davon aus, dass die reltuples für eine bestimmte Tabelle stehen. Die Parameter autovacuum_vacuum_scale_factor (standardmäßig 0.20) und autovacuum_vacuum_threshold (standardmäßig 50 Tupel) werden normalerweise global für die gesamte Instance gesetzt. Sie können jedoch verschiedene Werte für eine bestimmte Tabelle festlegen.

Suchen nach Tabellen, die unnötigerweise Speicherplatz belegen

Um Tabellen zu finden, die unnötig Speicherplatz beanspruchen, können Sie Funktionen der pgstattuple-Erweiterung von PostgreSQL verwenden. Diese Erweiterung (Modul) ist standardmäßig auf allen DB-Instances von RDS für PostgreSQL verfügbar und kann mit dem folgenden Befehl auf der Instance instanziiert werden.

CREATE EXTENSION pgstattuple;

Weitere Informationen zu dieser Erweiterung finden Sie unter pgstattuple in der PostgreSQL-Dokumentation.

Sie können in Ihrer Anwendung nach einer Überlastung von Tabellen und Indizes suchen. Weitere Informationen finden Sie unter Diagnostizieren einer Überlastung von Tabellen und Indizes.

Suchen nach Indizes, die unnötigerweise Speicherplatz belegen

Um aufgeblähte Indizes zu finden und abzuschätzen, wie viel Speicherplatz in den Tabellen, für die Sie Leserechte haben, unnötig beansprucht wird, können Sie die folgende Abfrage ausführen.

-- WARNING: rows with is_na = 't' are known to have bad statistics ("name" type is not supported). -- This query is compatible with PostgreSQL 8.2 and later. SELECT current_database(), nspname AS schemaname, tblname, idxname, bs*(relpages)::bigint AS real_size, bs*(relpages-est_pages)::bigint AS extra_size, 100 * (relpages-est_pages)::float / relpages AS extra_ratio, fillfactor, bs*(relpages-est_pages_ff) AS bloat_size, 100 * (relpages-est_pages_ff)::float / relpages AS bloat_ratio, is_na -- , 100-(sub.pst).avg_leaf_density, est_pages, index_tuple_hdr_bm, -- maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, sub.reltuples, sub.relpages -- (DEBUG INFO) FROM ( SELECT coalesce(1 + ceil(reltuples/floor((bs-pageopqdata-pagehdr)/(4+nulldatahdrwidth)::float)), 0 -- ItemIdData size + computed avg size of a tuple (nulldatahdrwidth) ) AS est_pages, coalesce(1 + ceil(reltuples/floor((bs-pageopqdata-pagehdr)*fillfactor/(100*(4+nulldatahdrwidth)::float))), 0 ) AS est_pages_ff, bs, nspname, table_oid, tblname, idxname, relpages, fillfactor, is_na -- , stattuple.pgstatindex(quote_ident(nspname)||'.'||quote_ident(idxname)) AS pst, -- index_tuple_hdr_bm, maxalign, pagehdr, nulldatawidth, nulldatahdrwidth, reltuples -- (DEBUG INFO) FROM ( SELECT maxalign, bs, nspname, tblname, idxname, reltuples, relpages, relam, table_oid, fillfactor, ( index_tuple_hdr_bm + maxalign - CASE -- Add padding to the index tuple header to align on MAXALIGN WHEN index_tuple_hdr_bm%maxalign = 0 THEN maxalign ELSE index_tuple_hdr_bm%maxalign END + nulldatawidth + maxalign - CASE -- Add padding to the data to align on MAXALIGN WHEN nulldatawidth = 0 THEN 0 WHEN nulldatawidth::integer%maxalign = 0 THEN maxalign ELSE nulldatawidth::integer%maxalign END )::numeric AS nulldatahdrwidth, pagehdr, pageopqdata, is_na -- , index_tuple_hdr_bm, nulldatawidth -- (DEBUG INFO) FROM ( SELECT i.nspname, i.tblname, i.idxname, i.reltuples, i.relpages, i.relam, a.attrelid AS table_oid, current_setting('block_size')::numeric AS bs, fillfactor, CASE -- MAXALIGN: 4 on 32bits, 8 on 64bits (and mingw32 ?) WHEN version() ~ 'mingw32' OR version() ~ '64-bit|x86_64|ppc64|ia64|amd64' THEN 8 ELSE 4 END AS maxalign, /* per page header, fixed size: 20 for 7.X, 24 for others */ 24 AS pagehdr, /* per page btree opaque data */ 16 AS pageopqdata, /* per tuple header: add IndexAttributeBitMapData if some cols are null-able */ CASE WHEN max(coalesce(s.null_frac,0)) = 0 THEN 2 -- IndexTupleData size ELSE 2 + (( 32 + 8 - 1 ) / 8) -- IndexTupleData size + IndexAttributeBitMapData size ( max num filed per index + 8 - 1 /8) END AS index_tuple_hdr_bm, /* data len: we remove null values save space using it fractionnal part from stats */ sum( (1-coalesce(s.null_frac, 0)) * coalesce(s.avg_width, 1024)) AS nulldatawidth, max( CASE WHEN a.atttypid = 'pg_catalog.name'::regtype THEN 1 ELSE 0 END ) > 0 AS is_na FROM pg_attribute AS a JOIN ( SELECT nspname, tbl.relname AS tblname, idx.relname AS idxname, idx.reltuples, idx.relpages, idx.relam, indrelid, indexrelid, indkey::smallint[] AS attnum, coalesce(substring( array_to_string(idx.reloptions, ' ') from 'fillfactor=([0-9]+)')::smallint, 90) AS fillfactor FROM pg_index JOIN pg_class idx ON idx.oid=pg_index.indexrelid JOIN pg_class tbl ON tbl.oid=pg_index.indrelid JOIN pg_namespace ON pg_namespace.oid = idx.relnamespace WHERE pg_index.indisvalid AND tbl.relkind = 'r' AND idx.relpages > 0 ) AS i ON a.attrelid = i.indexrelid JOIN pg_stats AS s ON s.schemaname = i.nspname AND ((s.tablename = i.tblname AND s.attname = pg_catalog.pg_get_indexdef(a.attrelid, a.attnum, TRUE)) -- stats from tbl OR (s.tablename = i.idxname AND s.attname = a.attname)) -- stats from functional cols JOIN pg_type AS t ON a.atttypid = t.oid WHERE a.attnum > 0 GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9 ) AS s1 ) AS s2 JOIN pg_am am ON s2.relam = am.oid WHERE am.amname = 'btree' ) AS sub -- WHERE NOT is_na ORDER BY 2,3,4;

Finden Sie Tabellen, die für die automatische Vakuumierung berechtigt sind

Führen Sie die folgende Abfrage aus, um Tabellen zu finden, die für die automatische Vakuumierung berechtigt sind.

--This query shows tables that need vacuuming and are eligible candidates. --The following query lists all tables that are due to be processed by autovacuum. -- During normal operation, this query should return very little. WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM pg_settings WHERE name = 'autovacuum_vacuum_threshold') , vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM pg_settings WHERE name = 'autovacuum_vacuum_scale_factor') , fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age') , sto AS (SELECT opt_oid, split_part(setting, '=', 1) as param, split_part(setting, '=', 2) as value FROM (SELECT oid opt_oid, unnest(reloptions) setting FROM pg_class) opt) SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation , pg_size_pretty(pg_table_size(c.oid)) as table_size , age(relfrozenxid) as xid_age , coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age , (coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples) as autovacuum_vacuum_tuples , n_dead_tup as dead_tuples FROM pg_class c JOIN pg_namespace ns ON ns.oid = c.relnamespace JOIN pg_stat_all_tables stat ON stat.relid = c.oid JOIN vbt on (1=1) JOIN vsf ON (1=1) JOIN fma on (1=1) LEFT JOIN sto cvbt ON cvbt.param = 'autovacuum_vacuum_threshold' AND c.oid = cvbt.opt_oid LEFT JOIN sto cvsf ON cvsf.param = 'autovacuum_vacuum_scale_factor' AND c.oid = cvsf.opt_oid LEFT JOIN sto cfma ON cfma.param = 'autovacuum_freeze_max_age' AND c.oid = cfma.opt_oid WHERE c.relkind = 'r' AND nspname <> 'pg_catalog' AND ( age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float) or coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples <= n_dead_tup -- or 1 = 1 ) ORDER BY age(relfrozenxid) DESC;

Reagieren Sie auf eine hohe Anzahl von Verbindungen

Wenn Sie Amazon überwachen CloudWatch, stellen Sie möglicherweise fest, dass die DatabaseConnections Metrik Spitzen aufweist. Dieser Anstieg deutet auf eine erhöhte Anzahl von Verbindungen zu Ihrer Datenbank hin. Wir empfehlen folgende Vorgehensweise:

  • Beschränken Sie die Anzahl der Verbindungen, die die Anwendung mit jeder Instance öffnen kann. Wenn Ihre Anwendung über eine eingebettete Verbindungspool-Funktion verfügt, legen Sie eine angemessene Anzahl von Verbindungen fest. Basieren Sie die Zahl darauf, was die vCPUs in Ihrer Instance effektiv parallelisieren können.

    Wenn Ihre Anwendung keine Verbindungspool-Funktion verwendet, sollten Sie den Amazon RDS Proxy oder eine Alternative in Betracht ziehen. Mit diesem Ansatz können Ihre Anwendung mehrere Verbindungen mit dem Load Balancer öffnen. Der Balancer kann dann eine begrenzte Anzahl von Verbindungen mit der Datenbank öffnen. Da weniger Verbindungen parallel laufen, führt Ihre DB-Instance weniger Kontextwechsel im Kernel durch. Abfragen sollten schneller voranschreiten und zu weniger Warteereignissen führen. Weitere Informationen finden Sie unter Verwenden von Amazon RDS Proxy.

  • Nutzen Sie nach Möglichkeit die Lesereplikate für RDS für PostgreSQL. Wenn Ihre Anwendung eine schreibgeschützten Operation ausführt, senden Sie diese Anfragen an das bzw. die Lesereplikate. Mit dieser Methode wird der I/O-Druck auf den primären (Writer-)Knoten) reduziert.

  • Ziehen Sie, Ihre DB-Instance zu skalieren. Eine Instance-Klasse mit höherer Kapazität bietet mehr Speicher, was RDS für PostgreSQL einen größeren freigegebenen Pufferpool zum Speichern von Seiten gibt. Die größere Größe gibt der DB-Instance auch mehr vCPUs für die Handhabung von Verbindungen. Mehr vCPUs sind besonders hilfreich, wenn die Vorgänge, die IO:DataFileRead-Warteereignisse generieren, Schreibvorgänge sind.