

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.

# Verwaltung von TOAST-OID-Konflikten in
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID"></a>

TOAST (The Oversized-Attribute Storage Technique) ist eine PostgreSQL-Funktion, die für die Verarbeitung großer Datenwerte entwickelt wurde, die die typische Datenbankblockgröße von 8 KB überschreiten. PostgreSQL erlaubt nicht, dass sich physische Zeilen über mehrere Blöcke erstrecken. Die Blockgröße dient als Obergrenze für die Zeilengröße. TOAST überwindet diese Einschränkung, indem große Feldwerte in kleinere Blöcke aufgeteilt werden. Es speichert sie separat in einer speziellen TOAST-Tabelle, die mit der Haupttabelle verknüpft ist. Weitere Informationen finden Sie in der Dokumentation zum [PostgreSQL TOAST-Speichermechanismus und](https://www.postgresql.org/docs/current/storage-toast.html) zur Implementierung.

**Topics**
+ [TOAST-Operationen verstehen](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.HowWorks)
+ [Identifizierung von Leistungsherausforderungen](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceChallenges)
+ [Empfehlungen](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Recommendations)
+ [Überwachen](#Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Monitoring)

## TOAST-Operationen verstehen
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.HowWorks"></a>

TOAST führt eine Komprimierung durch und speichert große Feldwerte außerhalb der Zeile. TOAST weist jedem Block übergroßer Daten, die in der TOAST-Tabelle gespeichert sind, eine eindeutige OID (Object Identifier) zu. Die Haupttabelle speichert die TOAST-Wert-ID und die Beziehungs-ID auf der Seite, um auf die entsprechende Zeile in der TOAST-Tabelle zu verweisen. Dadurch kann PostgreSQL diese TOAST-Chunks effizient lokalisieren und verwalten. Wenn die TOAST-Tabelle jedoch wächst, besteht die Gefahr, dass das System die verfügbaren OIDs Ressourcen ausschöpft, was sowohl zu Leistungseinbußen als auch zu potenziellen Ausfallzeiten aufgrund der OID-Erschöpfung führt.

### Objektkennungen in TOAST
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.ObjectIdentifiers"></a>

Ein Object Identifier (OID) ist ein systemweiter eindeutiger Identifier, der von PostgreSQL verwendet wird, um Datenbankobjekte wie Tabellen, Indizes und Funktionen zu referenzieren. Diese Identifikatoren spielen eine wichtige Rolle bei den internen Vorgängen von PostgreSQL und ermöglichen es der Datenbank, Objekte effizient zu lokalisieren und zu verwalten.

Für Tabellen mit Datensätzen, die für das Toasten in Frage kommen, weist PostgreSQL jedem übergroßen Datenblock, der in der zugehörigen TOAST-Tabelle gespeichert ist, eine eindeutige Identifizierung OIDs zu. Das System verknüpft jeden Chunk mit einem`chunk_id`, was PostgreSQL hilft, diese Chunks effizient in der TOAST-Tabelle zu organisieren und zu lokalisieren.

## Identifizierung von Leistungsherausforderungen
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceChallenges"></a>

Das OID-Management von PostgreSQL stützt sich auf einen globalen 32-Bit-Zähler, sodass es nach der Generierung von 4 Milliarden eindeutigen Werten einen Umbruch durchführt. Der Datenbank-Cluster teilt sich diesen Zähler, aber die OID-Zuweisung umfasst bei TOAST-Vorgängen zwei Schritte:
+ **Globaler Zähler für die Zuweisung** — Der globale Zähler weist dem gesamten Cluster eine neue OID zu.
+ **Lokale Suche nach Konflikten** — Die TOAST-Tabelle stellt sicher, dass die neue OID nicht mit der in der jeweiligen Tabelle OIDs bereits verwendeten OID in Konflikt steht.

Leistungseinbußen können auftreten, wenn:
+ Die TOAST-Tabelle weist eine hohe Fragmentierung oder eine hohe OID-Auslastung auf, was zu Verzögerungen bei der Zuweisung der OID führt.
+  OIDs In Umgebungen mit hoher Datenfluktuation oder großen Tabellen, in denen TOAST häufig verwendet wird, werden vom System häufig Zuweisungen vorgenommen und wiederverwendet.

Weitere Informationen finden Sie in der Dokumentation zur [PostgreSQL-TOAST-Tabellengröße und zur OID-Zuweisung](https://wiki.postgresql.org/wiki/TOAST#Total_table_size_limit):

Ein globaler Zähler generiert die Werte OIDs und schließt sie etwa alle 4 Milliarden ab, sodass das System von Zeit zu Zeit erneut einen bereits verwendeten Wert generiert. PostgreSQL erkennt das und versucht es erneut mit der nächsten OID. Ein langsames INSERT kann auftreten, wenn es eine sehr lange Reihe von verwendeten OID-Werten ohne Lücken in der TOAST-Tabelle gibt. Diese Probleme werden immer ausgeprägter, je größer der OID-Speicherplatz ist, was zu langsameren Einfügungen und Aktualisierungen führt.

### Identifizierung des Problems
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.IdentifyingProblem"></a>
+ Einfache `INSERT` Aussagen dauern auf inkonsistente und zufällige Weise deutlich länger als gewöhnlich.
+ Verzögerungen treten nur bei `INSERT` und bei `UPDATE` Anweisungen auf, die TOAST-Operationen beinhalten.
+ Die folgenden Protokolleinträge erscheinen in PostgreSQL-Protokollen, wenn das System Schwierigkeiten hat, verfügbare OIDs TOAST-Tabellen zu finden:

  ```
  LOG: still searching for an unused OID in relation "pg_toast_20815"
  DETAIL: OID candidates have been checked 1000000 times, but no unused OID has been found yet.
  ```
+ Performance Insights weist auf eine hohe Anzahl von durchschnittlichen aktiven Sitzungen (AAS) hin, die mit Ereignissen verknüpft sind `LWLock:buffer_io` und `LWLock:OidGenLock` warten.

  Sie können die folgende SQL-Abfrage ausführen, um lang andauernde INSERT-Transaktionen mit Warteereignissen zu identifizieren:

  ```
  SELECT
      datname AS database_name,
      usename AS database_user,
      pid,
      now() - pg_stat_activity.xact_start AS transaction_duration,
      concat(wait_event_type, ':', wait_event) AS wait_event,
      substr(query, 1, 30) AS TRANSACTION,
      state
  FROM
      pg_stat_activity
  WHERE (now() - pg_stat_activity.xact_start) > INTERVAL '60 seconds'
      AND state IN ('active', 'idle in transaction', 'idle in transaction (aborted)', 'fastpath function call', 'disabled')
      AND pid <> pg_backend_pid()
  AND lower(query) LIKE '%insert%'
  ORDER BY
      transaction_duration DESC;
  ```

  Beispiel für Abfrageergebnisse, die INSERT-Operationen mit längeren Wartezeiten anzeigen:

  ```
   database_name |  database_user  |  pid  | transaction_duration |     wait_event      |          transaction           | state
  ---------------+-----------------+-------+----------------------+---------------------+--------------------------------+--------
   postgres       | db_admin_user| 70965 | 00:10:19.484061      | LWLock:buffer_io    | INSERT INTO "products" (......... | active
   postgres       | db_admin_user| 69878 | 00:06:14.976037      | LWLock:buffer_io    | INSERT INTO "products" (......... | active
   postgres       | db_admin_user| 68937 | 00:05:13.942847      | :                   | INSERT INTO "products" (......... | active
  ```

### Das Problem isolieren
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.IsolatingProblem"></a>
+ **Test small insert — Fügt** einen Datensatz ein, der kleiner als der `toast_tuple_target` Schwellenwert ist. Denken Sie daran, dass die Komprimierung vor der TOAST-Speicherung angewendet wird. Wenn dies ohne Leistungsprobleme funktioniert, hängt das Problem mit TOAST-Vorgängen zusammen.
+ **Neue Tabelle testen** — Erstellen Sie eine neue Tabelle mit derselben Struktur und fügen Sie einen Datensatz ein, der größer als `toast_tuple_target` ist. Wenn das ohne Probleme funktioniert, ist das Problem auf die OID-Zuordnung der Originaltabelle beschränkt.

## Empfehlungen
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Recommendations"></a>

Die folgenden Lösungsansätze können dabei helfen, Probleme mit TOAST-OID-Konflikten zu lösen.
+ **Datenbereinigung und Archivierung** — Überprüfen und löschen Sie alle veralteten oder unnötigen Daten, um sie OIDs für die future Verwendung freizugeben, oder archivieren Sie sie. Erwägen Sie die folgenden Einschränkungen:
  + Eingeschränkte Skalierbarkeit, da eine future Bereinigung möglicherweise nicht immer möglich ist.
  + Möglicher lang andauernder VACUUM-Vorgang, um die resultierenden toten Tupel zu entfernen.
+ In **eine neue Tabelle schreiben** — Erstellen Sie eine neue Tabelle für future Einfügungen und verwenden Sie eine `UNION ALL` Ansicht, um alte und neue Daten für Abfragen zu kombinieren. In dieser Ansicht werden die kombinierten Daten aus alten und neuen Tabellen dargestellt, sodass Abfragen auf sie als eine einzige Tabelle zugreifen können. Erwägen Sie die folgenden Einschränkungen:
  + Aktualisierungen der alten Tabelle können immer noch zu einer Überlastung der OID führen.
+ **Partition oder Shard** — Partitionieren Sie die Tabellen- oder Shard-Daten, um die Skalierbarkeit und Leistung zu verbessern. Erwägen Sie die folgenden Einschränkungen:
  + Höhere Komplexität bei der Abfragelogik und Wartung, potenzielle Notwendigkeit von Anwendungsänderungen, um partitionierte Daten korrekt verarbeiten zu können.

## Überwachen
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.Monitoring"></a>

### Verwendung von Systemtabellen
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.SystemTables"></a>

Sie können die Systemtabellen von PostgreSQL verwenden, um das Wachstum der OID-Nutzung zu überwachen.

**Warnung**  
Je nach Anzahl der Einträge OIDs in der TOAST-Tabelle kann es einige Zeit dauern, bis der Vorgang abgeschlossen ist. Wir empfehlen, die Überwachung außerhalb der Geschäftszeiten einzuplanen, um die Auswirkungen zu minimieren.

Der folgende anonyme Block zählt die Anzahl der in jeder TOAST-Tabelle OIDs verwendeten Zeichen und zeigt die Informationen zur übergeordneten Tabelle an:

```
DO $$
DECLARE
    r record;
    o bigint;
    parent_table text;
    parent_schema text;
BEGIN
    SET LOCAL client_min_messages TO notice;
    FOR r IN
    SELECT
        c.oid,
        c.oid::regclass AS toast_table
    FROM
        pg_class c
    WHERE
        c.relkind = 't'
        AND c.relowner != 10 LOOP
            -- Fetch the number of distinct used OIDs (chunk IDs) from the TOAST table
            EXECUTE 'SELECT COUNT(DISTINCT chunk_id) FROM ' || r.toast_table INTO o;
            -- If there are used OIDs, find the associated parent table and its schema
            IF o <> 0 THEN
                SELECT
                    n.nspname,
                    c.relname INTO parent_schema,
                    parent_table
                FROM
                    pg_class c
                    JOIN pg_namespace n ON c.relnamespace = n.oid
                WHERE
                    c.reltoastrelid = r.oid;
                -- Raise a concise NOTICE message
                RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Number of used OIDs: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999');
            END IF;
        END LOOP;
END
$$;
```

Beispielausgabe mit OID-Nutzungsstatistiken nach TOAST-Tabelle:

```
NOTICE:  Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Number of used OIDs: 45,623,317
NOTICE:  Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Number of used OIDs: 10,000
NOTICE:  Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Number of used OIDs: 1,000,000
DO
```

Der folgende anonyme Block ruft die maximal zugewiesene OID für jede nicht leere TOAST-Tabelle ab:

```
DO $$
DECLARE
    r record;
    o bigint;
    parent_table text;
    parent_schema text;
BEGIN
    SET LOCAL client_min_messages TO notice;
    FOR r IN
    SELECT
        c.oid,
        c.oid::regclass AS toast_table
    FROM
        pg_class c
    WHERE
        c.relkind = 't'
        AND c.relowner != 10 LOOP
            -- Fetch the max(chunk_id) from the TOAST table
            EXECUTE 'SELECT max(chunk_id) FROM ' || r.toast_table INTO o;
            -- If there's at least one TOASTed chunk, find the associated parent table and its schema
            IF o IS NOT NULL THEN
                SELECT
                    n.nspname,
                    c.relname INTO parent_schema,
                    parent_table
                FROM
                    pg_class c
                    JOIN pg_namespace n ON c.relnamespace = n.oid
                WHERE
                    c.reltoastrelid = r.oid;
                -- Raise a concise NOTICE message
                RAISE NOTICE 'Parent schema: % | Parent table: % | Toast table: % | Max chunk_id: %', parent_schema, parent_table, r.toast_table, TO_CHAR(o, 'FM9,999,999,999,999');
            END IF;
        END LOOP;
END
$$;
```

Beispielausgabe, die den maximalen Teil für TOAST-Tabellen IDs anzeigt:

```
NOTICE:  Parent schema: public | Parent table: my_table | Toast table: pg_toast.pg_toast_16559 | Max chunk_id: 45,639,907
NOTICE:  Parent schema: public | Parent table: my_table1 | Toast table: pg_toast.pg_toast_45639925 | Max chunk_id: 45,649,929
NOTICE:  Parent schema: public | Parent table: my_table2 | Toast table: pg_toast.pg_toast_45649931 | Max chunk_id: 46,649,935
DO
```

### Verwendung von Performance-Insights
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.PerformanceInsights"></a>

Die Warteereignisse `LWLock:buffer_io` `LWLock:OidGenLock` werden in Performance Insights bei Vorgängen angezeigt, für die neue Objektkennungen () OIDs zugewiesen werden müssen. High Average Active Sessions (AAS) für diese Ereignisse deuten in der Regel auf Konflikte bei der OID-Zuweisung und der Ressourcenverwaltung hin. Dies ist besonders häufig in Umgebungen mit hoher Datenfluktuation, umfangreicher Datennutzung oder häufiger Objekterstellung der Fall.

#### LWLockDies ist besonders häufig in Umgebungen mit hoher Datenfluktuation, umfangreicher Datennutzung oder häufiger Objekterstellung der Fall. ----sep----:buffer\$1io
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.LWLockBufferIO"></a>

`LWLock:buffer_io`ist ein Wartungsereignis, das auftritt, wenn eine PostgreSQL-Sitzung auf den Abschluss von I/O Vorgängen in einem gemeinsam genutzten Puffer wartet. Dies passiert normalerweise, wenn die Datenbank Daten von der Festplatte in den Speicher liest oder geänderte Seiten vom Speicher auf die Festplatte schreibt. Das `BufferIO` Wait-Ereignis gewährleistet Konsistenz, indem es verhindert, dass mehrere Prozesse während laufender I/O Operationen auf denselben Puffer zugreifen oder ihn ändern. Ein häufiges Auftreten dieses Warteereignisses kann auf Festplattenengpässe oder übermäßige I/O Aktivität bei der Datenbank-Arbeitslast hinweisen.

Während TOAST-Vorgängen:
+ PostgreSQL weist OIDs große Objekte zu und stellt deren Einzigartigkeit sicher, indem es den Index der TOAST-Tabelle scannt.
+ Große TOAST-Indizes erfordern möglicherweise den Zugriff auf mehrere Seiten, um die Eindeutigkeit der OID zu überprüfen. Dies führt zu mehr Festplatten-E/A, insbesondere wenn der Pufferpool nicht alle erforderlichen Seiten zwischenspeichern kann.

Die Größe des Indexes wirkt sich direkt auf die Anzahl der Pufferseiten aus, auf die während dieser Operationen zugegriffen werden muss. Selbst wenn der Index nicht aufgebläht ist, kann seine bloße Größe die Puffer-I/O erhöhen, insbesondere in Umgebungen mit hoher Parallelität oder hoher Kundenabwanderung. [Weitere Informationen finden Sie unter: Anleitung zur Fehlerbehebung bei BufferiO-WarteereignissenLWLock.](https://docs.aws.amazon.com/AmazonRDS/latest/AuroraUserGuide/apg-waits.lwlockbufferio.html)

#### LWLock:OidGenLock
<a name="Appendix.PostgreSQL.CommonDBATasks.TOAST_OID.LWLockOidGenLock"></a>

`OidGenLock`ist ein Wartungsereignis, das auftritt, wenn eine PostgreSQL-Sitzung darauf wartet, einen neuen Objektbezeichner (OID) zuzuweisen. Diese Sperre stellt sicher, dass OIDs sie sequentiell und sicher generiert werden, sodass jeweils nur ein Prozess generiert OIDs werden kann.

Während TOAST-Vorgängen:
+ **OID-Zuweisung für Chunks in der TOAST-Tabelle** — PostgreSQL weist Chunks in TOAST-Tabellen OIDs zu, wenn große Datensätze verwaltet werden. Jede OID muss eindeutig sein, um Konflikte im Systemkatalog zu vermeiden.
+ **Hohe Parallelität** — Da der Zugriff auf den OID-Generator sequentiell erfolgt, kann es zu Konflikten kommen, wenn mehrere Sitzungen gleichzeitig Objekte erstellen OIDs, die dies erfordern. `OidGenLock` Dies erhöht die Wahrscheinlichkeit, dass Sitzungen auf den Abschluss der OID-Zuweisung warten.
+ **Abhängigkeit vom Systemkatalogzugriff** — Für die Zuweisung OIDs sind Aktualisierungen der gemeinsam genutzten Systemkatalogtabellen wie `pg_class` und `pg_type` erforderlich. Wenn diese Tabellen stark beansprucht werden (aufgrund häufiger DDL-Operationen), kann sich der Sperrkonflikt für erhöhen. `OidGenLock`
+ **Hohe Nachfrage nach OID-Zuweisungen** — TOAST-Arbeitslasten mit großen Datensätzen erfordern eine konstante OID-Zuweisung, was zu mehr Konflikten führt.

Zusätzliche Faktoren, die den OID-Konflikt erhöhen:
+ **Häufige Objekterstellung** — Workloads, bei denen häufig Objekte erstellt und gelöscht werden, wie z. B. temporäre Tabellen, verstärken den Konflikt auf dem globalen OID-Zähler.
+ **Globales Sperren von Leistungsindikatoren** — Auf den globalen OID-Zähler wird seriell zugegriffen, um die Eindeutigkeit sicherzustellen, wodurch in Umgebungen mit hoher Parallelität ein einziger Streitpunkt entsteht.