{"id":81089,"date":"2020-05-11T01:42:24","date_gmt":"2020-05-10T23:42:24","guid":{"rendered":"https:\/\/prohoster.info\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov"},"modified":"2020-05-11T01:42:24","modified_gmt":"2020-05-10T23:42:24","slug":"tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","title":{"rendered":"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><strong>Zach\u0119cam do zapoznania si\u0119 z t\u0142umaczeniem raportu z pocz\u0105tku 2016 roku autorstwa Andreja Sa\u0142nikowa &quot;Typowe b\u0142\u0119dy w aplikacjach, kt\u00f3re prowadz\u0105 do bloat w Postgresql&quot;<\/strong><\/p>\n<p><\/p>\n<p>W tym wyk\u0142adzie przedstawi\u0119 g\u0142\u00f3wne b\u0142\u0119dy w aplikacjach, kt\u00f3re pojawiaj\u0105 si\u0119 na etapie projektowania i pisania kodu aplikacji. Skupi\u0119 si\u0119 tylko na tych b\u0142\u0119dach, kt\u00f3re prowadz\u0105 do bloat w Postgresql. Zazwyczaj jest to pocz\u0105tek ko\u0144ca wydajno\u015bci twojego systemu jako ca\u0142o\u015bci, mimo \u017ce pocz\u0105tkowo nie wida\u0107 \u017cadnych przes\u0142anek.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/a9e199bfe2e01c76966b32868790f8f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p>Witam wszystkich! Ten wyk\u0142ad nie jest tak techniczny jak poprzedni prezentowany przez mojego koleg\u0119. Jest on g\u0142\u00f3wnie skierowany do programist\u00f3w system\u00f3w backendowych, poniewa\u017c mamy do\u015b\u0107 du\u017c\u0105 liczb\u0119 klient\u00f3w. I wszyscy pope\u0142niaj\u0105 te same b\u0142\u0119dy. O nich wam opowiem. Wyja\u015bni\u0119, do jakich fatalnych i negatywnych skutk\u00f3w prowadz\u0105 te b\u0142\u0119dy. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/c6c84dbafc595ae3068cd8bf804ccee7.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dlaczego te b\u0142\u0119dy s\u0105 pope\u0142niane? S\u0105 one wynikiem dw\u00f3ch czynnik\u00f3w: po pierwsze, na zasadzie 'mo\u017ce si\u0119 uda' oraz z braku wiedzy o mechanizmach zachodz\u0105cych na poziomie mi\u0119dzy baz\u0105 a aplikacj\u0105, jak r\u00f3wnie\u017c w samej bazie danych. <\/p>\n<p><\/p>\n<p>Podam wam trzy przyk\u0142ady z przera\u017caj\u0105cymi obrazkami ilustruj\u0105cymi, jak wszystko si\u0119 pogorszy\u0142o. Kr\u00f3tko opisz\u0119 mechanizmy, kt\u00f3re tam zachodz\u0105. A tak\u017ce jak sobie z nimi radzi\u0107, gdy ju\u017c si\u0119 pojawi\u0105 i jakie metody prewencyjne stosowa\u0107, by zapobiega\u0107 b\u0142\u0119dom. Opowiem o narz\u0119dziach pomocniczych i podam przydatne linki. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/b0230d992f5b44f0e542df2e4b4d526f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>U\u017cy\u0142em testowej bazy danych, w kt\u00f3rej mia\u0142em dwie tabele. Jedna tabela z rachunkami klient\u00f3w, a druga z operacjami na tych rachunkach. Z jak\u0105\u015b regularno\u015bci\u0105 aktualizujemy salda na tych rachunkach.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/1d2a21278b095b07546e1bb870819dbf.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Dane \u017ar\u00f3d\u0142owe tabeli: jest do\u015b\u0107 ma\u0142a, 2 MB. Czas odpowiedzi dla bazy i konkretnej tabeli jest r\u00f3wnie\u017c bardzo dobry. A obci\u0105\u017cenie wynosi \u2013 2000 operacji na sekund\u0119 na tabeli.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/dea5a4b1ac7952f8cfed0e2e1cfc10dd.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>W trakcie tego wyk\u0142adu b\u0119d\u0119 wam pokazywa\u0142 wykresy, aby by\u0142o jasno wida\u0107, co si\u0119 dzieje. Zawsze b\u0119d\u0105 dwa slajdy z wykresami. Pierwszy slajd \u2013 to, co dzieje si\u0119 og\u00f3lnie na serwerze. <\/p>\n<p><\/p>\n<p>W tej sytuacji widzimy, \u017ce nasza tabela ma rzeczywi\u015bcie niewielki rozmiar. Indeks jest ma\u0142y, wynosz\u0105cy 2 MB. To pierwszy wykres po lewej stronie. <\/p>\n<p><\/p>\n<p>\u015aredni czas odpowiedzi na serwerze r\u00f3wnie\u017c jest stabilny, niski. To wykres w prawym g\u00f3rnym rogu. <\/p>\n<p><\/p>\n<p>Lewy dolny wykres przedstawia najd\u0142u\u017csze transakcje. Widzimy, \u017ce transakcje s\u0105 szybko realizowane. A autovakuum jeszcze nie dzia\u0142a, poniewa\u017c by\u0142 to test pocz\u0105tkowy. W przysz\u0142o\u015bci b\u0119dzie dzia\u0142a\u0142 i przyniesie nam korzy\u015bci.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/9e9b46acd9a878ff70ca4a7850adff09.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Drugi slajd zawsze b\u0119dzie po\u015bwi\u0119cony testowanej tabeli. W tej sytuacji stale aktualizujemy stany na kontach klienta. I widzimy, \u017ce \u015bredni czas odpowiedzi dla operacji aktualizacji jest ca\u0142kiem dobry, poni\u017cej jednej milisekundy. Widzimy r\u00f3wnie\u017c, \u017ce zasoby procesora (to prawy g\u00f3rny wykres) s\u0105 wykorzystywane r\u00f3wnomiernie i pozostaj\u0105 na do\u015b\u0107 niskim poziomie. <\/p>\n<p><\/p>\n<p>Prawy dolny wykres pokazuje, ile pami\u0119ci operacyjnej i dyskowej przeszukujemy w poszukiwaniu potrzebnego wiersza przed jego aktualizacj\u0105. Liczba operacji na tabeli wynosi 2000 na sekund\u0119, tak jak wcze\u015bniej m\u00f3wi\u0142em. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/84760d52716209b8dcfffb462c67a8e1.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A teraz nast\u0119puje tragedia. Z jakiego\u015b powodu pojawia si\u0119 d\u0142uga zapomniana transakcja. Przyczyny s\u0105 zazwyczaj banalne: <\/p>\n<p><\/p>\n<ul>\n<li>Jedna z najcz\u0119stszych to to, \u017ce w kodzie aplikacji zacz\u0119li\u015bmy odwo\u0142ywa\u0107 si\u0119 do zewn\u0119trznej us\u0142ugi. A ta us\u0142uga nie odpowiada. Tzn. otworzyli\u015bmy transakcj\u0119, wprowadzili\u015bmy zmiany w bazie i poszli\u015bmy w aplikacji poczyta\u0107 poczt\u0119 lub skorzysta\u0107 z innej us\u0142ugi w naszej infrastrukturze, a ona z jakiego\u015b powodu nie odpowiada. I mamy zawieszon\u0105 sesj\u0119 w stanie \u2013 nie wiadomo, kiedy to si\u0119 rozwi\u0105\u017ce.<\/li>\n<li>Druga sytuacja, kiedy w kodzie z jakiego\u015b powodu wyst\u0105pi\u0142 wyj\u0105tek. I w tym wyj\u0105tku nie obs\u0142u\u017cyli\u015bmy zamkni\u0119cia transakcji. W rezultacie uzyskali\u015bmy wisz\u0105c\u0105 sesj\u0119 z otwart\u0105 transakcj\u0105. <\/li>\n<li>I ostatni \u2013 to do\u015b\u0107 cz\u0119sty przypadek. To niskiej jako\u015bci kod. Niekt\u00f3re frameworki otwieraj\u0105 transakcj\u0119. Ona wisi, a wy mo\u017cecie nie wiedzie\u0107 w aplikacji, \u017ce wisi. <\/li>\n<\/ul>\n<p><\/p>\n<p>Dok\u0105d prowadz\u0105 takie rzeczy? <\/p>\n<p><\/p>\n<p>Prowadz\u0105 do tego, \u017ce nasze tabele i indeksy zaczynaj\u0105 si\u0119 nagle znacznie powi\u0119ksza\u0107. To w\u0142a\u015bnie ten efekt bloat. Dla bazy przejawi si\u0119 to w tym, \u017ce znacznie wzro\u015bnie czas odpowiedzi bazy danych, zwi\u0119kszy si\u0119 obci\u0105\u017cenie serwera bazy danych. A w rezultacie ucierpi aplikacja. Poniewa\u017c je\u015bli w kodzie sp\u0119dza\u0142e\u015b 10 milisekund na zapytanie do bazy, 10 milisekund na swoj\u0105 logik\u0119, to twoja funkcja trwa\u0142a 20 milisekund. A teraz sytuacja b\u0119dzie znacznie gorsza. <\/p>\n<p><\/p>\n<p>Sp\u00f3jrzmy, co si\u0119 dzieje. Lewy dolny wykres pokazuje, \u017ce mamy d\u0142ug\u0105 transakcj\u0119. A je\u015bli spojrzymy na lewy g\u00f3rny wykres, widzimy, \u017ce rozmiar tabeli z dw\u00f3ch megabajt\u00f3w nagle wzr\u00f3s\u0142 do 300 megabajt\u00f3w. Jednocze\u015bnie ilo\u015b\u0107 danych w tabeli si\u0119 nie zmieni\u0142a, wi\u0119c jest tam sporo niepotrzebnych danych.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/b1947f6487e440a770a1251a955e62d2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Og\u00f3lna sytuacja dotycz\u0105ca \u015bredniego czasu odpowiedzi serwera r\u00f3wnie\u017c zmieni\u0142a si\u0119 o kilka rz\u0119d\u00f3w. To znaczy, \u017ce wszystkie zapytania serwera zacz\u0119\u0142y znacznie spowalnia\u0107. A w mi\u0119dzyczasie uruchomi\u0142y si\u0119 wewn\u0119trzne procesy Postgresa w postaci autovacuum, kt\u00f3re co\u015b pr\u00f3buj\u0105 robi\u0107 i zu\u017cywaj\u0105 zasoby.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/8e91f035d1dd04e72e842d714cc611a5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Co si\u0119 dzieje z nasz\u0105 tabel\u0105? Podobnie. \u015aredni czas odpowiedzi tabeli wzr\u00f3s\u0142 o kilka rz\u0119d\u00f3w. Je\u015bli chodzi o zu\u017cycie zasob\u00f3w, to widzimy, \u017ce obci\u0105\u017cenie procesora znacznie wzros\u0142o. To przedstawia prawy g\u00f3rny wykres. Wzros\u0142o, poniewa\u017c procesor musi przeszukiwa\u0107 mn\u00f3stwo nieprzydatnych wierszy w poszukiwaniu jednego potrzebnego. To przedstawia prawy dolny wykres. W rezultacie liczba wywo\u0142a\u0144 na sekund\u0119 zacz\u0119\u0142a znacznie male\u0107, poniewa\u017c baza danych nie nad\u0105\u017ca\u0142a przetwarza\u0107 tego samego poziomu zapyta\u0144. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/424685ce852bc5f3ef77151f8d3d7289.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Musimy wr\u00f3ci\u0107 do normalno\u015bci. Przegl\u0105damy internet i dowiadujemy si\u0119, \u017ce d\u0142ugie transakcje prowadz\u0105 do problem\u00f3w. Znajdujemy i ko\u0144czymy t\u0119 transakcj\u0119. I wszystko wraca do normy. Wszystko dzia\u0142a jak nale\u017cy. <\/p>\n<p><\/p>\n<p>Uspokajamy si\u0119, ale po pewnym czasie zaczynamy dostrzega\u0107, \u017ce aplikacja dzia\u0142a nie tak, jak przed awari\u0105. Zapytania wci\u0105\u017c s\u0105 przetwarzane wolniej, a zw\u0142aszcza wolniej. O p\u00f3\u0142torej do dw\u00f3ch razy wolniej, konkretne w moim przyk\u0142adzie. Obci\u0105\u017cenie serwera r\u00f3wnie\u017c jest wy\u017csze ni\u017c przed awari\u0105. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/ee3037719a31f8d18fc42745716c4da5.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Pytanie: 'Co si\u0119 dzieje z baz\u0105 danych w tym momencie?'. A z baz\u0105 dzieje si\u0119 nast\u0119puj\u0105ca sytuacja. Na wykresie transakcji wida\u0107, \u017ce si\u0119 zatrzyma\u0142a i rzeczywi\u015bcie nie ma d\u0142ugich transakcji. Ale rozmiar tabeli podczas awarii dramatycznie wzr\u00f3s\u0142. I od tego czasu si\u0119 nie zmniejszy\u0142. \u015aredni czas odpowiedzi w bazie ustabilizowa\u0142 si\u0119. Odpowiedzi wydaj\u0105 si\u0119 by\u0107 adekwatne przy akceptowalnej dla nas pr\u0119dko\u015bci. Autovacuum sta\u0142o si\u0119 bardziej aktywne i zacz\u0119\u0142o co\u015b robi\u0107 z tabel\u0105, poniewa\u017c musi przetworzy\u0107 wi\u0119ksz\u0105 ilo\u015b\u0107 danych. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/f6205242c4024dc3ed4cade5844dbf76.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Specifically regarding the tested table with invoices, where we change the balances: the response time for the request seems to have returned to normal. But in reality, it is one and a half times higher.<\/p>\n<p><\/p>\n<p>And regarding the CPU load, we see that the CPU load has not returned to the desired level since the failure. The reasons lie precisely in the lower right graph. It is clear that some amount of memory is being exhausted there. That is, in order to find the necessary row, we are consuming server resources from the database by sifting through useless data. The number of transactions per second has stabilized. <\/p>\n<p><\/p>\n<p>Overall good, but the situation is worse than it was. There is a clear degradation of the database as a consequence of our application interacting with this database. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/0dfc9cd453fd84bc639ffd99cf189fd2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>And to understand what is happening there, if you weren't at the previous report, here's a bit of theory. Theory about the internal process. Why is autovacuum necessary and what does it do?<\/p>\n<p><\/p>\n<p>Briefly for understanding. At a certain point in time, we have a table. The table contains rows. These rows can be active, alive, and currently needed by us. In the picture, they are marked in green. And there are dead rows that have already been processed, updated, and new entries have appeared for them. They are noted as no longer relevant to the database. But they remain in the table due to the specifics of Postgres.<\/p>\n<p><\/p>\n<p>Why is autovacuum needed? At some point, autovacuum comes in, queries the database, and asks: \"Please give me the id of the oldest transaction that is currently open in the database.\" The database returns this id. Autovacuum, based on it, sifts through the rows in the table. If it sees that some rows have been modified by much older transactions, it has the right to mark them as rows that we can reuse in the future by writing new data into them. This is a background process.<\/p>\n<p><\/p>\n<p>Meanwhile, we continue to work with the database, continuing to make some changes to the table. And for those rows that we can reuse, we write new data. And thus, we have a cycle, i.e., there are always some dead old rows appearing there, and instead of them, we write new rows that we need. And this is a normal state for working with PostgreSQL.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/98dd4451a7ca5f418775f72822c2840c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Co si\u0119 wydarzy\u0142o podczas awarii? Jak przebiega\u0142 ten proces?<\/p>\n<p><\/p>\n<p>Mieli\u015bmy tabel\u0119 w r\u00f3\u017cnym stanie, z niekt\u00f3rymi aktywnymi, a niekt\u00f3rymi nie\u017cyj\u0105cymi wierszami. Przyszed\u0142 autowakuum. Zapyta\u0142 baz\u0119 danych, jaka jest nasza najstarsza transakcja i jaki ma identyfikator. Otrzyma\u0142 ten identyfikator, kt\u00f3ry mo\u017ce mie\u0107 kilka godzin lub dziesi\u0119\u0107 minut. To zale\u017cy od tego, jak du\u017ce obci\u0105\u017cenie masz w bazie danych. I poszed\u0142 szuka\u0107 wierszy, kt\u00f3re mo\u017ce oznaczy\u0107 jako do ponownego u\u017cycia. I nie znalaz\u0142 takich wierszy w naszej tabeli. <\/p>\n<p><\/p>\n<p>Ale w mi\u0119dzyczasie wci\u0105\u017c pracujemy z tabel\u0105. Co\u015b w niej robimy, aktualizujemy, zmieniamy dane. A co powinna robi\u0107 baza danych w tym czasie? Nie ma nic innego, jak tylko dopisywa\u0107 nowe wiersze na ko\u0144cu istniej\u0105cej tabeli. W ten spos\u00f3b rozmiar tabeli zaczyna rosn\u0105\u0107. <\/p>\n<p><\/p>\n<p>Realnie potrzebujemy zielonych wierszy do pracy. Ale w trakcie takiego problemu okazuje si\u0119, \u017ce procent zielonych wierszy jest bardzo niski w ca\u0142ej obj\u0119to\u015bci tabeli. <\/p>\n<p><\/p>\n<p>A kiedy wykonujemy zapytanie, baza danych musi przeszuka\u0107 wszystkie wiersze: i czerwone, i zielone, aby znale\u017a\u0107 potrzebny wiersz. Efekt nadmiaru danych w tabeli nazywa si\u0119 'bloat', kt\u00f3ry dodatkowo zjada nasze miejsce na dysku. Pami\u0119tacie, by\u0142o 2 MB, sta\u0142o si\u0119 300 MB? A teraz zamie\u0144cie megabajty na gigabajty i wkr\u00f3tce pozb\u0119dziecie si\u0119 wszystkich zasob\u00f3w dyskowych.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/fe7cb6b5c99610744ebcfe5ad7235d1e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jakie mog\u0105 by\u0107 konsekwencje dla nas? <\/p>\n<p><\/p>\n<ul>\n<li>W moim przyk\u0142adzie tabela i indeks zwi\u0119kszy\u0142y si\u0119 150 razy. U niekt\u00f3rych naszych klient\u00f3w zdarza\u0142y si\u0119 bardziej fatalne przypadki, gdy po prostu zaczyna\u0142o brakowa\u0107 miejsca na dysku. <\/li>\n<li>Rozmiar tabel nigdy sam w sobie si\u0119 nie zmniejszy. Autowakuum w niekt\u00f3rych przypadkach mo\u017ce odci\u0105\u0107 koniec tabeli, je\u015bli znajduj\u0105 si\u0119 tam tylko martwe wiersze. Ale poniewa\u017c nast\u0119puje ci\u0105g\u0142a rotacja, jeden zielony wiersz mo\u017ce zawisn\u0105\u0107 na ko\u0144cu i nie by\u0107 aktualizowany, podczas gdy wszystkie inne b\u0119d\u0105 zapisywane gdzie\u015b na pocz\u0105tku tabeli. Ale to tak ma\u0142o prawdopodobne zdarzenie, \u017ce nie ma co liczy\u0107, \u017ce samodzielnie tabela zmniejszy swoje rozmiary. <\/li>\n<li>Baza danych musi przeszukiwa\u0107 ca\u0142\u0105 stert\u0119 bezsensownych wierszy. I marnujemy zasoby dyskowe, zasoby procesora i energi\u0119 elektryczn\u0105. <\/li>\n<li>I to bezpo\u015brednio wp\u0142ywa na nasz\u0105 aplikacj\u0119, poniewa\u017c je\u015bli na pocz\u0105tku sp\u0119dzali\u015bmy 10 milisekund na zapytanie i 10 milisekund na nasz kod, to podczas awarii zacz\u0119li\u015bmy sp\u0119dza\u0107 sekund\u0119 na zapytaniu i 10 milisekund na kodzie, tzn. wydajno\u015b\u0107 aplikacji spad\u0142a o rz\u0105d wielko\u015bci. A kiedy awaria zosta\u0142a rozwi\u0105zana, zacz\u0119li\u015bmy po\u015bwi\u0119ca\u0107 20 milisekund na zapytanie i 10 milisekund na kod. Oznacza to, \u017ce i tak zanotowali\u015bmy p\u00f3\u0142torarazowy spadek wydajno\u015bci. A wszystko to z powodu jednej transakcji, kt\u00f3ra si\u0119 zawiesi\u0142a, przy czym by\u0107 mo\u017ce z naszej winy. <\/li>\n<li>I pytanie: \u201eJak wszystko przywr\u00f3ci\u0107 do normy?\u201d, aby ponownie uzyska\u0107 dobr\u0105 wydajno\u015b\u0107 i aby zapytania dzia\u0142a\u0142y tak szybko, jak przed awari\u0105. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/1bf46e8cd9b28ca2862f978f2ca85819.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>W tym celu istnieje okre\u015blony cykl prac, kt\u00f3re nale\u017cy przeprowadzi\u0107. <\/p>\n<p><\/p>\n<p>Najpierw musimy znale\u017a\u0107 problematyczne tabele, kt\u00f3re si\u0119 rozros\u0142y. Rozumiemy, \u017ce w przypadku niekt\u00f3rych tabel zapisy s\u0105 bardziej aktywne, a w przypadku innych mniej aktywne. W tym celu u\u017cywa si\u0119 rozszerzenia <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/pgstattuple.html\">pgstattuple<\/a><\/noindex>. Po zainstalowaniu tego rozszerzenia mo\u017cesz napisa\u0107 zapytania, kt\u00f3re pomog\u0105 ci znale\u017a\u0107 tabele, kt\u00f3re rozros\u0142y si\u0119 na tyle, \u017ce s\u0105 problematyczne. <\/p>\n<p><\/p>\n<p>Po znalezieniu tych tabel nale\u017cy je skompresowa\u0107. W tym celu dost\u0119pne s\u0105 ju\u017c narz\u0119dzia. W naszej firmie u\u017cywamy trzech narz\u0119dzi. Pierwsze to wbudowane VACUUM FULL. Jest brutalne, surowe i bezwzgl\u0119dne, ale czasami jest bardzo przydatne. <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">Pg_repack<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">pgcompacttable<\/a><\/noindex> to zewn\u0119trzne narz\u0119dzia do kompresji tabel. I s\u0105 one bardziej delikatne dla bazy danych. <\/p>\n<p><\/p>\n<p>S\u0105 u\u017cywane w zale\u017cno\u015bci od tego, co jest dla ciebie wygodniejsze. Ale o tym opowiem na samym ko\u0144cu. Najwa\u017cniejsze to, \u017ce s\u0105 trzy narz\u0119dzia. Jest z czego wybiera\u0107. <\/p>\n<p><\/p>\n<p>Po tym, jak wszystko naprawili\u015bmy i upewnili\u015bmy si\u0119, \u017ce wszystko dzia\u0142a poprawnie, musimy wiedzie\u0107, jak zapobiec tej sytuacji w przysz\u0142o\u015bci:<\/p>\n<p><\/p>\n<ul>\n<li>Zapobiega si\u0119 temu do\u015b\u0107 \u0142atwo. Nale\u017cy monitorowa\u0107 czas trwania sesji na serwerze g\u0142\u00f3wnym. <strong>Szczeg\u00f3lnie niebezpieczne s\u0105 sesje w stanie idle in transaction<\/strong>. To te, kt\u00f3re otworzy\u0142y transakcj\u0119, co\u015b zrobi\u0142y i odesz\u0142y lub po prostu si\u0119 zawiesi\u0142y, znikn\u0119\u0142y w kodzie. <\/li>\n<li>Dla was, jako dla programist\u00f3w, wa\u017cne jest testowanie kodu w momencie powstawania tych sytuacji. To nie jest trudne do zrobienia. B\u0119dzie to przydatna kontrola. Unikniesz wielu \u201edziecinnych\u201d problem\u00f3w zwi\u0105zanych z d\u0142ugotrwa\u0142ymi transakcjami. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/d55465d96c4018db733954867d23aaba.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na tych wykresach chcia\u0142em pokaza\u0107, jak zmieni\u0142a si\u0119 tabela i zachowanie bazy danych po przeprowadzeniu VACUUM FULL na tabeli. Nie jest to produkcja.<\/p>\n<p><\/p>\n<p>Rozmiar tabeli natychmiast wr\u00f3ci\u0142 do normalnego stanu roboczego, kilku megabajt\u00f3w. Na \u015bredni czas odpowiedzi serwera nie mia\u0142o to wi\u0119kszego wp\u0142ywu. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/cbb07ad24dba899395223d1ca25e438e.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jednak w przypadku naszej testowanej tabeli, w kt\u00f3rej aktualizowali\u015bmy saldo na kontach, widzimy, \u017ce \u015bredni czas odpowiedzi na zapytanie o aktualizacj\u0119 danych w tabeli skr\u00f3ci\u0142 si\u0119 do poziomu sprzed awarii. Zasoby wykorzystywane przez procesor do wykonania tego zapytania r\u00f3wnie\u017c spad\u0142y do poziomu sprzed awarii. A prawy dolny wykres pokazuje, \u017ce teraz natychmiast znajdujemy dok\u0142adnie ten wiersz, kt\u00f3rego potrzebujemy, nie przeszukuj\u0105c zbioru martwych wierszy, kt\u00f3re by\u0142y przed kompresj\u0105 tabeli. A \u015bredni czas zapyta\u0144 pozosta\u0142 na mniej wi\u0119cej tym samym poziomie. Ale tutaj bardziej chodzi o b\u0142\u0105d mojego sprz\u0119tu.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/c1d90c5442e02fce209dc40e048a8ca2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>To na razie koniec pierwszej opowie\u015bci. Jest ona najbardziej powszechna. I zdarza si\u0119 ka\u017cdemu, niezale\u017cnie od do\u015bwiadczenia klienta, niezale\u017cnie od tego, jak wykwalifikowani s\u0105 programi\u015bci. Pr\u0119dzej czy p\u00f3\u017aniej to si\u0119 zdarza. <\/p>\n<p><\/p>\n<p>Druga historia, w kt\u00f3rej rozk\u0142adamy obci\u0105\u017cenie i optymalizujemy zasoby serwera.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/cda421c554d1329107ddc935045cc1b9.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<ul>\n<li>Ju\u017c uros\u0142y\u015bmy i stali\u015bmy si\u0119 powa\u017cnymi graczami. Rozumiemy, \u017ce mamy replik\u0119 i dobrze by by\u0142o zbalansowa\u0107 obci\u0105\u017cenie: pisa\u0107 na Masterze, a czyta\u0107 z repliki. Zwykle ta sytuacja wyst\u0119puje, gdy chcemy przygotowa\u0107 jakie\u015b raporty lub ETL. I biznes bardzo si\u0119 z tego cieszy. Bardzo pragnie r\u00f3\u017cnorodnych raport\u00f3w z mas\u0105 skomplikowanej analityki. <\/li>\n<li>Raporty s\u0105 wielogodzinne, poniewa\u017c skomplikowanej analityki nie obliczy si\u0119 w milisekundach. My, jako dzielni ch\u0142opcy, piszemy kod. Robimy w aplikacji wstawki, \u017ce zapisujemy na Masterze, a raporty wykonujemy na replikach. <\/li>\n<li>Rozk\u0142adamy obci\u0105\u017cenie. <\/li>\n<li>Wszystko dzia\u0142a \u015bwietnie. Jeste\u015bmy \u015bwietni. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/e94c8c492197a5015ac8aae79389a4c2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jak wygl\u0105da ta sytuacja? Na tych wykresach doda\u0142em tak\u017ce czas trwania transakcji z repliki. Wszystkie inne wykresy dotycz\u0105 tylko serwera Master. <\/p>\n<p><\/p>\n<p>Tabela raport\u00f3w do tego momentu wzros\u0142a. Jest ich wi\u0119cej. Widzimy, \u017ce \u015bredni czas odpowiedzi serwera jest stabilny. Widzimy, \u017ce na replikacji mamy d\u0142ug\u0105 transakcj\u0119, kt\u00f3ra trwa 2 godziny. Zauwa\u017camy spokojn\u0105 prac\u0119 autowakuum, kt\u00f3re przetwarza martwe wiersze. Wszystko u nas w porz\u0105dku. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/2da8acf098d12d6f146ab9b9dcb54b81.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Konkretnie w przypadku testowanej tabeli kontynuujemy aktualizacj\u0119 stan\u00f3w na kontach. I r\u00f3wnie\u017c mamy stabilny czas odpowiedzi na zapytania, stabilne zu\u017cycie zasob\u00f3w. Wszystko u nas w porz\u0105dku. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/3621ef723017bac6fb635caf0a5f4de6.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Wszystko dobrze do momentu, kiedy nasze raporty zaczynaj\u0105 si\u0119 wystrzeliwa\u0107 z powodu konfliktu z replikacj\u0105. A wystrzeliwuj\u0105 si\u0119 one z regularn\u0105 cz\u0119stotliwo\u015bci\u0105. <\/p>\n<p><\/p>\n<p>Zag\u0142\u0119biamy si\u0119 w internet i zaczynamy czyta\u0107, dlaczego tak si\u0119 dzieje. I znajdujemy rozwi\u0105zanie. <\/p>\n<p><\/p>\n<p>Pierwsze rozwi\u0105zanie to zwi\u0119kszenie op\u00f3\u017anienia replikacji. Wiemy, \u017ce nasz raport dzia\u0142a przez 3 godziny. Ustawiamy op\u00f3\u017anienie replikacji na 3 godziny. Uruchamiamy wszystko, ale nadal mamy problemy z tym, \u017ce raporty czasami wystrzeliwuj\u0105 si\u0119. <\/p>\n<p><\/p>\n<p>Chcemy, aby wszystko by\u0142o idealne. Zag\u0142\u0119biamy si\u0119 dalej. I znajdujemy w internecie \u015bwietn\u0105 konfiguracj\u0119 \u2013 hot_standby_feedback. W\u0142\u0105czamy j\u0105. Hot_standby_feedback pozwala nam zatrzyma\u0107 dzia\u0142anie autowakuum na Mistrzu. Dzi\u0119ki temu ca\u0142kowicie pozbywamy si\u0119 konflikt\u00f3w replikacji. I wszystko dobrze dzia\u0142a z raportami.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/ee3c315168bdd3f392d2e8a1c5861004.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A co si\u0119 dzieje z Mistrzem w tym czasie? A z Mistrzem dzieje si\u0119 totalna katastrofa. Obserwujemy teraz wykresy, kiedy w\u0142\u0105czy\u0142em te dwa ustawienia. I widzimy, \u017ce sesja na replikacji w jaki\u015b spos\u00f3b zacz\u0119\u0142a wp\u0142ywa\u0107 na sytuacj\u0119 na Mistrzu. Rzeczywi\u015bcie wp\u0142ywa, poniewa\u017c wstrzyma\u0142a autowakuum, kt\u00f3re oczyszcza martwe wiersze. Rozmiar tabeli znowu skoczy\u0142 w g\u00f3r\u0119. \u015aredni czas wykonania zapyta\u0144 w ca\u0142ej bazie danych r\u00f3wnie\u017c skoczy\u0142 w g\u00f3r\u0119. Autowakuumy lekko si\u0119 poddenerwowa\u0142y. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/980611dcce8b189dc50f422ffd3d2d72.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Konkretnie w naszej tabeli widzimy, \u017ce aktualizacja danych r\u00f3wnie\u017c skoczy\u0142a w g\u00f3r\u0119. Zu\u017cycie zasob\u00f3w procesora r\u00f3wnie\u017c bardzo wzros\u0142o. Znowu przeszukujemy du\u017c\u0105 liczb\u0119 martwych, bezu\u017cytecznych wierszy. A czas odpowiedzi na t\u0119 tabel\u0119, liczba transakcji spad\u0142a. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/a648fd313a5dccf45f0056dc13c54263.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Jak to b\u0119dzie wygl\u0105da\u0107, je\u015bli nie wiemy, o czym m\u00f3wi\u0142em wcze\u015bniej?<\/p>\n<p><\/p>\n<ul>\n<li>Zaczynamy szuka\u0107 problem\u00f3w. Je\u015bli napotkali\u015bmy problemy w pierwszej cz\u0119\u015bci, wiemy, \u017ce mo\u017ce to by\u0107 spowodowane d\u0142ug\u0105 transakcj\u0105 i zag\u0142\u0119biamy si\u0119 w Mistrza. Problem tkwi w Mistrzu. Zawiesza si\u0119. Grzeje si\u0119, jego Load Average jest blisko setki. <\/li>\n<li>Zapytania tam si\u0119 op\u00f3\u017aniaj\u0105, ale nie widzimy tam \u017cadnych d\u0142ugotrwa\u0142ych transakcji. I nie rozumiemy, o co chodzi. Nie wiemy, gdzie szuka\u0107. <\/li>\n<li>Sprawdzamy sprz\u0119t serwerowy. Mo\u017ce nasz RAID uleg\u0142 awarii. Mo\u017ce mamy spalon\u0105 ko\u015b\u0107 pami\u0119ci. Mo\u017ce by\u0107 cokolwiek. Ale nie, serwery s\u0105 nowe, wszystko dzia\u0142a doskonale. <\/li>\n<li>Biegaj\u0105 wszyscy: administratorzy, programi\u015bci i dyrektor. Nic nie pomaga. <\/li>\n<li>I w pewnym momencie wszystko nagle zaczyna si\u0119 samo naprawia\u0107. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/7d4f6417bc5cb3cec33679d843c6661d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Na replikacji w tym czasie zapytanie zosta\u0142o wykonane i odesz\u0142o. Otrzymali\u015bmy raport. Biznes wci\u0105\u017c zadowolony. Jak wida\u0107, nasza tabela znowu uros\u0142a i nie zamierza si\u0119 zmniejsza\u0107. Na wykresie sesji zostawi\u0142em fragment tej d\u0142ugiej transakcji z replikacji, aby\u015bcie mogli oceni\u0107, jak d\u0142ugi czas mija, zanim sytuacja si\u0119 stabilizuje. <\/p>\n<p><\/p>\n<p>Sesja odesz\u0142a. I dopiero po jakim\u015b czasie serwer wraca do wzgl\u0119dnego porz\u0105dku. A \u015bredni czas odpowiedzi na zapytania na serwerze Mistrza wraca do normy. Bo w ko\u0144cu autovakuum otrzyma\u0142 mo\u017cliwo\u015b\u0107 oczyszczenia, oznaczania tych martwych wierszy. I zacz\u0105\u0142 swoj\u0105 prac\u0119. A jak szybko to robi, tak szybko wr\u00f3cimy do porz\u0105dku.<\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/547d195e08de1566da818150a47218eb.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>W tablicy testowej, gdzie aktualizujemy stany na kontach, widzimy dok\u0142adnie t\u0119 sam\u0105 sytuacj\u0119. \u015aredni czas aktualizacji konta tak\u017ce stopniowo si\u0119 normalizuje. Zasoby wykorzystywane przez procesor r\u00f3wnie\u017c malej\u0105. A liczba transakcji na sekund\u0119 wraca do normy. Ale znowu nie do takiej normy, jak\u0105 mieli\u015bmy przed awari\u0105. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/29372a5e9124690931485a7aea65befc.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tak czy inaczej, do\u015bwiadczamy spadk\u00f3w wydajno\u015bci, jak w pierwszym przypadku, od p\u00f3\u0142tora do dw\u00f3ch razy, a czasem nawet wi\u0119cej. <\/p>\n<p><\/p>\n<p>Wygl\u0105da na to, \u017ce zrobili\u015bmy wszystko dobrze. Roz\u0142o\u017cyli\u015bmy obci\u0105\u017cenie. Sprz\u0119t nie stoi bezczynnie. Rozs\u0105dnie podzielili\u015bmy zapytania, ale mimo to wszystko posz\u0142o \u017ale. <\/p>\n<p><\/p>\n<ul>\n<li>Czy nie w\u0142\u0105cza\u0107 hot_standby_feedback? Tak, nie zaleca si\u0119 jego w\u0142\u0105czania bez wyra\u017anych powod\u00f3w. Poniewa\u017c ta opcja wp\u0142ywa bezpo\u015brednio na serwer g\u0142\u00f3wny i wstrzymuje dzia\u0142anie autovacuum. W\u0142\u0105czaj\u0105c to na jakiej\u015b replikacji i zapominaj\u0105c o tym, mo\u017cesz zniszczy\u0107 serwer g\u0142\u00f3wny i napotka\u0107 powa\u017cne problemy z aplikacj\u0105. <\/li>\n<li>Czy zwi\u0119kszy\u0107 max_standby_streaming_delay? Tak, je\u017celi chodzi o raporty \u2013 to ma sens. Je\u015bli masz trzygodzinny raport i nie chcesz, aby si\u0119 on zepsu\u0142 z powodu konflikt\u00f3w replikacji, po prostu zwi\u0119ksz op\u00f3\u017anienie. D\u0142ugi raport nigdy nie wymaga danych, kt\u00f3re trafi\u0142y do bazy chwil\u0119 temu. Je\u017celi trwa on trzy godziny, oznacza to, \u017ce uruchamiasz go na podstawie danych sprzed jakiego\u015b czasu. I nie ma znaczenia, czy op\u00f3\u017anienie wynosi trzy godziny, czy sze\u015b\u0107, ale b\u0119dziesz otrzymywa\u0142 stabilne raporty i unikniesz problem\u00f3w z ich awari\u0105. <\/li>\n<li>Oczywi\u015bcie, nale\u017cy kontrolowa\u0107 d\u0142ugie sesje na replikach, szczeg\u00f3lnie je\u015bli zdecydowa\u0142e\u015b si\u0119 w\u0142\u0105czy\u0107 hot_standby_feedback na replikach. Poniewa\u017c mo\u017ce si\u0119 zdarzy\u0107 wszystko. Przekazali\u015bmy t\u0119 replik\u0119 programi\u015bcie, aby przetestowa\u0142 zapytania. Napisa\u0142 on szalone zapytanie. Uruchomi\u0142 je i poszed\u0142 napi\u0107 si\u0119 herbaty, a my otrzymujemy zablokowany serwer g\u0142\u00f3wny. Lub wpu\u015bcili\u015bmy tam nieodpowiedni\u0105 aplikacj\u0119. Sytuacje bywaj\u0105 r\u00f3\u017cne. Sesje na replikach nale\u017cy kontrolowa\u0107 r\u00f3wnie dok\u0142adnie, jak na serwerze g\u0142\u00f3wnym. <\/li>\n<li>A je\u015bli masz szybkie i d\u0142ugie zapytania po replikach, to w tej sytuacji lepiej jest podzieli\u0107 je dla roz\u0142o\u017cenia obci\u0105\u017cenia. To odniesienie do streaming_delay. Dla szybkich zapyta\u0144 mie\u0107 jedn\u0105 replik\u0119 z niewielkim op\u00f3\u017anieniem replikacji. Dla d\u0142ugich zapyta\u0144 raportowych mie\u0107 replik\u0119, kt\u00f3ra mo\u017ce mie\u0107 op\u00f3\u017anienie wynosz\u0105ce 6 godzin, nawet do doby. To ca\u0142kowicie normalna sytuacja. <\/li>\n<\/ul>\n<p><\/p>\n<p>Usuwamy konsekwencje w ten sam spos\u00f3b:<\/p>\n<p><\/p>\n<ul>\n<li>Znajdujemy powi\u0119kszone tabele.<\/li>\n<li>I kompresujemy je najwygodniejszym narz\u0119dziem, kt\u00f3re nam odpowiada. <\/li>\n<\/ul>\n<p><\/p>\n<p>Druga historia na tym si\u0119 zako\u0144czy\u0142a. Przechodzimy do historii trzeciej. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/c8784e0be27883640cb8f6919a1c25e0.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Te\u017c do\u015b\u0107 zwyczajna dla nas, w kt\u00f3rej przeprowadzamy migracj\u0119. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/a04b9cd88a0e7e8a3b960ef930eb2657.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<ul>\n<li>Ka\u017cdy produkt oprogramowania si\u0119 rozwija. Zmieniaj\u0105 si\u0119 wymagania wobec niego. W ka\u017cdym przypadku chcemy si\u0119 rozwija\u0107. I czasami musimy zaktualizowa\u0107 dane w tabeli, przeprowadzi\u0107 aktualizacj\u0119 w ramach naszej migracji pod now\u0105 funkcjonalno\u015b\u0107, kt\u00f3r\u0105 wprowadzamy w ramach naszego rozwoju. <\/li>\n<li>Stary format danych nie jest wystarczaj\u0105cy. Za\u0142\u00f3\u017cmy, \u017ce teraz odwo\u0142amy si\u0119 do drugiej tabeli, gdzie mam operacje na tych kontach. I za\u0142\u00f3\u017cmy, \u017ce by\u0142y w rublach, a postanowili\u015bmy zwi\u0119kszy\u0107 precyzj\u0119 i robi\u0107 to w kopiejkach. Aby tego dokona\u0107, musimy przeprowadzi\u0107 aktualizacj\u0119: pole z kwot\u0105 operacji pomno\u017cy\u0107 przez sto. <\/li>\n<li>W dzisiejszym \u015bwiecie korzystamy z zautomatyzowanych narz\u0119dzi do kontroli wersji bazy danych. Za\u0142\u00f3\u017cmy, <noindex><a rel=\"nofollow\" href=\"https:\/\/www.liquibase.org\/\">Liquibase<\/a><\/noindex>. Wpisujemy nasz\u0105 migracj\u0119. Testujemy j\u0105 na naszej bazie testowej. Wszystko dzia\u0142a \u015bwietnie. Aktualizacja przebiega. Blokuje prac\u0119 na jaki\u015b czas, ale zyskujemy zaktualizowane dane. Mo\u017cemy uruchamia\u0107 now\u0105 funkcjonalno\u015b\u0107 na tym. Wszystko przetestowane, sprawdzone. Wszystko potwierdzone. <\/li>\n<li>Przeprowadzili\u015bmy okresowe prace, przeprowadzili\u015bmy migracj\u0119. <\/li>\n<\/ul>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/9e046583f7b1723fc1eaf61a03900918.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Oto migracja z aktualizacj\u0105 przedstawiona przed tob\u0105. Poniewa\u017c s\u0105 to operacje na kontach, tabela mia\u0142a 15 GB. I poniewa\u017c aktualizujemy ka\u017cdy wiersz, w efekcie powi\u0119kszyli\u015bmy tabel\u0119 dwukrotnie, poniewa\u017c zapisali\u015bmy ka\u017cdy wiersz ponownie. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/06120c98ea43d0568045e71935c23592.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Podczas migracji nie mogli\u015bmy nic robi\u0107 z t\u0105 tabel\u0105, poniewa\u017c wszystkie zapytania do niej stan\u0119\u0142y w kolejce i czeka\u0142y, a\u017c ta aktualizacja si\u0119 zako\u0144czy. Ale tu chc\u0119 zwr\u00f3ci\u0107 uwag\u0119 na liczby, kt\u00f3re zobaczysz na osi pionowej. T. j. mamy \u015bredni czas zapytania przed migracj\u0105 w okolicach 5 milisekund i obci\u0105\u017cenie procesora, liczba operacji blokowych po odczycie pami\u0119ci dysku jest mniejsza ni\u017c 7,5. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/69a3ba4d1d0cec7d39284e09e9d3055b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Przeprowadzili\u015bmy migracj\u0119 i zn\u00f3w napotkali\u015bmy problemy. <\/p>\n<p><\/p>\n<p>Migracja przebieg\u0142a pomy\u015blnie, ale:<\/p>\n<p><\/p>\n<ul>\n<li>Stara funkcjonalno\u015b\u0107 zacz\u0119\u0142a dzia\u0142a\u0107 wolniej. <\/li>\n<li>Tabela zn\u00f3w zwi\u0119kszy\u0142a swoje rozmiary. <\/li>\n<li>Obci\u0105\u017cenie serwera zn\u00f3w sta\u0142o si\u0119 wy\u017csze, ni\u017c by\u0142o. <\/li>\n<li>I oczywi\u015bcie, nadal zajmujemy si\u0119 t\u0105 funkcjonalno\u015bci\u0105, kt\u00f3ra dzia\u0142a\u0142a dobrze, nieco j\u0105 poprawili\u015bmy. <\/li>\n<\/ul>\n<p><\/p>\n<p>I to zn\u00f3w prowadzi do bloat, kt\u00f3ry ponownie utrudnia nam \u017cycie. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/becd7cce3a1c8821c81c96257f41202b.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Tutaj demonstruj\u0119, \u017ce tabela, jak w dw\u00f3ch poprzednich przypadkach, nie zamierza wraca\u0107 do wcze\u015bniejszych rozmiar\u00f3w. \u015arednie obci\u0105\u017cenie serwera wydaje si\u0119 by\u0107 adekwatne. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/4d703a60d43a3460bc3782d49865b690.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>A je\u015bli spojrzymy na tabel\u0119 z rachunkami, zobaczymy, \u017ce \u015bredni czas zapytania wzr\u00f3s\u0142 dwukrotnie w por\u00f3wnaniu do tej tabeli. Obci\u0105\u017cenie procesora i liczba przetwarzanych w pami\u0119ci wierszy wzros\u0142y powy\u017cej 7,5, podczas gdy wcze\u015bniej by\u0142o poni\u017cej. W przypadku procesor\u00f3w wzros\u0142o dwukrotnie, w przypadku operacji blokowych wzros\u0142o 1,5 razy, co oznacza, \u017ce do\u015bwiadcili\u015bmy degradacji wydajno\u015bci serwera. A w konsekwencji \u2013 degradacji wydajno\u015bci naszej aplikacji. Przy tym liczba wywo\u0142a\u0144 pozosta\u0142a na mniej wi\u0119cej tym samym poziomie. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/80772afa0643b29f5314a2482c9dfe0d.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>I tutaj najwa\u017cniejsze jest zrozumienie, jak w\u0142a\u015bciwie przeprowadza\u0107 takie migracje. A s\u0105 one konieczne. Do\u015b\u0107 regularnie przeprowadzamy te migracje.<\/p>\n<p><\/p>\n<ul>\n<li>Takie du\u017ce migracje nie s\u0105 przeprowadzane automatycznie. Zawsze musz\u0105 by\u0107 kontrolowane. <\/li>\n<li>Wymagana jest kontrola ze strony znaj\u0105cej si\u0119 osoby. Je\u015bli masz DBA w zespole, to niech to robi DBA. To jego praca. Je\u015bli nie, niech to robi najbardziej do\u015bwiadczona osoba, kt\u00f3ra wie, jak pracowa\u0107 z bazami danych. <\/li>\n<li>Nowy schemat bazy danych, nawet w przypadku, gdy aktualizujemy jedn\u0105 kolumn\u0119, zawsze przygotowujemy etapami, tj. wcze\u015bniej przed wdro\u017ceniem nowej wersji aplikacji:<\/li>\n<li>Dodawane s\u0105 nowe pola, do kt\u00f3rych b\u0119dziemy zapisywa\u0107 w\u0142a\u015bnie zaktualizowane dane. <\/li>\n<li>Przenosimy dane ze starego pola do nowego pola ma\u0142ymi partiami. Dlaczego to robimy? Po pierwsze, zawsze kontrolujemy przebieg tego procesu. Wiemy, ile ju\u017c przenie\u015bli\u015bmy partii i ile nam pozosta\u0142o. <\/li>\n<li>A drugim pozytywnym efektem jest to, \u017ce mi\u0119dzy ka\u017cd\u0105 tak\u0105 parti\u0105 zamykamy transakcj\u0119, otwieramy now\u0105, co daje mo\u017cliwo\u015b\u0107 automatycznemu wakumowi dzia\u0142aj\u0105cemu na tabeli, oznaczeniu martwych wierszy do ponownego wykorzystania. <\/li>\n<li>Dla wierszy, kt\u00f3re b\u0119d\u0105 si\u0119 pojawia\u0107 w trakcie dzia\u0142ania aplikacji (mamy jeszcze dzia\u0142aj\u0105c\u0105 star\u0105 aplikacj\u0119) dodajemy wyzwalacz, kt\u00f3ry zapisuje nowe warto\u015bci w nowych polach. W naszym przypadku \u2013 jest to pomno\u017cenie starej warto\u015bci przez sto. <\/li>\n<li>Je\u015bli jeste\u015bmy naprawd\u0119 upartymi i chcemy to samo pole, to po zako\u0144czeniu wszystkich migracji i przed wdro\u017ceniem nowej wersji aplikacji, po prostu zmieniamy nazwy p\u00f3l. Stare na jakie\u015b wymy\u015blone nazwy, a nowe pola zmieniamy w stare. <\/li>\n<li>I dopiero po tym uruchamiamy now\u0105 wersj\u0119 aplikacji. <\/li>\n<\/ul>\n<p><\/p>\n<p>I dzi\u0119ki temu nie do\u015bwiadczymy bloat i nie spadniemy na wydajno\u015bci. <\/p>\n<p><\/p>\n<p>Na tym sko\u0144czy\u0142a si\u0119 trzecia historia. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/2afab2906b5ccd30e4c8772248818057.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat.sql\">https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat.sql<\/a><\/noindex><\/p>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat_approx.sql\">https:\/\/github.com\/dataegret\/pg-utils\/blob\/master\/sql\/table_bloat_approx.sql<\/a><\/noindex><\/p>\n<p><\/p>\n<p>A teraz troch\u0119 bardziej szczeg\u00f3\u0142owo o narz\u0119dziach, kt\u00f3re wspomina\u0142em w pierwszej historii. <\/p>\n<p><\/p>\n<p>Zanim zaczniesz szuka\u0107 bloat, musisz koniecznie zainstalowa\u0107 rozszerzenie. <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/pgstattuple.html\">pgstattuple<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Aby nie wymy\u015bla\u0107 zapyta\u0144, ju\u017c przygotowali\u015bmy je w naszej pracy. Mo\u017cesz je wykorzysta\u0107. Tutaj przedstawiono dwa zapytania. <\/p>\n<p><\/p>\n<ul>\n<li>Pierwsze dzia\u0142a do\u015b\u0107 d\u0142ugo, ale poka\u017ce ci dok\u0142adne warto\u015bci bloat w tabeli. <\/li>\n<li>Drugie dzia\u0142a szybciej i jest bardzo skuteczne, kiedy trzeba szybko oceni\u0107 \u2013 czy w tabeli jest bloat, czy nie. I powiniene\u015b rozumie\u0107, \u017ce bloat w tabeli Postgres zawsze istnieje. To cecha jego modelu MVCC. <\/li>\n<li>A 20% bloat to w wi\u0119kszo\u015bci przypadk\u00f3w normalne dla tabel. Tzn. nie musisz si\u0119 martwi\u0107 i kompresowa\u0107 tej tabeli. <\/li>\n<\/ul>\n<p><\/p>\n<p>Jak zidentyfikowa\u0107 tabele, kt\u00f3re si\u0119 powi\u0119kszy\u0142y, to zrozumieli\u015bmy, zw\u0142aszcza kiedy zwi\u0119kszy\u0142y si\u0119 o niepotrzebne dane. <\/p>\n<p><\/p>\n<p>Teraz o tym, jak naprawi\u0107 bloat:<\/p>\n<p><\/p>\n<ul>\n<li>Je\u015bli mamy ma\u0142\u0105 tabel\u0119 i dobre dyski, tzn. na tabeli do gigabajta mo\u017cna u\u017cy\u0107 VACUUM FULL. We\u017amie on dla siebie wy\u0142\u0105czn\u0105 blokad\u0119 na tabel\u0119 na kilka sekund, ale za to szybko i skutecznie wszystko zrobi. Co robi VACUUM FULL? Bierze wy\u0142\u0105czn\u0105 blokad\u0119 na tabel\u0119 i przepisuje aktywne wiersze ze starych tabel do nowej tabeli. A na koniec zamienia je miejscami. Usuwa stare pliki, a nowe podstawia w miejsce starych. Ale w czasie swojej pracy bierze wy\u0142\u0105czn\u0105 blokad\u0119 tabeli. To oznacza, \u017ce nie mo\u017cesz zrobi\u0107 nic z t\u0105 tabel\u0105: ani w niej pisa\u0107, ani jej czyta\u0107, ani modyfikowa\u0107. I VACUUM FULL wymaga dodatkowego miejsca na dysku, aby zapisa\u0107 dane.<\/li>\n<li>Nast\u0119pne narz\u0119dzie <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">pg_repack<\/a><\/noindex>. Zasadniczo jest bardzo podobne do VACUUM FULL, poniewa\u017c r\u00f3wnie\u017c przepisuje dane ze starych plik\u00f3w do nowych i zamienia je w tabeli. Ale na pocz\u0105tku pracy nie bierze wy\u0142\u0105cznej blokady tabeli, tylko w momencie, gdy ma ju\u017c gotowe dane do zamiany plik\u00f3w. Wymagania dotycz\u0105ce zasob\u00f3w dyskowych s\u0105 takie same jak u VACUUM FULL. Potrzebujesz dodatkowego miejsca na dysku, a to czasami bywa krytyczne, je\u015bli masz tabeli o terabajtowej wielko\u015bci. I jest do\u015b\u0107 zasobo\u017cerny, poniewa\u017c prowadzi aktywn\u0105 prac\u0119 z wej\u015bciem-wyj\u015bciem. <\/li>\n<li>Trzecie narz\u0119dzie to <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">pgcompacttable<\/a><\/noindex>Ona bardziej oszcz\u0119dnie podchodzi do zasob\u00f3w, poniewa\u017c dzia\u0142a nieco na innych zasadach. G\u0142\u00f3wna istota pgcompacttable polega na tym, \u017ce podczas aktualizacji w tabeli przenosi wszystkie aktywne wiersze na pocz\u0105tek tabeli. Nast\u0119pnie uruchamia proces vacuum na tej tabeli, poniewa\u017c wiemy, \u017ce na pocz\u0105tku s\u0105 aktywne, a na ko\u0144cu martwe wiersze. A vacuum samo obcina ten ogon, tzn. dodatkowe miejsce na dysku nie jest w du\u017cym stopniu wymagane. Przy tym mo\u017cna jeszcze ograniczy\u0107 jego zu\u017cycie zasob\u00f3w. <\/li>\n<\/ul>\n<p><\/p>\n<p>Z narz\u0119dziami wszystko. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andriej Sa\u0142nikow\" src=\"\/wp-content\/uploads\/2020\/05\/4187915e54e54a0b85a342fe0280f78f.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Je\u015bli temat bloat wyda ci si\u0119 interesuj\u0105cy do dalszego zg\u0142\u0119biania, oto kilka przydatnych link\u00f3w:<\/p>\n<p><\/p>\n<ul>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/www.slideshare.net\/alexius2Mb\/where-is-the-space-postgres\">https:\/\/www.slideshare.net\/alexius2Mb\/where-is-the-space-postgres<\/a><\/noindex> \u2013 to prezentacja mojego kolegi. Jest to og\u00f3lna kwestia dotycz\u0105ca tego, gdzie znika miejsce w Postgresie w trakcie jego dzia\u0142ania. Zawiera bardzo du\u017c\u0105 i szczeg\u00f3\u0142ow\u0105 cz\u0119\u015b\u0107 techniczn\u0105 dla administrator\u00f3w baz danych na temat bloat. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pg-utils\">https:\/\/github.com\/dataegret\/pg-utils<\/a><\/noindex> \u2013 to link do naszego repozytorium, gdzie przechowujemy mn\u00f3stwo przydatnych skrypt\u00f3w do sprawdzania stanu bazy danych. Mo\u017cesz tam znale\u017a\u0107 skrypty do wyszukiwania bloat. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/reorg\/pg_repack\">Trzeci<\/a><\/noindex> i <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/dataegret\/pgcompacttable\">czwarty<\/a><\/noindex> linki do narz\u0119dzi, kt\u00f3re pomog\u0105 ci ograniczy\u0107 tabele. <\/li>\n<li><noindex><a rel=\"nofollow\" href=\"http:\/\/blog.dataegret.com\/2Mb018\/03\/postgresql-bloatbusters.html\">http:\/\/blog.dataegret.com\/2Mb018\/03\/postgresql-bloatbusters.html<\/a><\/noindex> \u2013 to post mojego kolegi. Tam bardzo szczeg\u00f3\u0142owo i technicznie omawia bloat na poziomie bliskim administratorom. <\/li>\n<\/ul>\n<p><\/p>\n<p>Stara\u0142em si\u0119 tutaj bardziej pokaza\u0107 straszak dla deweloper\u00f3w, poniewa\u017c s\u0105 oni naszymi bezpo\u015brednimi klientami baz danych i musz\u0105 rozumie\u0107, do czego prowadz\u0105 r\u00f3\u017cne dzia\u0142ania. Mam nadziej\u0119, \u017ce mi si\u0119 to uda\u0142o. Dzi\u0119kuj\u0119 za uwag\u0119!<\/p>\n<p><\/p>\n<p>Pytania<\/p>\n<p><\/p>\n<p><em>Dzi\u0119kuj\u0119 za prezentacj\u0119! M\u00f3wi\u0142e\u015b o tym, jak mo\u017cna identyfikowa\u0107 problemy. A jak mo\u017cna ich unika\u0107? Tzn. mia\u0142em sytuacj\u0119, kiedy zapytania zawiesza\u0142y si\u0119 nie tylko z powodu tego, \u017ce odwo\u0142ywa\u0142y si\u0119 do jaki\u015b zewn\u0119trznych serwis\u00f3w. To by\u0142y po prostu jakie\u015b straszne joins. By\u0142y jakie\u015b ma\u0142e, niegro\u017ane zapytania, kt\u00f3re przez dob\u0119 si\u0119 wiesza\u0142y, a potem zaczyna\u0142y robi\u0107 jakie\u015b g\u0142upoty. Tzn. bardzo przypomina to, co opisujesz. Jak to monitorowa\u0107? Siedzie\u0107 i ci\u0105gle patrze\u0107, kt\u00f3re zapytanie utkn\u0119\u0142o? Jak mo\u017cna tego unikn\u0105\u0107?<\/em><\/p>\n<p><\/p>\n<p>W tym przypadku \u2013 to zadanie dla administrator\u00f3w twojej firmy, a niekoniecznie dla DBA.<\/p>\n<p><\/p>\n<p><em>Jestem administratorem.<\/em><\/p>\n<p><\/p>\n<p>W PostgreSQL istnieje takie widok, jak pg_stat_activity, w kt\u00f3rym pokazywane s\u0105 wisz\u0105ce zapytania. Mo\u017cesz zobaczy\u0107, jak d\u0142ugo tam wisz\u0105.<\/p>\n<p><\/p>\n<p><em>Musz\u0119 co 5 minut wchodzi\u0107 i sprawdza\u0107?<\/em><\/p>\n<p><\/p>\n<p>Skonfiguruj cron i monitoruj. Je\u015bli masz d\u0142ugi zapytanie, napisz e-mail i tyle. Tzn. nie musisz patrze\u0107 na to na bie\u017c\u0105co, mo\u017cna to zautomatyzowa\u0107. Otrzymasz e-mail, na kt\u00f3ry reagujesz. Mo\u017cesz te\u017c automatycznie reagowa\u0107.<\/p>\n<p><\/p>\n<p><em>Czy s\u0105 oczywiste powody, dlaczego to si\u0119 dzieje?<\/em><\/p>\n<p><\/p>\n<p>Wymieni\u0142em kilka. Inne s\u0105 bardziej skomplikowanymi przyk\u0142adami. Rozmowa o nich mo\u017ce trwa\u0107 d\u0142ugo.<\/p>\n<p><\/p>\n<p><em>Dzi\u0119kuj\u0119 za prezentacj\u0119! Chcia\u0142em zapyta\u0107 o narz\u0119dzie pg_repack. Je\u015bli nie blokuje ono wy\u0142\u0105cznie, to\u2026<\/em><\/p>\n<p><\/p>\n<p>Ono blokuje wy\u0142\u0105cznie. <\/p>\n<p><\/p>\n<p>\u2026 <em>to potencjalnie mog\u0119 straci\u0107 dane. Moja aplikacja nie powinna nic zapisywa\u0107 w tym czasie?<\/em><\/p>\n<p><\/p>\n<p>Nie, dzia\u0142a spokojnie z tabel\u0105, tzn. pg_repack najpierw przenosi wszystkie \u017cywe wiersze, kt\u00f3re s\u0105. Naturalnie w tabeli zachodzi jaka\u015b operacja zapisu. On po prostu dok\u0142ada ten ko\u0144cowy fragment. <\/p>\n<p><\/p>\n<p><em>Tzn. on w ko\u0144cu jednak to robi?<\/em><\/p>\n<p><\/p>\n<p>Na ko\u0144cu bierze wy\u0142\u0105czn\u0105 blokad\u0119, aby zamieni\u0107 te pliki miejscami. <\/p>\n<p><\/p>\n<p><em>Czy to b\u0119dzie szybsze ni\u017c VACUUM FULL?<\/em><\/p>\n<p><\/p>\n<p>VACUUM FULL, kiedy si\u0119 uruchomi, od razu bierze wy\u0142\u0105czn\u0105 blokad\u0119. I dop\u00f3ki wszystkiego nie sko\u0144czy, nie zwolni blokady. A pg_repack bierze wy\u0142\u0105czn\u0105 blokad\u0119 tylko w momencie wymiany plik\u00f3w. W tym momencie nie zapiszesz nic, ale dane nie zostan\u0105 utracone, wszystko b\u0119dzie w porz\u0105dku. <\/p>\n<p><\/p>\n<p><em>Cze\u015b\u0107! Opowiada\u0142e\u015b o pracy autovacuum. By\u0142 wykres z czerwonymi, \u017c\u00f3\u0142tymi i zielonymi kom\u00f3rkami zapisu. Tzn. \u017c\u00f3\u0142te \u2013 oznaczy\u0142 jako usuni\u0119te. A w konsekwencji mo\u017cna w nich zapisa\u0107 co\u015b nowego?<\/em><\/p>\n<p><\/p>\n<p>Tak. Postgres nie usuwa wierszy. Ma tak\u0105 specyfik\u0119. Je\u015bli zaktualizujemy wiersz, stary jest oznaczany jako usuni\u0119ty. Tam wstawia si\u0119 id transakcji, kt\u00f3ra zmieni\u0142a ten wiersz, i zapisujemy nowy wiersz. I mamy sesje, kt\u00f3re potencjalnie mog\u0105 je odczyta\u0107. W pewnym momencie staj\u0105 si\u0119 ca\u0142kiem stare. Istota dzia\u0142ania autovacuum polega na tym, \u017ce przeszukuje te wiersze i oznacza je jako niepotrzebne. I mo\u017cna tam zapisa\u0107 nowe dane. <\/p>\n<p><\/p>\n<p><em>Zrozumia\u0142em. Ale pytanie nieco nie dotyczy tego. Nie doko\u0144czy\u0142em. Za\u0142\u00f3\u017cmy, \u017ce mamy tabel\u0119. Ma pola zmiennej d\u0142ugo\u015bci. Je\u015bli spr\u00f3buj\u0119 wstawi\u0107 co\u015b nowego, to mo\u017ce po prostu nie zmie\u015bci\u0107 si\u0119 w starej kom\u00f3rce.<\/em> <\/p>\n<p><\/p>\n<p>Nie, w ka\u017cdym razie ca\u0142a linia jest aktualizowana. W Postgres s\u0105 dwa modele przechowywania danych. Wybiera je w zale\u017cno\u015bci od typu danych. S\u0105 dane, kt\u00f3re s\u0105 przechowywane bezpo\u015brednio w tabeli, a s\u0105 te\u017c dane tos. To s\u0105 du\u017ce obj\u0119to\u015bci danych: tekst, json. S\u0105 one przechowywane w osobnych tabelach. I w przypadku tych tabel wyst\u0119puje ta sama historia z bloat, tzn. wszystko to samo. Po prostu s\u0105 one wydzielone osobno. <\/p>\n<p><\/p>\n<p><em>Dzi\u0119kuj\u0119 za prezentacj\u0119! Na ile akceptowalne jest u\u017cywanie limit\u00f3w czasowych dla zapyta\u0144 statement timeout?<\/em><\/p>\n<p><\/p>\n<p>Bardzo akceptowalne. U\u017cywamy tego wsz\u0119dzie. A poniewa\u017c nie mamy w\u0142asnych us\u0142ug, \u015bwiadczymy zdalne wsparcie, wi\u0119c mamy do czynienia z r\u00f3\u017cnorodnymi klientami. I wszyscy s\u0105 z tego ca\u0142kiem zadowoleni. Tzn. mamy zadania w cron, kt\u00f3re to sprawdzaj\u0105. Po prostu z klientem ustala si\u0119 czas trwania sesji, przed ko\u0144cem kt\u00f3rego nie ko\u0144czymy. Mo\u017ce to by\u0107 minuta, mo\u017ce to by\u0107 10 minut. Zale\u017cy to od obci\u0105\u017cenia bazy i jej celu. Ale wszyscy wykorzystujemy pg_stat_activity.<\/p>\n<p><\/p>\n<p><em>Dzi\u0119kuj\u0119 za prezentacj\u0119! Staram si\u0119 dostosowa\u0107 to, co m\u00f3wisz, do moich aplikacji. I wydaje mi si\u0119, \u017ce wsz\u0119dzie zaczynamy transakcj\u0119, wsz\u0119dzie jawnie j\u0105 ko\u0144czymy. Je\u017celi wyst\u0105pi jaki\u015b wyj\u0105tek, to i tak wyst\u0119puje rollback. I tutaj si\u0119 zastanowi\u0142em. Przecie\u017c transakcja mo\u017ce rozpocz\u0105\u0107 si\u0119 niejawnie. To chyba sugestia dla dziewczyny. Je\u017celi po prostu aktualizuj\u0119 rekord, transakcja rozpocznie si\u0119 w PostgreSQL i zako\u0144czy, gdy nast\u0105pi roz\u0142\u0105czenie?<\/em><\/p>\n<p><\/p>\n<p>Je\u015bli m\u00f3wisz teraz o poziomie aplikacji, to zale\u017cy to od sterownika, kt\u00f3ry u\u017cywasz, od ORM, kt\u00f3ry jest wykorzystywany. Jest tam bardzo wiele ustawie\u0144. Je\u015bli masz w\u0142\u0105czony auto commit on, to transakcja si\u0119 rozpoczyna i zaraz zamyka.<\/p>\n<p><\/p>\n<p><em>Tzn. zamyka si\u0119 ona zaraz po aktualizacji?<\/em><\/p>\n<p><\/p>\n<p>To zale\u017cy od ustawie\u0144. Jedno ustawienie, o kt\u00f3rym wspomnia\u0142em, to auto commit on. Jest to do\u015b\u0107 powszechne. Je\u015bli jest w\u0142\u0105czone, to transakcja otwiera si\u0119 i zamyka. Je\u015bli nie powiedzia\u0142e\u015b jawnie \u201estart transaction\u201d i \u201eend transaction\u201d, tylko po prostu uruchomi\u0142e\u015b zapytanie w sesji. <\/p>\n<p><\/p>\n<p><em>Dzie\u0144 dobry! Dzi\u0119kuj\u0119 za prezentacj\u0119! Za\u0142\u00f3\u017cmy, \u017ce mamy baz\u0119, kt\u00f3ra ro\u015bnie ro\u015bnie, a na serwerze ko\u0144czy si\u0119 miejsce. Czy s\u0105 jakie\u015b narz\u0119dzia, kt\u00f3re mog\u0105 rozwi\u0105za\u0107 t\u0119 sytuacj\u0119?<\/em> <\/p>\n<p><\/p>\n<p>Miejsce na serwerze naprawd\u0119 trzeba monitorowa\u0107. <\/p>\n<p><\/p>\n<p><em>Na przyk\u0142ad DBA poszed\u0142 pi\u0107 herbat\u0119, by\u0142 na wakacjach itd.<\/em><\/p>\n<p><\/p>\n<p>Kiedy tworzony jest system plik\u00f3w, minimalnie tworzone jest jakie\u015b miejsce rezerwowe, do kt\u00f3rego nie s\u0105 zapisywane dane. <\/p>\n<p><\/p>\n<p><em>A je\u015bli ca\u0142kowicie do zera?<\/em><\/p>\n<p><\/p>\n<p>To nazywa si\u0119 przestrzeni\u0105 zarezerwowan\u0105, tj. mo\u017cna j\u0105 zwolni\u0107, a w zale\u017cno\u015bci od tego, jak du\u017c\u0105 j\u0105 stworzono, otrzymujesz wolne miejsce. Domy\u015blnie nie wiem, ile tego jest. A w innym przypadku \u2013 dostarczy\u0107 dyski, aby\u015b mia\u0142 miejsce na wykonanie operacji przywracania. Mo\u017cna usun\u0105\u0107 jak\u0105\u015b tabel\u0119, kt\u00f3ra na pewno nie jest potrzebna. <\/p>\n<p><\/p>\n<p><em>Nie ma innych narz\u0119dzi?<\/em><\/p>\n<p><\/p>\n<p>To zawsze jest praca r\u0119czna. I na miejscu ustala si\u0119, co najlepiej zrobi\u0107, poniewa\u017c s\u0105 dane krytyczne i niekrytyczne. I dla ka\u017cdej bazy i aplikacji, kt\u00f3ra z ni\u0105 pracuje, zale\u017cy to od biznesu. Zawsze rozwi\u0105zuje si\u0119 to na miejscu. <\/p>\n<p><\/p>\n<p><em>Dzi\u0119kuj\u0119 za wyk\u0142ad! Mam dwa pytania. Po pierwsze, pokazywa\u0142e\u015b slajdy, na kt\u00f3rych widzieli\u015bmy, \u017ce w przypadku zawieszonych transakcji ro\u015bnie zar\u00f3wno obj\u0119to\u015b\u0107 przestrzeni tabeli, jak i rozmiar indeksu. A co z indeksem?<\/em><\/p>\n<p><\/p>\n<p>One r\u00f3wnie\u017c pakuj\u0105 je. <\/p>\n<p><\/p>\n<p><em>Ale wakuum nie dotyczy indeksu?<\/em><\/p>\n<p><\/p>\n<p>Niekt\u00f3re dzia\u0142aj\u0105 z indeksem. Na przyk\u0142ad pg_rapack, pgcompacttable. Wakuum rekreuje indeksy, dotyka ich. Istota VACUUM FULL polega na tym, aby wszystko przepisano, tj. dzia\u0142a ze wszystkimi. <\/p>\n<p><\/p>\n<p><em>I drugie pytanie. Nie zrozumia\u0142em, dlaczego raporty na replikach tak bardzo zale\u017c\u0105 od samej replikacji. Wydawa\u0142o mi si\u0119, \u017ce raporty to czytanie, a replikacja to zapis.<\/em> <\/p>\n<p><\/p>\n<p>Gdzie wyst\u0119puje konflikt replikacji? Mamy Mastera, na kt\u00f3rym przebiegaj\u0105 procesy. Mamy autowakuum. Co w\u0142a\u015bciwie robi autowakuum? Usuwa jakie\u015b stare wiersze. Je\u015bli w tym czasie na replikacji jest zapytanie, kt\u00f3re odczytuje te stare wiersze, a na Masterze wyst\u0105pi\u0142a sytuacja, \u017ce autowakuum oznaczy\u0142 te wiersze jako mo\u017cliwe do przepisania, to je przepisujemy. I przychodzi pakiet danych, kiedy musimy przepisze wiersze, kt\u00f3re s\u0105 potrzebne zapytaniu na replikacji, proces replikacji poczeka na ten ustawiony przez ciebie timeout. A potem PostgreSQL zdecyduje, co jest dla niego wa\u017cniejsze. A replikacja jest dla niego wa\u017cniejsza ni\u017c zapytanie i odrzuci zapytanie, aby wykona\u0107 te zmiany na replikacji. <\/p>\n<p><\/p>\n<p><em>Andrzej, mam pytanie. Czy te niesamowite wykresy, kt\u00f3re pokazywa\u0142e\u015b podczas prezentacji, to efekt pracy jakiej\u015b Twojej aplikacji? Jak stworzy\u0142e\u015b te wykresy?<\/em><\/p>\n<p><\/p>\n<p>To jest serwis <noindex><a rel=\"nofollow\" href=\"https:\/\/okmeter.io\/\">Okmeter<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p><em>Czy to jest produkt komercyjny?<\/em><\/p>\n<p><\/p>\n<p>Tak. To jest produkt komercyjny.<\/p>\n<p>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/501040\/\">habr.com<\/a> <\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0418 \u0432\u043e\u0437\u044c\u043c\u0443 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 Postgresql. \u041a\u0430\u043a \u043f\u0440\u0430\u0432\u0438\u043b\u043e, \u044d\u0442\u043e \u043d\u0430\u0447\u0430\u043b\u043e \u043a\u043e\u043d\u0446\u0430 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":81090,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-81089","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"pl_PL\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql. \u0410\u043d\u0434\u0440\u0435\u0439 \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432 | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2020-05-10T23:42:24+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-05-10T23:42:24+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql. Andrzej Sa\u0142nikow | ProHoster","description":"Prosz\u0119 zapozna\u0107 si\u0119 z transkrypcj\u0105 prezentacji z pocz\u0105tku 2016 roku Andrzeja Sa\u0142nikowa \"Typowe b\u0142\u0119dy w aplikacjach prowadz\u0105ce do bloat w postgresql\" W tej prezentacji om\u00f3wi\u0119 najwa\u017cniejsze.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pl_PL","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql. \u0410\u043d\u0434\u0440\u0435\u0439 \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432 | ProHoster","og:description":"\u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u0442\u044c\u0441\u044f \u0441 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u043e\u0439 \u0434\u043e\u043a\u043b\u0430\u0434\u0430 \u043d\u0430\u0447\u0430\u043b\u0430 2016 \u0433\u043e\u0434\u0430 \u0410\u043d\u0434\u0440\u0435\u044f \u0421\u0430\u043b\u044c\u043d\u0438\u043a\u043e\u0432\u0430 &quot;\u0422\u0438\u043f\u043e\u0432\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432\u0435\u0434\u0443\u0442 \u043a bloat \u0432 postgresql&quot; \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0434\u043e\u043a\u043b\u0430\u0434\u0435 \u044f \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/tipovye-oshibki-v-prilozheniyah-kotorye-vedut-k-bloat-v-postgresql-andrej-salnikov","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2020-05-10T23:42:24+00:00","article:modified_time":"2020-05-10T23:42:24+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"81089","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 16:05:22","updated":"2022-09-27 16:01:50","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/81089","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/comments?post=81089"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/81089\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/81090"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=81089"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=81089"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=81089"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}