web-dev-qa-db-fra.com

PostgreSQL: Les données binaires en streaming à un champ ByTea sont très lentes

J'essaie de diffuser des données binaires dans un champ bytea. Le processus est assez simple:

loop until the end of the incoming stream
  UPDATE myTable SET data = data || $chunk WHERE id = myId
  • $chunk Est une liaison pour le flux de courant actuel
  • La ligne (myId) existe déjà avec des données NULL
  • chaque morceau est d'environ 64k
  • les données finales sont d'environ 4 Mo

Tout fonctionne correctement s'attendre à ce que les données de concaténation deviennent de plus en plus lentes car les morceaux sont stockés.

Depuis que j'ai besoin de garder mon SQL assez portable, je ne peux pas utiliser "objets de grande grasse postgresql"

Est-il possible d'optimiser ce processus?

  • peut-être en pré-alloué avec des données vides, puis utilisez overlay() pour placer chaque morceau?
1
Franck Freiburger

Mise à jour d'une ligne dans un modèle multiversion Comme Postgres signifie créer une deuxième copie de cette ligne avec le nouveau contenu. Physiquement, il n'y a pas de mise à jour sur place: la mise à jour est similaire à Supprimer + Insérer le nouveau contenu.

Donc, dans la boucle ci-dessus, le premier morceau, au lieu d'être écrit une fois, est écrit N fois, le deuxième morceau est écrit N-1 fois, le troisième N-2 fois et ainsi de suite.

Pour que cela aggrave, toutes ces écrivies doivent également aller dans les fichiers WAL pour la journalisation et toutes les versions intermédiaires des lignes devront être ramassées par le processus d'autovachage pour être éventuellement mis au rebut.

En supposant que ces morceaux ne puissent être assemblés sur le client et doivent être diffusés, cela pourrait aider à faire quelque chose comme ceci:

CREATE TEMPORARY sequence s;
CREATE TEMPORARY TABLE buffer(seq int default nextval('s'), chunk bytea);

-- buffer in temporary storage
LOOP 
   INSERT INTO buffer(chunk) VALUES ($chunk)
END LOOP

-- assemble in final storage
INSERT INTO permanent_table(data)
   SELECT string_agg(chunk,''::bytea order by seq) FROM buffer;

TRUNCATE (or DROP) TABLE buffer;

Au moins, les morceaux ne seront écrits que deux fois (une fois dans le stockage tampon et une fois en stockage durable final), et une seule fois dans le journal, comme la table temporaire ne sera pas connectée à Wal.

1
Daniel Vérité