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

Buforowanie w PostgreSQL

Buforowanie…!!, trochę trudno jest omówić pokrótce z jednym artykułem. Ale postaram się podzielić moją wiedzą zdobytą od Heikki/Robert Haas/Bruce Momjian w skrócie. W PostgreSQL istnieją dwie warstwy, współdzielone bufory PG i pamięć podręczna stron systemu operacyjnego, każdy odczyt/zapis powinien przechodzić przez pamięć podręczną systemu operacyjnego (do tej pory bez pomijania). Postgres zapisuje dane w pamięci podręcznej OS Page Cache i potwierdza użytkownikowi, jak zapisał na dysku, a później pamięć podręczna systemu operacyjnego zapisuje na dysku fizycznym we własnym tempie. Bufory współdzielone PG nie mają kontroli nad pamięcią podręczną stron systemu operacyjnego i nawet nie wiedzą, co znajduje się w pamięci podręcznej systemu operacyjnego. Tak więc większość zaleceń wydanych przez Postgres DBA/Professional's, aby mieć szybszy dysk / lepszą pamięć podręczną.

Pamięć podręczna/bufory w PostgreSQL są silniejsze niż inne bazy danych i wysoce wyrafinowane. Ponieważ jestem z przeszłości Oracle (także nastawienie…:) ), więc moje pytanie od kogo się dowiedziałem, to jak/kiedy/co/dlaczego itp., dotyczące bufora bazy danych, przypiętych buforów, opróżniania buforów bazy danych, wstępnego ładowania bazy danych itp., Otrzymałem od nich wszystkie odpowiedzi, jednak podejście jest nieco inne. Mimo, że moje pytania były irytujące, odpowiadały z dużą cierpliwością i wyjaśniały mnie w dużym stopniu, co w efekcie sprawiło, że czytasz tego bloga…. :)..

W przypadku niektórych wniosków (wciąż się uczę) narysowałem mały przegląd przepływu danych między pamięcią na dysk w Postgresie, a także niektóre ważne narzędzia i NOWĄ łatkę autorstwa Roberta Haasa(pg_prewarm) .

pg_buffercache
Moduł contrib, który mówi, co znajduje się w buforze bufora PostgreSQL. Instalacja poniżej:-

postgres=# CREATE EXTENSION pg_buffercache;

pgfincore
Posiada funkcję informującą o tym, jakie dane znajdują się w pamięci podręcznej stron systemu operacyjnego. Pgfincore, moduł staje się bardzo przydatny, gdy jest połączony z pg_buffercache, teraz można uzyskać informacje o pamięci podręcznej bufora PG i pamięci podręcznej strony systemu operacyjnego. Podziękowania dla Cerdica Villemaina. Pgfincore, backbone to fadvise, fincore, które są ftoolami linuksowymi. Możesz także użyć fincore/fadvise, instalując źródła. Po drugie, możesz użyć modułu pgfincore contrib lub ftools, które dają to samo. Próbowałem obu, są po prostu niesamowite.

Installation:
Download the latest version: http://pgfoundry.org/frs/download.php/3186/pgfincore-v1.1.1.tar.gz
As root user:
export PATH=/usr/local/pgsql91/bin:$PATH //Set the path to point pg_config.
tar -xvf pgfincore-v1.1.1.tar.gz
cd pgfincore-1.1.1
make clean
make
make install

Now connect to PG and run below command

postgres=# CREATE EXTENSION pgfincore;

pg_prewarm
Wstępne ładowanie relacji/indeksu do pamięci podręcznej bufora PG. Czy to możliwe w PostgreSQL? o tak, dzięki Robertowi Haasowi , który niedawno przesłał łatkę społeczności, miejmy nadzieję, że będzie ona dostępna w wersji PG 9.2 lub PG 9.3. Możesz jednak użyć poprawki do testów na PG 9.1.

pg_prewarm ma trzy TRYBY:

  1. PRZESUNIĘCIE WSTĘPNE: Pobieranie bloków danych asynchronicznie do pamięci podręcznej systemu operacyjnego, ale nie do buforów PG (tylko do pamięci podręcznej systemu operacyjnego)
  2. CZYTAJ: Wczytuje wszystkie bloki do fikcyjnego bufora i wymusza pamięć podręczną systemu operacyjnego. (działa tylko w pamięci podręcznej systemu operacyjnego)
  3. BUFOR: odczytuje wszystkie bloki lub zakresy bloków do pamięci podręcznej bufora bazy danych.

Instalacja:
Zastosowuję łatkę pg_prewarm na mojej instalacji źródła PG, musisz dostosować zgodnie z konfiguracją.

  1. Rozpakuj lokalizację źródła PG:/usr/local/src/postgresql-9.1.3
  2. Lokalizacja instalacji PG:/usr/local/pgsql91
  3. Lokalizacja wszystkich pobranych plików:/usr/local/src

Uwaga:zainstaluj PG przed zastosowaniem poprawki pg_prewarm.

1. Pobierz łatkę do /usr/local/src/ location
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
E-mail z łatką:
http://archives.postgresql.org/message-id/CA+TgmobRrRxCO+t6gcQrw_dJw+Uf9ZEdwf9beJnu+RB5TEBjEw@mail.gmail.com
2. Po pobraniu przejdź do lokalizacji źródła PG i postępuj zgodnie z instrukcjami.

# cd /usr/local/src/postgresql-9.1.3
# patch -p1 < ../pg_prewarm.bin         (I have renamed after download)
# make -C contrib/pg_prewarm
# make -C contrib/pg_prewarm install

3. Powyższe polecenie utworzy pliki w katalogu $PGPATH/contrib/extension. Teraz możesz dodać moduł contrib.

postgres=# create EXTENSION pg_prewarm;
CREATE EXTENSION
postgres=# dx
List of installed extensions
Name | Version | Schema | Description
----------------+---------+------------+----------------------------------------
pg_buffercache | 1.0 | public | examine the shared buffer cache
pg_prewarm | 1.0 | public | prewarm relation data
pgfincore | 1.1.1 | public | examine and manage the os buffer cache
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
(4 rows)

Documentation:
/usr/local/src/postgresql-9.1.3/doc/src/sgml
[root@localhost sgml]# ll pgpre*
-rw-r--r-- 1 root root 2481 Apr 10 10:15 pgprewarm.sgml

dstat
Kombinacja vmstat,iostat,netstat,top,itp., razem w jednym poleceniu linux „dstat”. Gdy baza danych zachowuje się nietypowo, aby poznać przyczynę z poziomu systemu operacyjnego, otwieramy kilka terminali, aby pobrać proces, pamięć, odczyt/zapis na dysku, informacje o sieci, co jest trochę uciążliwe do przetasowania między oknami. Tak więc dstat ma w sobie opcje serwerowe, które pomagają pokazać wszystkie polecenia w jednym wyjściu w jednym oknie.

Installation:
Dstat download link: (RHEL 6)
wget http://pkgs.repoforge.org/dstat/dstat-0.7.2-1.el6.rfx.noarch.rpm
or
yum install dstat
Documentation: http://dag.wieers.com/home-made/dstat/

Ftools dla Linuksa
Jest przeznaczony do pracy z nowoczesnymi wywołaniami systemu Linux, w tym mincore, fallocate, fadvise itp. Ftools pomogą Ci dowiedzieć się, jakie pliki znajdują się w pamięci podręcznej systemu operacyjnego. Używając skryptów perl/python możesz pobrać informacje o pamięci podręcznej stron OS w plikach obiektowych (pg_class.relfilenode). pg_fincore jest na tym oparty. Możesz użyć skryptów pgfincore lub ftools.

Installation:
Download the tar.gz from the link.
https://github.com/david415/python-ftools

cd python-ftools
python setup.py build
export PYTHONPATH=build/lib.linux-x86_64-2.5
python setup.py install

Note: You need to have python & psycopg2 installed before installing python-ftools.

Teraz wszyscy jesteśmy gotowi, aby przejść do przykładu, aby sprawdzić za pomocą narzędzi i programów narzędziowych. W moim przykładzie mam tabelę, która ma jeden indeks i sekwencję z ponad 100 MB danych.

postgres=# d+ cache
Table "public.cache"
Column | Type | Modifiers | Storage | Description
--------+---------+-----------------------------------------+----------+-------------
name | text | | extended |
code | integer | | plain |
id | integer | default nextval('icache_seq'::regclass) | plain |
Indexes:
"icache" btree (code)
Has OIDs: no

Zapytanie, aby poznać rozmiar zajmowany przez tabelę, sekwencję i jej indeks.

postgres=# SELECT c.relname AS object_name,
CASE when c.relkind='r' then 'table'
when c.relkind='i' then 'index'
when c.relkind='S' then 'sequence'
else 'others'
END AS type,pg_relation_size(c.relname::text) AS size, pg_size_pretty(pg_relation_size(c.relname::text)) AS pretty_size
FROM pg_class c
JOIN pg_roles r ON r.oid = c.relowner
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE (c.relkind = ANY (ARRAY['r'::"char", 'i'::"char", 'S'::"char",''::"char"])) AND n.nspname = 'public';

object_name | type | size | pretty_size
-------------+----------+----------+-------------
icache_seq | sequence | 8192 | 8192 bytes
cache | table | 83492864 | 80 MB
icache | index | 35962880 | 34 MB
(3 rows)

Total object size 'cache'

postgres=# select pg_size_pretty(pg_total_relation_size('cache'));
pg_size_pretty
----------------
114 MB
(1 row)

Napisałem małe zapytanie przez clubbing pgfincore i pg_buffercache, aby pobrać informacje z pamięci podręcznej PG Buffer i OS Page. Będę używał tego zapytania w całym moim przykładzie, wklejając tylko wyniki tego zapytania.

select rpad(c.relname,30,' ') as Object_Name,
case when c.relkind='r' then 'Table' when c.relkind='i' then 'Index' else 'Other' end as Object_Type,
rpad(count(*)::text,5,' ') as "PG_Buffer_Cache_usage(8KB)",
split_part(pgfincore(c.relname::text)::text,','::text,5) as "OS_Cache_usage(4KB)"
from pg_class c inner join pg_buffercache b on b.relfilenode=c.relfilenode
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database() and c.relnamespace=(select oid from pg_namespace where nspname='public'))
group by c.relname,c.relkind
order by "PG_Buffer_Cache_usage(8KB)"
desc limit 10;

object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
(0 rows)

Note: I have bounced the cluster to flush PG buffers & OS Page Cache. So, no data in any Cache/buffer.

Wstępne ładowanie relacji/indeksu za pomocą pg_prewarm:
Przed odbijaniem klastra uruchomiłem zapytanie o sekwencyjne skanowanie pełnej tabeli w tabeli „Cache” i zanotowałem czas, który jest przed ociepleniem relacji/indeksu.

postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.033..354.691 rows=1600000 loops=1)
Total runtime: 427.769 ms
(2 rows)

Pozwala ogrzać relację/indeks/sekwencję za pomocą pg_prewarm i sprawdzić plan zapytania.

postgres=# select pg_prewarm('cache','main','buffer',null,null);
pg_prewarm
------------
10192
(1 row)
postgres=# select pg_prewarm('icache','main','buffer',null,null);
pg_prewarm
------------
4390
(1 row)

Output of combined buffers:
object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
icache | Index | 4390 | 8780
cache | Table | 10192 | 20384
(2 rows)

Wyjście pgfincore:

postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 2
cache | 20384
icache | 8780
(3 rows)

or for each object.

postgres=# select * from pgfincore('cache');
relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit
------------------+---------+--------------+--------------+-----------+-----------+---------------+---------
base/12780/16790 | 0 | 4096 | 20384 | 20384 | 1 | 316451 |
(1 row)

Aby pobrać podobne informacje za pomocą skryptu python-ftools, musisz znać numer relfilenode obiektu, sprawdź poniżej.

postgres=# select relfilenode,relname from pg_class where relname ilike '%cache%';
relfilenode | relname
-------------+----------------
16787 | icache_seq /// you can exclude sequence.
16790 | cache /// table
16796 | icache /// index
(3 rows)

za pomocą skryptu python-ftools

Czy to nie interesujące….!!!!.
Teraz porównaj plan wyjaśnienia po rozgrzaniu stołu do bufora.

postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.016..141.804 rows=1600000 loops=1)
Total runtime: 215.100 ms
(2 rows)

Jak opróżnić/ogrzać relację/indeks w pamięci podręcznej systemu operacyjnego?
Za pomocą pgfadvise możesz wstępnie załadować lub usunąć relację z pamięci podręcznej systemu operacyjnego. Aby uzyskać więcej informacji, wpisz df pgfadvise* w terminalu dla wszystkich funkcji związanych z pgfadvise. Poniżej znajduje się przykład opróżniania pamięci podręcznej systemu operacyjnego.

postgres=# select * from pgfadvise_dontneed('cache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16790 | 4096 | 20384 | 178145
(1 row)
postgres=# select * from pgfadvise_dontneed('icache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16796 | 4096 | 8780 | 187166
(1 row)
postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 0
cache | 0
icache | 0
(3 rows)

Podczas gdy te rzeczy dzieją się w jednym oknie, możesz sprawdzić stosunek odczytu/zapisu za pomocą dstat. Aby uzyskać więcej opcji, użyj dstat –list
dstat -s –top-io –top-bio –top-mem

Wstępne ładowanie zakresu bloków przy użyciu funkcji zakresu pg_prewarm.
Załóżmy, że z jakiegoś powodu chcesz odbić klaster, ale jedna z dużych tabel w buforze działa dobrze. Przy odbijaniu Twoja tabela nie jest już w buforach, aby wrócić do pierwotnego stanu przed odbiciem, musisz wiedzieć, ile bloków tabeli znajdowało się w buforach i wstępnie je załadować za pomocą opcji zakresu pg_prewarm.

Utworzyłem tabelę przez zapytanie pg_buffercache, a później wysłałem informacje o zakresie bloków do pg_prewarm. Dzięki temu współdzielone bufory powracają z wcześniej załadowaną tabelą. Zobacz przykład.

select c.relname,count(*) as buffers from pg_class c 
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)
Note: These are the blocks in buffer.

postgres=# create table blocks_in_buff (relation, fork, block) as select c.oid::regclass::text, case b.relforknumber when 0 then 'main' when 1 then 'fsm' when 2 then 'vm' end, b.relblocknumber from pg_buffercache b, pg_class c, pg_database d where b.relfilenode = c.relfilenode and b.reldatabase = d.oid and d.datname = current_database() and b.relforknumber in (0, 1, 2);
SELECT 14716

Odbij klaster i wstępnie załaduj zakres bloków związanych z tabelą do buforów z „blocks_in_buff”.

postgres=# select sum(pg_prewarm(relation, fork, 'buffer', block, block)) from blocks_in_buff;
sum
-------
14716
(1 row)

postgres=# select c.relname,count(*) as buffers from pg_class c
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)

Widzisz, mój shared_buffer znów działa.

Cieszyć się…!!! wróci z ciekawszymi rzeczami. Opublikuj swoje komentarze.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zwróć zgrupowaną listę z wystąpieniami za pomocą Rails i PostgreSQL

  2. Dynamicznie generuj kolumny w PostgreSQL

  3. SQL, gdzie połączony zbiór musi zawierać wszystkie wartości, ale może zawierać więcej

  4. LOWER() – Konwertuj na małe litery w PostgreSQL

  5. Tabele tymczasowe PostgreSQL