sql >> Databáze >  >> RDS >> PostgreSQL

Rychlost zkrácení Postgresql

V poslední době se to několikrát objevilo, a to jak na SO, tak na e-mailových konferencích PostgreSQL.

TL;DR pro vaše poslední dva body:

(a) Větší sdílené vyrovnávací paměti mohou být důvodem, proč je TRUNCATE na serveru CI pomalejší. Na vině může být také odlišná konfigurace fsync nebo použití rotačních médií místo SSD.

(b) TRUNCATE má pevnou cenu, ale ne nutně pomalejší než DELETE a navíc to dá víc práce. Viz podrobné vysvětlení, které následuje.

AKTUALIZACE: Z tohoto příspěvku vznikla významná diskuse o výkonu pgsql. Viz toto vlákno.

AKTUALIZACE 2: Do 9.2beta3 byla přidána vylepšení, která by s tím měla pomoci, viz tento příspěvek.

Podrobné vysvětlení TRUNCATE vs DELETE FROM :

I když nejsem odborník na toto téma, chápu to tak, že TRUNCATE má téměř fixní náklady na tabulku, zatímco DELETE je alespoň O(n) pro n řádků; horší, pokud existují nějaké cizí klíče odkazující na odstraňovanou tabulku.

Vždy jsem předpokládal, že fixní náklady na TRUNCATE byla nižší než cena DELETE na téměř prázdném stole, ale to vůbec není pravda.

TRUNCATE table; dělá více než DELETE FROM table;

Stav databáze po TRUNCATE table je v podstatě stejné, jako kdybyste místo toho spustili:

  • DELETE FROM table;
  • VACCUUM (FULL, ANALYZE) table; (pouze 9.0+, viz poznámka pod čarou)

... i když samozřejmě TRUNCATE ve skutečnosti nedosahuje svých účinků pomocí příkazu DELETE a VACUUM .

Jde o to, že DELETE a TRUNCATE dělat různé věci, takže neporovnáváte jen dva příkazy se stejnými výsledky.

A DELETE FROM table; umožňuje zachovat mrtvé řádky a nadýmání, umožňuje indexům přenášet mrtvé položky, neaktualizuje statistiky tabulky používané plánovačem dotazů atd.

A TRUNCATE vám dává úplně novou tabulku a indexy, jako by byly jen CREATE vyd. Jako byste smazali všechny záznamy, přeindexovali tabulku a provedli VACUUM FULL .

Pokud vám nezáleží na tom, jestli v tabulce zbylo nahrubo, protože se chystáte ji znovu naplnit, možná bude lepší použít DELETE FROM table; .

Protože nepoužíváte VACUUM zjistíte, že mrtvé řádky a položky rejstříku se hromadí jako nadýmání, které musí být naskenováno a poté ignorováno; tím se zpomalí všechny vaše dotazy. Pokud vaše testy ve skutečnosti nevytvářejí a neodstraňují tolik dat, nemusíte si toho všimnout nebo vás to zajímat a vždy můžete provést VACUUM nebo dva během zkušebního provozu, pokud ano. Raději nechte agresivní nastavení autovakua zajistit, že to autovakuum udělá za vás na pozadí.

Stále můžete TRUNCATE všechny vaše stoly po celku běží testovací sada, aby se zajistilo, že se během mnoha běhů nevytvoří žádné efekty. Na 9.0 a novějších VACUUM (FULL, ANALYZE) table; globálně na stole je přinejmenším stejně dobré, ne-li lepší, a je to mnohem jednodušší.

IIRC Pg má několik optimalizací, což znamená, že si může všimnout, že vaše transakce je jediná, která vidí tabulku, a okamžitě označit bloky jako volné. Při testování, když jsem chtěl vytvořit nadýmání, musel jsem mít více než jedno souběžné připojení, abych to udělal. Na to bych ale nespoléhal.

DELETE FROM table; je velmi levná pro malé stoly bez f/k refů

Chcete-li DELETE všechny záznamy z tabulky bez odkazů na cizí klíč, všechny Pg musí provést sekvenční skenování tabulky a nastavit xmax z nalezených n-tic. Jedná se o velmi levnou operaci - v podstatě lineární čtení a semilineární zápis. AFAIK se nemusí dotýkat indexů; nadále ukazují na mrtvé n-tice, dokud je nevyčistí pozdější VACUUM to také označí bloky v tabulce obsahující pouze mrtvé n-tice jako volné.

DELETE zdraží pouze v případě, že jich je spousta záznamů, pokud existuje mnoho odkazů na cizí klíče, které je třeba zkontrolovat, nebo pokud spočítáte následující tabulku VACUUM (FULL, ANALYZE) table; potřeba, aby odpovídala TRUNCATE efekty v rámci nákladů na váš DELETE .

V mých testech zde DELETE FROM table; byl obvykle 4x rychlejší než TRUNCATE při 0,5 ms oproti 2 ms. Toto je testovací databáze na SSD, běžící s fsync=off protože je mi jedno, jestli o všechna tato data přijdu. Samozřejmě DELETE FROM table; nedělá stejnou práci, a pokud budu pokračovat s tabulkou VACUUM (FULL, ANALYZE) table; je to mnohem dražší 21 ms, takže DELETE je výhra pouze v případě, že stůl ve skutečnosti nepotřebuji nedotčený.

TRUNCATE table; dělá mnohem více práce s pevnými náklady a úklidu než DELETE

Naproti tomu TRUNCATE musí udělat hodně práce. Musí alokovat nové soubory pro tabulku, její tabulku TOAST, pokud existuje, a každý index, který tabulka má. Do těchto souborů musí být zapsána záhlaví a systémové katalogy mohou vyžadovat aktualizaci (v tomto bodě si nejsem jistý, nekontrolováno). Poté musí nahradit staré soubory novými nebo odstranit staré a musí zajistit, aby souborový systém zachytil změny pomocí synchronizační operace - fsync() nebo podobně - která obvykle vyprázdní všechny vyrovnávací paměti na disk. . Nejsem si jistý, zda je synchronizace přeskočena, pokud používáte možnost (požírání dat) fsync=off .

Nedávno jsem se dozvěděl, že TRUNCATE musí také vyprázdnit všechny buffery PostgreSQL související se starou tabulkou. To může s obrovskými shared_buffers zabrat netriviální množství času . Mám podezření, že to je důvod, proč je na vašem CI serveru pomalejší.

Zůstatek

Každopádně můžete vidět, že TRUNCATE tabulky, která má přidruženou tabulku TOAST (většina má) a několik indexů, může chvíli trvat. Ne dlouhé, ale delší než DELETE z téměř prázdného stolu.

V důsledku toho může být lepší udělat DELETE FROM table; .

--

Poznámka:na databázích před verzí 9.0 CLUSTER table_id_seq ON table; ANALYZE table; nebo tabulka VACUUM FULL ANALYZE table; REINDEX table; by byl bližší ekvivalent TRUNCATE . VACUUM FULL impl se v 9.0 změnil na mnohem lepší.



  1. Chyba příkazu Postgresql COPY poskytující oprávnění byla odepřena

  2. Co znamená symbol SQL Select || znamenat?

  3. Zkrácení všech tabulek v databázi Postgres

  4. Použití uložených procedur SQL Server z Pythonu (pyodbc)