Batch-Lesevorgänge brauchen einen Ergebnisvertrag

Eine Schleife von Primärschlüssel-Abfragen durch eine einzelne ANY-Abfrage zu ersetzen, entfernt Roundtrips. Dabei kann sich aber die Form der Antwort ändern. Ein Aufrufer könnte [42, 7, 42, NULL, -1] anfordern und fünf Ergebnispositionen erwarten. SQL-Mengen-Semantik verspricht diese Ausrichtung nicht.

Hinweis vom 04.10.2026: Die SQL-Zeilencache-API local_cache.mget(regclass, anyarray) aus 2.x wurde in 3.0.0 entfernt; verwenden Sie RESP MGET für aktuelle Ganzzeilen-Lesevorgänge.

Eine Zeilenmenge ist keine Liste von Antworten

Mit WHERE id = ANY($1::bigint[]) trifft eine doppelte ID normalerweise nur einmal auf ihre Tabellenzeile. Eine fehlende ID liefert keine Zeile. Eine Eingabe NULL trifft keinen nicht-nullbaren Primärschlüssel, und die Ausgabe hat keine garantierte Eingabereihenfolge. ORDER BY id sortiert nach Schlüssel; die angeforderten Positionen werden trotzdem nicht reproduziert.

Wenn Verbraucher eine Menge benötigen, ist das in Ordnung. Wenn sie ein Ergebnis für jede Eingabe brauchen, machen Sie die Positionen zum Teil der Abfrage oder stellen Sie sie in der Anwendung wieder her.

Positionen in SQL explizit halten

Starten Sie die lokale Demo und führen Sie dies in ihrer psql-Sitzung aus:

WITH requested AS (
  SELECT key, position
  FROM unnest(ARRAY[42, 7, 42, NULL, -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;

Die Ordinalitätsspalte unterscheidet beide Vorkommen von 42. Der Left Join behält alle fünf Positionen einschließlich der Null-Eingabe und jedes fehlenden Schlüssels. Für einen fehlenden Schlüssel ist row SQL NULL. Übergeben Sie im Anwendungscode das Array als Parameter, statt IDs an SQL anzuhängen. Der Quellcode der Node.js-Hilfsfunktion zeigt die clientseitige Ausrichtung der Ergebnisse.

Die API für vollständige Zeilen vergleichen

Für vollständige Zeilen aus angehängten Tabellen verwenden Sie RESP MGET. Kodieren Sie jeden Primärschlüssel in einem Schlüssel der Form CRUD:..<table>::

RESP MGET gibt ein RESP2-Array in Anfrage-Reihenfolge zurück. Doppelte Schlüssel behalten ihre Position; für eine fehlende Zeile wird nil zurückgegeben. RESP-Schlüssel bezeichnen Primärschlüsselwerte und enthalten keine SQL-NULL-Position in einem Array. Wenn für jeden SQL-Eingabewert einschließlich NULL ein ausgerichtetes Ergebnis nötig ist, verwenden Sie den obigen SQL-Weg mit WITH ORDINALITY. Ein Befehl akzeptiert höchstens 1.024 Schlüssel, jede JSON-Zeile ist auf 65.536 Byte und die kodierte Antwort auf 66.560 Byte begrenzt. RESP MGET ersetzt keine Projektionen, Joins, Zeilensperren oder das Caching beliebiger Abfrageergebnisse.

REDISCLI_AUTH=DemoRespToken_0123456789abcdef0123456789 redis-cli -2 -p 56379 MGET 'CRUD:pglc_demo.public.items:{"id":42}' \
  'CRUD:pglc_demo.public.items:{"id":7}' \
  'CRUD:pglc_demo.public.items:{"id":42}' \
  'CRUD:pglc_demo.public.items:{"id":-1}'

Batches begrenzen und beobachtbar halten

Bei mehr als 1.024 Schlüsseln teilen Sie Anfragen explizit auf oder behalten Sie eine gewöhnliche SQL-Abfrage bei. Chunking über mehrere Anweisungen kann unterschiedliche READ COMMITTED-Snapshots sehen; wählen Sie die Transaktionssemantik bewusst. Größere Batches erhöhen außerdem Antwortgröße und Dekodierarbeit des Clients, daher beweist „weniger Abfragen“ allein keine schnellere Anfrage.

Für GraphQL muss eine DataLoader-Batch-Funktion eine Antwort pro Eingabeschlüssel in derselben Reihenfolge zurückgeben. Anfragebezogene Memoization und der gemeinsame Cache von PostgreSQL sind getrennte Ebenen; löschen Sie betroffene Loader-Einträge nach Mutationen. Siehe den vollständigen Batching-Leitfaden und vergleichen Sie Latenz, Payloads und Durchsatz mit dem Benchmark-Runner.