it-swarm-eu.dev

Nejúčinnější způsob hromadného mazání řádků z postgresu

Zajímalo by mě, jaký nejefektivnější způsob by bylo odstranění velkého počtu řádků z PostgreSQL, tento proces by byl součástí opakujícího se úkolu hromadně importovat data (delta vkládání + mazání) do tabulky. Mohly by být odstraněny tisíce, případně miliony řádků.

Mám soubor primárních klíčů, jeden na řádek. Dvě možnosti, o nichž jsem přemýšlel, byly v souladu s níže uvedenými pokyny, ale nevím/nerozumím dost o vnitřních znalostech PostgreSQL, abych mohl učinit informované rozhodnutí, které by bylo nejlepší.

  • Spusťte dotaz DELETE pro každý řádek v souboru pomocí jednoduchého WHERE na primárním klíči (nebo seskupte mazání v dávkách n pomocí IN() doložka)
  • Importujte primární klíče do dočasné tabulky pomocí příkazu COPY a poté smažte z hlavní tabulky pomocí spojení

Jakékoli návrhy budou velmi oceněny!

25
tarnfeld

Vaše druhá možnost je mnohem čistší a bude fungovat dostatečně dobře, aby to stálo za to. Vaše alternativa je sestavení gigantických dotazů, které bude docela bolest plánovat a provádět. Obecně bude lepší, když necháte PostgreSQL dělat tu práci. Obecně jsem našel aktualizace na desítkách tisíc řádků způsobem, který popisujete, aby vykonával adekvátně, ale je tu jedna důležitá věc, kterým se musíte vyhnout.

Způsob, jak to udělat, je použít výběr a připojení ve vašem odstranit.

DELETE FROM foo WHERE id IN (select id from rows_to_delete);

S velkou tabulkou byste za žádných okolností neměli takto:

DELETE FROM foo WHERE id NOT IN (select id from rows_to_keep);

Obvykle to způsobí vnořenou antijoinovou smyčku, která způsobí, že výkon bude poněkud problematický. Pokud nakonec budete muset jít touto cestou, udělejte to místo toho:

DELETE FROM foo 
WHERE id IN (select id from foo f 
          LEFT JOIN rows_to_keep d on f.id = d.id
              WHERE d.id IS NULL);

PostgreSQL je obvykle docela dobrý způsob, jak se vyhnout špatným plánům, ale stále existují případy, které se týkají vnějších spojení, což může udělat velký rozdíl mezi dobrými a špatnými plány.

Toto je putování o něco dál, ale myslím, že stojí za zmínku, protože je snadné přejít z IN na NOT IN a sledovat výkonnostní nádrž dotazů.

26
Chris Travers

Na tuto otázku jsem narazil, protože jsem měl podobný problém. Vyčisťuji databázi, která má 300 řádků + řádků, konečná databáze bude mít pouze asi 30% původních dat. Pokud čelíte podobnému scénáři, je ve skutečnosti jednodušší vložit do nové tabulky a reindexovat namísto odstranění.

Udělej něco jako

CREATE temp_foo as SELECT * FROM foo WHERE 1=2;
INSERT INTO temp_foo (SELECT * FROM foo where foo.id IN (SELECT bar.id FROM BAR);

Se správným indexováním na foo a baru se můžete vyhnout Seq skenům.

Potom byste museli tabulku znovu indexovat a přejmenovat.

2
Niro