PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Szybkość obcinania Postgresql

Ostatnio pojawiło się to kilka razy, zarówno na listach dyskusyjnych SO, jak i na listach dyskusyjnych PostgreSQL.

TL;DR za ostatnie dwa punkty:

(a) Większe shared_buffers mogą być przyczyną wolniejszego działania funkcji TRUNCATE na serwerze CI. Inna konfiguracja fsync lub użycie nośników rotacyjnych zamiast dysków SSD może również być wadą.

(b) TRUNCATE ma stały koszt, ale niekoniecznie wolniej niż DELETE , a ponadto wykonuje więcej pracy. Zobacz szczegółowe wyjaśnienie poniżej.

AKTUALIZACJA: Z tego posta wywiązała się ważna dyskusja na temat wydajności pgsql. Zobacz ten wątek.

AKTUALIZACJA 2: Do wersji 9.2beta3 dodano ulepszenia, które powinny w tym pomóc, zobacz ten post.

Szczegółowe wyjaśnienie TRUNCATE vs DELETE FROM :

Chociaż nie jestem ekspertem w tym temacie, rozumiem, że TRUNCATE ma prawie stały koszt na tabelę, podczas gdy DELETE wynosi co najmniej O(n) dla n wierszy; gorzej, jeśli istnieją jakiekolwiek klucze obce odwołujące się do usuwanej tabeli.

Zawsze zakładałem, że stały koszt TRUNCATE był niższy niż koszt DELETE na prawie pustym stole, ale to wcale nie jest prawda.

TRUNCATE table; robi więcej niż DELETE FROM table;

Stan bazy danych po TRUNCATE table jest prawie taki sam, jak gdybyś zamiast tego uruchomił:

  • DELETE FROM table;
  • VACCUUM (FULL, ANALYZE) table; (tylko 9.0+, patrz przypis)

... choć oczywiście TRUNCATE w rzeczywistości nie osiąga swoich efektów za pomocą DELETE i VACUUM .

Chodzi o to, że DELETE i TRUNCATE rób różne rzeczy, więc nie porównujesz tylko dwóch poleceń z identycznymi wynikami.

Tabela DELETE FROM table; pozwala na pozostawanie martwych wierszy i rozrostu, umożliwia indeksom przenoszenie martwych wpisów, nie aktualizuje statystyk tabeli używanych przez planer zapytań itp.

TRUNCATE daje zupełnie nową tabelę i indeksy tak, jakby były po prostu CREATE wyd. To tak, jakbyś usunął wszystkie rekordy, ponownie zindeksował tabelę i wykonał VACUUM FULL .

Jeśli nie dbasz o to, czy w tabeli zostało resztki, ponieważ masz zamiar wypełnić ją ponownie, może być lepiej, gdy użyjesz DELETE FROM table; .

Ponieważ nie używasz VACUUM przekonasz się, że martwe wiersze i wpisy indeksu gromadzą się jako rozdęcie, które należy przeskanować, a następnie zignorować; to spowalnia wszystkie zapytania. Jeśli twoje testy w rzeczywistości nie tworzą i nie usuwają tak wielu danych, których możesz nie zauważyć lub nie obchodzić, i zawsze możesz wykonać VACUUM lub dwie w połowie testu, jeśli to zrobisz. Lepiej, niech agresywne ustawienia automatycznego odkurzania zapewnią, że autoodkurzacz zrobi to za Ciebie w tle.

Nadal możesz TRUNCATE wszystkie Twoje stoły po całości zestaw testowy uruchamia się, aby upewnić się, że w wielu uruchomieniach nie narastają żadne efekty. W wersji 9.0 i nowszych VACUUM (FULL, ANALYZE) table; globalnie na stole jest co najmniej tak samo dobre, jeśli nie lepsze, i jest o wiele łatwiejsze.

IIRC Pg ma kilka optymalizacji, co oznacza, że ​​może zauważyć, że Twoja transakcja jest jedyną, która widzi tabelę i od razu oznacza bloki jako wolne. W testach, gdy chciałem stworzyć wzdęcie, musiałem mieć więcej niż jedno jednoczesne połączenie, aby to zrobić. Nie polegałbym jednak na tym.

DELETE FROM table; jest bardzo tani dla małych stołów bez referencji f/k

Aby DELETE wszystkie rekordy z tabeli bez odniesień do klucza obcego, wszystkie Pg muszą wykonać sekwencyjne skanowanie tabeli i ustawić xmax napotkanych krotek. Jest to bardzo tania operacja - w zasadzie odczyt liniowy i zapis półliniowy. AFAIK nie musi dotykać indeksów; nadal wskazują martwe krotki, dopóki nie zostaną oczyszczone przez późniejszą VACUUM oznacza to również bloki w tabeli zawierające tylko martwe krotki jako wolne.

DELETE drożeje tylko wtedy, gdy jest dużo rekordów, jeśli istnieje wiele odwołań do kluczy obcych, które należy sprawdzić, lub jeśli policzysz kolejną tabelę VACUUM (FULL, ANALYZE) table; potrzebne do dopasowania TRUNCATE efekty w ramach kosztu DELETE .

W moich testach tutaj, tabela DELETE FROM table; był zazwyczaj 4x szybszy niż TRUNCATE przy 0.5ms vs 2ms. To jest testowa baza danych na dysku SSD, działająca z fsync=off ponieważ nie obchodzi mnie, czy stracę wszystkie te dane. Oczywiście DELETE FROM table; nie wykonuje tej samej pracy, a jeśli pójdę z tabelą VACUUM (FULL, ANALYZE) table; to znacznie droższe 21 ms, więc DELETE jest wygrana tylko wtedy, gdy właściwie nie potrzebuję nieskazitelnego stołu.

TRUNCATE table; wykonuje o wiele więcej prac i sprzątania o stałych kosztach niż DELETE

Natomiast TRUNCATE musi wykonać dużo pracy. Musi alokować nowe pliki dla tabeli, jej tabelę TOAST, jeśli taka istnieje, oraz każdy indeks, jaki ma ta tabela. Nagłówki muszą być zapisane w tych plikach, a katalogi systemowe również mogą wymagać aktualizacji (nie jestem pewien w tym punkcie, nie sprawdzałem). Następnie musi zastąpić stare pliki nowymi lub usunąć stare i upewnić się, że system plików dogonił zmiany za pomocą operacji synchronizacji — fsync() lub podobnej — która zwykle opróżnia wszystkie bufory na dysk . Nie jestem pewien, czy synchronizacja jest pomijana, jeśli korzystasz z opcji (zjadanie danych) fsync=off .

Niedawno dowiedziałem się, że TRUNCATE musi także opróżnić wszystkie bufory PostgreSQL związane ze starą tabelą. Może to zająć nietrywialną ilość czasu z ogromnymi shared_buffers . Podejrzewam, że właśnie dlatego działa wolniej na twoim serwerze CI.

Saldo

W każdym razie widać, że TRUNCATE tabeli, która ma powiązaną tabelę TOAST (większość tak) i kilka indeksów może zająć kilka chwil. Niedługo, ale dłużej niż DELETE z prawie pustego stołu.

W związku z tym może być lepiej, jeśli zrobisz DELETE FROM table; .

--

Uwaga:w bazach danych starszych niż 9.0, CLUSTER table_id_seq ON table; ANALYZE table; lub VACUUM FULL ANALYZE table; REINDEX table; byłby bliższym odpowiednikiem TRUNCATE . VACUUM FULL impl zmieniono na znacznie lepszą w wersji 9.0.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. uWSGI, Flask, sqlalchemy i postgres:błąd SSL:odszyfrowanie nie powiodło się lub zły rekord mac

  2. Ustaw na stałe ścieżkę schematu Postgresql

  3. Entity Framework 6 z Npgsql

  4. W obronie sar (i jak to skonfigurować)

  5. PostgreSQL działa wolno na dużym stole z tablicami i mnóstwem aktualizacji