Batch-Abfragen von PostgreSQL per Primärschlüssel

Wenn Anwendungscode eine Abfrage pro ID sendet, können Netzwerk-Roundtrips und Abfrage-Overhead einen kleinen Lesevorgang dominieren. Probieren Sie zuerst eine parametrisierte Anweisung:

SELECT id, value, revision
FROM public.items
WHERE id = ANY($1::bigint[]);

Übergeben Sie die IDs als Array-Parameter. Halten Sie Tabelle und Spalten in der Anweisung fest; bauen Sie kein SQL aus ID-Strings. PostgreSQL wertet ANY durch Vergleich des linken Ausdrucks mit Array-Elementen aus, wie in der Dokumentation zu Zeilen- und Array-Vergleichen beschrieben.

Ergebnisvertrag kennen

Die obige Abfrage gibt eine Menge zurück. Sie verspricht weder die Eingabereihenfolge, noch trifft eine doppelte ID normalerweise mehr als einmal auf dieselbe Tabellenzeile. Fehlende IDs erzeugen keine Zeile. Eine Eingabe NULL trifft keinen nicht-nullbaren Primärschlüssel; ein Null-Array oder Null-Elemente folgen außerdem PostgreSQLs dreiwertiger ANY-Logik. Ein leeres Array gibt keine Zeilen zurück.

Wenn der Aufrufer für jede angeforderte Position ein Ergebnis benötigt, bewahren Sie die Positionen explizit:

WITH requested AS (
  SELECT key, position
  FROM unnest($1::bigint[]) WITH ORDINALITY AS input(key, position)
)
SELECT requested.position,
       requested.key,
       CASE WHEN items.id IS NULL THEN NULL
            ELSE row_to_json(items)::text END AS row
FROM requested
LEFT JOIN public.items AS items ON items.id = requested.key
ORDER BY requested.position;

WITH ORDINALITY erhält Duplikate und NULL-Positionen; der Left Join gibt für einen fehlenden Schlüssel eine Null-row zurück. Dies ist eine nützliche Baseline für einen Client, der eine explizite Ausrichtung benötigt. Siehe das node-postgres-Beispiel für die clientseitige Wiederherstellung des gleichen Vertrags.

Wann mget die richtige Alternative ist

Für vollständige Zeilen per Primärschlüssel bietet pg_local_cache eine explizite, begrenzte Batch-API:

SELECT local_cache.mget(
  'public.items'::regclass,
  $1::bigint[]
) AS rows;

Das zurückgegebene text[] bewahrt Eingabereihenfolge und Duplikate. Eingabe- NULL und fehlende Zeilen erzeugen ausgerichtete NULL-Elemente. Aufrufe akzeptieren höchstens 1.024 Schlüssel, und die Funktion kann den Cache gemäß Transaktions-, Snapshot-, Zuordnungs- und Zeilengrößenregeln umgehen oder verfehlen; sie fällt auf PostgreSQL zurück, statt den Ergebnisvertrag zu ändern. Sie gibt vollständige serialisierte Zeilen zurück. Verwenden Sie daher ANY oder die Ordinalitätsabfrage, wenn Sie eine Projektion, Joins, Filter jenseits des Schlüssels oder einen unbegrenzten Batch benötigen.

GraphQL, DataLoader und N+1-Lesevorgänge

DataLoader kombiniert einzelne Ladevorgänge zu einem Batch. Seine Batch-Funktion muss einen Wert pro Eingabeschlüssel in derselben Reihenfolge zurückgeben; die obige Wiederherstellung liefert diese Form auch für fehlende Zeilen.

DataLoaders Memoization pro Anfrage ist vom gemeinsamen Zeilen-Cache von PostgreSQL getrennt. Erstellen Sie Loader für jede Anfrage und löschen Sie betroffene Loader-Einträge nach Mutationen in dieser Anfrage. Die PostgreSQL-Invalidation kann Werte nicht löschen, die bereits in einem JavaScript-Loader gespeichert sind. Behalten Sie Autorisierungsprüfungen der Anwendung bei; pg_local_cache unterstützt keine RLS-Tabellen.

Führen Sie den Quickstart aus und vergleichen Sie anschließend beide Lesepfade in den Benchmarks. Die technische Referenz definiert die API; der Transaktionsleitfaden behandelt Schreibvorgänge.

Aktualisiert .