Zoptymalizuj PostgreSQL do szybkiego testowania

203

Przechodzę na PostgreSQL z SQLite dla typowej aplikacji Railsowej.

Problem polega na tym, że działające specyfikacje stały się wolne z PG.
Na SQLite zajęło ~ 34 sekund, na PG ~ 76 sekund, czyli ponad 2x wolniej .

Więc teraz chcę zastosować pewne techniki, aby dostosować wydajność specyfikacji do SQLite bez modyfikacji kodu (najlepiej po prostu ustawiając opcje połączenia, co prawdopodobnie nie jest możliwe).

Kilka oczywistych rzeczy z góry mojej głowy to:

  • Dysk RAM (dobrze byłoby zobaczyć dobrą konfigurację z RSpec na OSX)
  • Niezalogowane tabele (czy można je zastosować do całej bazy danych, aby nie zmieniać wszystkich skryptów?)

Jak zapewne zrozumiałeś, nie dbam o niezawodność i resztę (DB jest tutaj czymś wyjątkowym).
Muszę jak najlepiej wykorzystać PG i zrobić to tak szybko, jak to możliwe .

Najlepsza odpowiedź najlepiej opisałaby sztuczki związane z robieniem tego, ustawienie i wady tych sztuczek.

AKTUALIZACJA: fsync = off + full_page_writes = offtylko skrócił czas do ~ 65 sekund (~ -16 sekund). Dobry początek, ale daleko od celu 34.

UPDATE 2: I próbował dysku wykorzystanie pamięci RAM , ale wzrost wydajności był obrębie marginesu błędu. Nie wydaje się więc tego warte.

AKTUALIZACJA 3: * Znalazłem największe wąskie gardło, a teraz moje specyfikacje działają tak szybko, jak te SQLite.

Problem polegał na oczyszczeniu bazy danych, które spowodowało obcięcie . Najwyraźniej SQLite jest tam zbyt szybki.

Aby to naprawić, otwieram transakcję przed każdym testem i wycofuję ją na końcu.

Niektóre liczby dla ~ 700 testów.

  • Obcięcie: SQLite - 34s, PG - 76s.
  • Transakcja: SQLite - 17s, PG - 18s.

2x wzrost prędkości dla SQLite. 4x wzrost prędkości dla PG.

Dmytrii Nagirniak
źródło
2
Naprawdę wątpię, żebyś działał tak szybko jak SQLite. SQLite z jednym użytkownikiem jest niesamowicie szybki. Projekt SQLite jest bardzo szybki, z małą liczbą użytkowników i słabo skalowany; Projekt Pg dobrze się skaluje, ale nie jest tak szybki do prostej pracy z jednym użytkownikiem.
Craig Ringer
1
Zdaję sobie z tego sprawę, ale mam szczególny przypadek, dla którego mam nadzieję zoptymalizować PG (testy), więc jest tak szybki, jak to tylko możliwe. Nie przeszkadza mi, że jest tam trochę wolniej, ale 2.2x jest nieco zbyt wolny. Widzisz co mam na myśli?
Dmytrii Nagirniak
+1 Byłbym bardzo zainteresowany aktualizacjami w podejściu do dysku RAM, jeśli masz jakieś wyniki dotyczące tego.
tscho
@tscho Zdecydowanie tu opublikuję. Ale potrzebuję trochę czasu, ponieważ pracuję nad innymi rzeczami i „badam” rzeczy PG w „tle”.
Dmytrii Nagirniak
czy wstawianie danych jest Twoim problemem lub zapytanie ? Z twojego pytania nie wynika jasno.
a_horse_w_no_name

Odpowiedzi:

281

Po pierwsze, zawsze używaj najnowszej wersji PostgreSQL. Poprawki wydajności zawsze nadchodzą, więc prawdopodobnie tracisz czas, jeśli dostrajasz starą wersję. Na przykład PostgreSQL 9.2 znacząco poprawia szybkośćTRUNCATE i oczywiście dodaje skanowanie tylko do indeksu. Należy zawsze śledzić nawet niewielkie wydania; zobacz zasady dotyczące wersji .

Nie

Czy NIE umieścić tabel na ramdysku lub innego przedmiotu trwałego składowania .

W przypadku utraty obszaru tabel cała baza danych może zostać uszkodzona i utrudniona w użyciu bez znacznej pracy. Ma to bardzo małą zaletę w porównaniu do zwykłego używania UNLOGGEDtabel i posiadania dużej ilości pamięci RAM na pamięć podręczną.

Jeśli naprawdę chcesz systemu opartego na ramdysku, initdbto całkowicie nowy klaster na ramdysku, initdbwprowadzając nową instancję PostgreSQL na ramdysku, więc masz całkowicie jednorazową instancję PostgreSQL.

Konfiguracja serwera PostgreSQL

Podczas testowania możesz skonfigurować serwer pod kątem nietrwałej, ale szybszej pracy .

Jest to jedno z niewielu dopuszczalnych zastosowań fsync=offustawienia w PostgreSQL. To ustawienie w zasadzie mówi PostgreSQL, aby nie zawracał sobie głowy zamówionymi zapisami lub innymi nieprzyjemnymi kwestiami związanymi z ochroną integralności danych i zabezpieczeniem przed awariami, dając mu pozwolenie na całkowite zniszczenie danych w przypadku utraty zasilania lub awarii systemu operacyjnego.

Nie trzeba dodawać, że nigdy nie należy włączać fsync=offprodukcji, chyba że używasz PG jako tymczasowej bazy danych dla danych, które możesz ponownie wygenerować z innego miejsca. Jeśli i tylko jeśli chcesz wyłączyć fsync, możesz go również full_page_writeswyłączyć, ponieważ nie przynosi to już żadnego pożytku. Uważaj fsync=offi full_page_writesstosuj na poziomie klastra , aby wpływały one na wszystkie bazy danych w Twojej instancji PostgreSQL.

Do użytku produkcyjnego możesz użyć synchronous_commit=offi ustawić commit_delay, ponieważ uzyskasz wiele takich samych korzyści, jak fsync=offbez ogromnego ryzyka uszkodzenia danych. Jeśli włączysz zatwierdzanie asynchroniczne, masz małe okno utraty ostatnich danych - ale to wszystko.

Jeśli masz możliwość nieznacznej zmiany DDL, możesz także użyć UNLOGGEDtabel w Pg 9.1+, aby całkowicie uniknąć rejestrowania WAL i uzyskać rzeczywiste przyspieszenie kosztem usunięcia tabel w przypadku awarii serwera. Nie ma opcji konfiguracji, aby wszystkie tabele były niezalogowane, należy je ustawić podczas CREATE TABLE. Oprócz tego, że jest dobry do testowania, jest to przydatne, jeśli masz tabele pełne wygenerowanych lub nieistotnych danych w bazie danych, która w przeciwnym razie zawiera elementy, które musisz zachować bezpieczeństwo.

Sprawdź swoje dzienniki i sprawdź, czy otrzymujesz ostrzeżenia o zbyt wielu punktach kontrolnych. Jeśli tak, powinieneś zwiększyć swoje punkty kontrolne . Możesz także dostroić swój punkt kontrolny_wykonanie_przeprowadzania, aby wygładzić zapisy.

Dostosuj shared_buffersdo obciążenia. Jest to zależne od systemu operacyjnego, zależy od tego, co dzieje się na twoim komputerze i wymaga pewnych prób i błędów. Domyślne są bardzo konserwatywne. Może być konieczne zwiększenie maksymalnego limitu pamięci współużytkowanej przez system operacyjny, jeśli zwiększysz shared_buffersw PostgreSQL 9.2 i niższych; W wersji 9.3 i nowszych zmieniono sposób, w jaki korzystają z pamięci współdzielonej, aby tego uniknąć.

Jeśli używasz tylko kilku połączeń, które wykonują dużo pracy, zwiększ work_memje , aby dać im więcej pamięci RAM na różne rodzaje itp. Uważaj, że zbyt wysokie work_memustawienie może powodować problemy z brakiem pamięci, ponieważ nie jest to zależne od rodzaju na połączenie, więc jedno zapytanie może mieć wiele zagnieżdżonych rodzajów. Naprawdę musisz tylko zwiększyć, work_memjeśli widzisz sortowania przelewające się na dysk EXPLAINlub zalogowane z log_temp_filesustawieniem (zalecane), ale wyższa wartość może również pozwolić Pg wybrać inteligentniejsze plany.

Jak powiedział inny plakat tutaj, rozsądnie jest umieścić xlog i główne tabele / indeksy na osobnych dyskach twardych, jeśli to możliwe. Oddzielne partycje są dość bezcelowe, naprawdę chcesz osobnych dysków. Ta separacja przynosi znacznie mniejsze korzyści, jeśli używasz, fsync=offi prawie żadna, jeśli używasz UNLOGGEDtabel.

Na koniec dostosuj swoje zapytania. Upewnij się, że random_page_costi seq_page_costodzwierciedlają wydajność systemu, zapewnienia bezpieczeństwa effective_cache_sizejest prawidłowa, itd. Zastosowanie EXPLAIN (BUFFERS, ANALYZE)do zbadania indywidualnych planów kwerend i włącz auto_explainmoduł dotyczący zgłaszania wszystkich powolnych zapytań. Często można znacznie poprawić wydajność zapytań, po prostu tworząc odpowiedni indeks lub dostosowując parametry kosztów.

AFAIK nie ma możliwości ustawienia całej bazy danych lub klastra jako UNLOGGED. Byłoby interesujące móc to zrobić. Zastanów się nad pytaniem na liście mailingowej PostgreSQL.

Strojenie systemu operacyjnego hosta

Istnieje również możliwość dostrajania na poziomie systemu operacyjnego. Najważniejsze, co możesz zrobić, to przekonać system operacyjny, aby nie czyścił agresywnie zapisów na dysk, ponieważ tak naprawdę nie obchodzi Cię, kiedy / jeśli trafią na dysk.

W Linuksie można sterować tym z wirtualnego podsystemu pamięci „s dirty_*ustawień, takich jak dirty_writeback_centisecs.

Jedynym problemem związanym z dostrajaniem ustawień zapisu zwrotnego, które są zbyt luźne, jest to, że opróżnianie przez inny program może powodować opróżnianie wszystkich zgromadzonych buforów PostgreSQL, powodując duże przeciągnięcia, podczas gdy wszystko blokuje zapis. Możesz to złagodzić, uruchamiając PostgreSQL na innym systemie plików, ale niektóre zmiany mogą być na poziomie urządzenia lub całego hosta, a nie systemu plików, więc nie możesz na tym polegać.

To dostrajanie naprawdę wymaga zabawy z ustawieniami, aby zobaczyć, co działa najlepiej dla twojego obciążenia.

W nowszych jądrach możesz to zapewnić vm.zone_reclaim_mode jest ustawiony na zero, ponieważ może to powodować poważne problemy z wydajnością w systemach NUMA (większość systemów obecnie) z powodu interakcji z zarządzaniem PostgreSQL shared_buffers.

Dostosowywanie zapytań i obciążenia

Są to rzeczy, które wymagają zmian kodu; mogą ci nie odpowiadać. Niektóre rzeczy możesz zastosować.

Jeśli nie grupujesz pracy w większe transakcje, zacznij. Wiele małych transakcji jest drogich, więc powinieneś grupować rzeczy, gdy tylko jest to możliwe i praktyczne. Jeśli używasz zatwierdzenia asynchronicznego, jest to mniej ważne, ale nadal wysoce zalecane.

O ile to możliwe, używaj tabel tymczasowych. Nie generują one ruchu WAL, więc są znacznie szybsze w przypadku wstawek i aktualizacji. Czasami warto schować kilka danych do tabeli tymczasowej, manipulować nimi w dowolny sposób, a następnie INSERT INTO ... SELECT ...skopiować je do tabeli końcowej. Pamiętaj, że tabele tymczasowe są na sesję; jeśli twoja sesja się skończy lub stracisz połączenie, tabela tymczasowa zniknie i żadne inne połączenie nie będzie widzieć zawartości tabel tymczasowych.

Jeśli korzystasz z PostgreSQL 9.1 lub nowszego, możesz użyć UNLOGGEDtabel dla danych, które możesz stracić, np. Stanu sesji. Są one widoczne w różnych sesjach i zachowywane między połączeniami. Są one obcinane, jeśli serwer zostanie wyłączony nieczysto, więc nie można ich użyć do niczego, czego nie można odtworzyć, ale świetnie nadają się do pamięci podręcznych, zmaterializowanych widoków, tabel stanu itp.

Ogólnie nie DELETE FROM blah;. TRUNCATE TABLE blah;Zamiast tego użyj ; jest o wiele szybsze, gdy zrzucasz wszystkie wiersze w tabeli. TRUNCATEJeśli możesz, obetnij wiele tabel w jednym wywołaniu. Jest jednak zastrzeżenie, jeśli robisz wiele TRUNCATESmałych stolików w kółko; patrz: Postgresql Prędkość obcięcia

Jeśli nie masz indeksów na klucze obce, DELETEs obejmujących klucze podstawowe, do których odwołują się te klucze obce, będą strasznie wolne. Pamiętaj, aby utworzyć takie indeksy, jeśli kiedykolwiek będziesz tego oczekiwał na DELETEpodstawie tabel (y). Indeksy nie są wymagane dla TRUNCATE.

Nie twórz indeksów, których nie potrzebujesz. Każdy indeks ma koszt utrzymania. Spróbuj użyć minimalnego zestawu indeksów i pozwól skanom indeksów bitmapowych je połączyć, zamiast utrzymywać zbyt wiele ogromnych, drogich indeksów wielokolumnowych. Tam, gdzie wymagane są indeksy, spróbuj najpierw wypełnić tabelę, a następnie utwórz indeksy na końcu.

Sprzęt komputerowy

Posiadanie wystarczającej ilości pamięci RAM do przechowywania całej bazy danych to ogromna wygrana, jeśli możesz nią zarządzać.

Jeśli nie masz wystarczającej ilości pamięci RAM, tym szybciej możesz uzyskać więcej miejsca. Nawet tani dysk SSD ma ogromną różnicę w stosunku do wirującej rdzy. Nie ufaj taniej dyskom SSD do produkcji, często nie są odporne na awarie i mogą zjadać twoje dane.

Uczenie się

Książka Grega Smitha, PostgreSQL 9.0 High Performance pozostaje aktualna, mimo że odnosi się do nieco starszej wersji. Powinno to być przydatne odniesienie.

Dołącz do ogólnej listy mailingowej PostgreSQL i śledź ją.

Czytanie:

Craig Ringer
źródło
10
Mogę również polecić PostgreSQL 9.0 High Performance autorstwa @GregSmith, to naprawdę świetna lektura. Książka obejmuje każdy aspekt dostrajania wydajności, od układu dysku po dostrajanie zapytań i zapewnia bardzo dobre zrozumienie wewnętrznych elementów PG.
tscho
10
Nie wydałem aktualizacji książki PostgreSQL 9.1, jedynej wersji od czasu jej publikacji, ponieważ w wersji 9.1 nie było wystarczających zmian związanych z wydajnością, aby to uzasadnić.
Greg Smith
3
Świetny opis. Podobnie jak niewielka aktualizacja: „Może być konieczne zwiększenie maksymalnego limitu pamięci współdzielonej systemu operacyjnego, jeśli zwiększysz shared_buffers” nie jest już prawdą (dla większości użytkowników) w PostgreSQL 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Gunnlaugur Briem,
1
@brauliobo Moje testy często wykonują wiele tx przy wysokim TPS ... ponieważ próbuję symulować produkcję, w tym obciążenia o dużej współbieżności. Jeśli masz na myśli „testowanie liniowe z jednym połączeniem”, zgodziłbym się z tobą.
Craig Ringer
1
stackoverflow.com/questions/11419536/… DELETE może być szybsze niż TRUNCATE w przypadku tabel z kilkoma wierszami, co może mieć miejsce w testach.
Jonathan Crosmer,
9

Użyj innego układu dysku:

  • inny dysk dla $ PGDATA
  • inny dysk dla $ PGDATA / pg_xlog
  • inny dysk dla plików tem (na bazę danych $ PGDATA / base // pgsql_tmp) (patrz uwaga na temat work_mem)

poprawki w postgresql.conf:

  • shared_memory: 30% dostępnej pamięci RAM, ale nie więcej niż 6 do 8 GB. Wydaje się, że lepiej jest mieć mniej pamięci współdzielonej (2 GB - 4 GB) na potrzeby intensywnego zapisu
  • work_mem: głównie dla wybranych zapytań z sortowaniem / agregacjami. Jest to ustawienie połączenia i zapytanie może przydzielić tę wartość wiele razy. Jeśli dane nie mieszczą się, używany jest dysk (pgsql_tmp). Zaznacz „wyjaśnij analizę”, aby zobaczyć, ile pamięci potrzebujesz
  • fsync i synchronous_commit: Wartości domyślne są bezpieczne, ale jeśli tolerujesz utratę danych, możesz je wyłączyć
  • random_page_cost: jeśli masz dysk SSD lub szybką macierz RAID, możesz obniżyć go do 2,0 (RAID) lub nawet mniej (1.1) dla SSD
  • checkpoint_segments: możesz przejść wyżej 32 lub 64 i zmienić checkpoint_completion_target na 0.9. Niższa wartość umożliwia szybsze przywracanie po awarii
mys
źródło
4
Zauważ, że jeśli już korzystasz z fsync=off, umieszczenie pg_xlog na osobnym dysku już się nie poprawi.
intgr
Wartość 1,1 dla dysku SSD wydaje się bardzo niekwalifikowana. Przyznaję, że niektórzy profesjonaliści na ślepo to zalecili. Nawet dyski SSD są znacznie szybsze w przypadku odczytów sekwencyjnych niż odczytów losowych.
Acumenus,
@ABB Tak, ale masz także efekty buforowania bufora systemu operacyjnego w pracy. Wszystkie te parametry i tak są nieco falujące ...
Craig Ringer