PostgreSQL: Wymuś dane do pamięci

32

Czy istnieje systematyczny sposób, aby zmusić PostgreSQL do załadowania określonej tabeli do pamięci lub przynajmniej odczytania jej z dysku, aby system mógł ją buforować?

Adam Matan
źródło

Odpowiedzi:

25

Możesz być zainteresowany jednym z tematów list mailowych , na który odpowiada Tom Lane (główny programista):

[..] Ale moim zdaniem ludzie, którzy myślą, że są mądrzejsi niż algorytm buforowania LRU, zwykle się mylą. Jeśli stół jest bardzo intensywnie używany, pozostanie w pamięci w porządku. Jeśli zgodnie z algorytmem LRU nie jest wystarczająco mocno wykorzystywany do pozostawania w pamięci, być może przestrzeń pamięci naprawdę powinna zostać wydana na coś innego. [..]

Może Cię również zainteresować pytanie SO: https://stackoverflow.com/questions/486154/postgresql-temporary-tables, a może bardziej odpowiedni https://stackoverflow.com/questions/407006/need-to-load-the -whole-postgresql-database-into-the-ram

DrColossos
źródło
1
+1 Ten sam pomysł dotyczy również innych RDBMS.
gbn
25
Tak i nie. Blokujemy niektóre tabele Oracle w pamięci, ponieważ wiemy, że mogą nie być używane tak często, ale w sytuacji, w której są używane, opóźnienia będą zabójcze. DB powinien zawsze dawać ostatnie zdanie DBA (innym przykładem jest podpowiedź do optymalizatora zapytań).
Gajusz
35

Postgres 9.4 w końcu dodał rozszerzenie do wstępnego ładowania danych ze relacji do pamięci podręcznej systemu operacyjnego lub bufora bazy danych (do wyboru):

pg_prewarm

Pozwala to szybciej osiągnąć pełną wydajność operacyjną.

Uruchom raz w bazie danych (szczegółowe instrukcje tutaj ):

CREATE EXTENSION pg_prewarm;

Następnie łatwo jest wstępnie załadować dowolną relację. Podstawowy przykład:

SELECT pg_prewarm('my_tbl');

Znajduje pierwszą tabelę o nazwie podanej my_tblw ścieżce wyszukiwania i ładuje ją do pamięci podręcznej bufora Postgres

Lub:

SELECT pg_prewarm('my_schema.my_tbl', 'prefetch');

prefetchwydaje asynchroniczne żądania pobierania wstępnego do systemu operacyjnego, jeśli jest to obsługiwane, lub w przeciwnym razie zgłasza błąd. read odczytuje żądany zakres bloków; w przeciwieństwie do prefetchtego jest synchroniczny i obsługiwany na wszystkich platformach i kompilacjach, ale może być wolniejszy. bufferwczytuje żądany zakres bloków do bufora bufora bazy danych.

Wartość domyślna to buffer, która ma największy wpływ (wyższy koszt, najlepszy efekt).

Przeczytaj instrukcję, aby uzyskać więcej informacji , cytaty są stamtąd.
Depesz też o tym bloguje .

Erwin Brandstetter
źródło
4

W ogólnym przypadku, jeśli masz wystarczającą ilość pamięci RAM, możesz ogólnie zaufać usłudze bazy danych, aby dobrze wykonywać czynności, których regularnie używasz w pamięci RAM. Niektóre systemy pozwalają wskazać, że tabela powinna zawsze znajdować się w pamięci RAM (co jest przydatne w przypadku małych tabel, które nie są często używane, ale kiedy są używane, ważne jest, aby odpowiadały tak szybko, jak to możliwe), ale jeśli pgsql ma takie wskazówki dotyczące tabeli musisz być bardzo ostrożny z ich używaniem, ponieważ zmniejszasz ilość dostępnej pamięci do buforowania czegokolwiek innego, aby spowolnić całą aplikację.

Jeśli chcesz uruchomić pamięć podręczną strony bazy danych podczas uruchamiania (na przykład po ponownym uruchomieniu lub innej operacji konserwacji, która powoduje, że DB zapomina o wszystkim, co jest buforowane), to napisz skrypt, który wykonuje następujące czynności:

SELECT * FROM <table>
SELECT <primary key fields> FROM <table> ORDER BY <primary key fields>
SELECT <indexed fields> FROM <table> ORDER BY <indexed fields>

(ten ostatni krok powtarza się dla każdego indeksu lub kursu i uważaj, aby pola w klauzuli ORDER BY były w odpowiedniej kolejności)

Po uruchomieniu powyższego każda strona danych i indeksu powinna zostać przeczytana i tak będzie w pamięci podręcznej strony RAM (przynajmniej na razie). Mamy takie skrypty dla naszych baz danych aplikacji, które są uruchamiane po ponownym uruchomieniu, aby pierwsi użytkownicy logujący się później do systemu nie reagowali wolniej. Lepiej odręcznie pisz dowolny taki skrypt, zamiast skanować tabele definicji db (jak sys.objects/ sys.indexes/ sys.columnsw MSSQL), wtedy możesz selektywnie skanować najczęściej używane indeksy, zamiast skanować wszystko, co zajmie dłużej.

David Spillett
źródło
3
To nie zadziała, przynajmniej na PostgreSQL. Mały bufor pierścieniowy (256 KB) jest przydzielany z buforów współdzielonych do skanowania sekwencyjnego, aby zapobiec użyciu całego bufora pamięci podręcznej. Szczegółowe informacje można znaleźć na stronie github.com/postgres/postgres/blob/master/src/backend/storage/ ... Możesz to sprawdzić, wykonując WYBÓR * z dużej tabeli, a następnie patrząc na tabelę pg_buffercache (z rozszerzenia pg_buffercache).
hbn
@ hbn witam, ale ten koleś w tym wątku zapisu mówi, że to działa - dba.stackexchange.com/a/36165/55752
scythargon
@scythargon może skończyć w pamięci podręcznej systemu operacyjnego, nie dostanie go w pamięci podręcznej bufora PostgreSQL. Spróbuj tego, co zasugerowałem powyżej, jeśli mi nie wierzysz.
hbn
W Postgres 9.5 próbowałem SELECT * FROM schema.tablei zobaczyłem, że ładuje całą tabelę 60GiB do mojej pamięci podręcznej bufora PostgreSQL 100GiB.
sudo
1

Miałem podobny problem:
po zrestartowaniu usługi serwera i porzuceniu wszystkich danych kasowanych, wiele zapytań wywoływanych po raz pierwszy było naprawdę bardzo powolnych, ze względu na specyficzną złożoność zapytań, do momentu wykonania wszystkich niezbędnych indeksów i danych. oznacza to na przykład, że użytkownicy muszą trafić raz „każdy element” (czas wykonania 1-3 sekund) i powiązane dane z 50 milionów wierszy, aby użytkownicy nie doświadczyli już żadnych niepożądanych opóźnień. Pierwsze irytujące zawieszanie się zajmuje użytkownikom pierwsze 3 godziny, aż większość używanych danych zostanie spieniężona, a programy rujnują wydajność na najwyższym poziomie, a nawet koniec, 2 dni kilka nagłych krótkich opóźnień, gdy uderzają mniej danych za pierwszym razem ... , dla danych statystycznych itp.

Aby rozwiązać ten problem, napisałem mały skrypt Pythona, który wykonuje selekcje na najcięższych tabelach z dużymi indeksami. Uruchomienie trwało 15 minut i nie opóźniało działania.

LongBeard_Boldy
źródło
0

Hmmm, może pomóc polecenie COPY. Wystarczy wykonać KOPIUJ, aby przejść do standardowego wyjścia i odczytać z niego. Można to zrobić za pomocą pg_dump:

pg_dump -U <user> -t <table> <database> > /dev/null

Innym sposobem jest znalezienie wszystkich plików tabel i uruchomienie cat <files> > /dev/null.

Oto przykład, jak uzyskać nazwy plików tabel:

# SELECT oid, datname FROM pg_database ;
  oid  |  datname  
-------+-----------                                                                                                                                          
<...>
 16384 | test
-- out of database is 16384
# SELECT oid, relname FROM pg_class WHERE relname like 'fn%';
  oid  | relname 
-------+---------
 24576 | fn
(1 row)
-- oid of our table is 24576

więc plik (i) tabeli to / path / to / pgsql / data / base / 16384/24576 *

Możesz także chcieć czytać indeksy i tosty, a także pobierać ich Oids w ten sam sposób.

BTW, dlaczego go potrzebujesz? Uważam, że postgresql i system operacyjny są wystarczająco inteligentne, aby buforować najgorętsze dane i utrzymywać dobrą. wydajność pamięci podręcznej.

RVS
źródło
0

Używam RamDrive z QSoft, który został przetestowany jako najszybszy ramdysk dla systemu Windows. Właśnie użyłem

initdb -D e:\data

gdzie e: \ jest miejscem RamDisk.

David
źródło
5
PG na Windows jest dość odważnym wyborem dla strony produkcyjnej, ponieważ jest dużo wolniejszy na Windowsie niż na * nix (niezależnie od pamięci RAM).
DrColossos,