{"id":34419,"date":"2019-10-31T21:58:13","date_gmt":"2019-10-31T18:58:13","guid":{"rendered":"https:\/\/prohoster.info\/blog\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql\/"},"modified":"2019-10-31T21:58:13","modified_gmt":"2019-10-31T18:58:13","slug":"ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql","title":{"rendered":"Wykorzystujemy wszystkie mo\u017cliwo\u015bci indeks\u00f3w w PostgreSQL","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Wykorzystujemy wszystkie mo\u017cliwo\u015bci indeks\u00f3w w PostgreSQL\" src=\"\/wp-content\/uploads\/2019\/05\/34a92715e0cfaff2519d1aea460592ea.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\nW \u015bwiecie Postgres indeksy s\u0105 niezwykle wa\u017cne dla efektywnej nawigacji po magazynie bazy danych (nazywanym \u201ekup\u0105\u201d, heap). Postgres nie wspiera dla niego klasteryzacji, a architektura MVCC prowadzi do gromadzenia wielu wersji tego samego krotki. Dlatego bardzo wa\u017cne jest umiej\u0119tne tworzenie i utrzymywanie efektywnych indeks\u00f3w wspieraj\u0105cych aplikacje.<\/p>\n<p>Przedstawiam kilka wskaz\u00f3wek dotycz\u0105cych optymalizacji i poprawy wykorzystania indeks\u00f3w.<\/p>\n<p><i>Uwaga: przedstawione poni\u017cej zapytania dzia\u0142aj\u0105 na niezmodyfikowanym <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/devrimgunduz\/pagila\">przyk\u0142adzie bazy danych pagila<\/a><\/noindex>.<\/i><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h3>Wykorzystanie indeks\u00f3w pokrywaj\u0105cych (Covering Indexes)<\/h3>\n<p>\nRozwa\u017cmy zapytanie o wyci\u0105ganie adres\u00f3w e-mail dla nieaktywnych u\u017cytkownik\u00f3w. W tabeli <code>customer<\/code> jest kolumna <code>active<\/code>, a zapytanie jest stosunkowo proste:<\/p>\n<pre><code class=\"sql\">pagila=# EXPLAIN SELECT email FROM customer WHERE active=0;\n                        PLAN ZAPYTANIA\n-----------------------------------------------------------\n Sekwencyjne skanowanie na customer  (koszt=0.00..16.49 wierszy=15 szeroko\u015b\u0107=32)\n   Filtr: (active = 0)\n(2 wiersze)<\/code><\/pre>\n<p>\nW zapytaniu nast\u0119puje pe\u0142ne sekwencyjne skanowanie tabeli. <code>customer<\/code>Stw\u00f3rzmy indeks dla kolumny <code>active<\/code>:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_cust1 ON customer(active);\nCREATE INDEX\npagila=# EXPLAIN SELECT email FROM customer WHERE active=0;\n                                 PLAN ZAPYTANIA\n-----------------------------------------------------------------------------\n Skanowanie indeksu za pomoc\u0105 idx_cust1 na customer  (koszt=0.28..12.29 wierszy=15 szeroko\u015b\u0107=32)\n   Warunek Indeksu: (active = 0)\n(2 wiersze)<\/code><\/pre>\n<p>\nPomog\u0142o, kolejne skanowanie sta\u0142o si\u0119 &#171;<code>skanowanie indeksu<\/code>&#171;. To oznacza, \u017ce Postgres przeskanuje indeks &#171;<code>idx_cust1<\/code>&#171;, a nast\u0119pnie kontynuuje poszukiwania w tabeli, aby przeczyta\u0107 warto\u015bci innych kolumn (w tym przypadku kolumny <code>email<\/code>), kt\u00f3re s\u0105 potrzebne zapytaniu.<\/p>\n<p>W PostgreSQL 11 pojawi\u0142y si\u0119 indeksy pokrywaj\u0105ce. Dzi\u0119ki nim mo\u017cna w\u0142\u0105czy\u0107 do samego indeksu jedn\u0105 lub wi\u0119cej dodatkowych kolumn \u2014 ich warto\u015bci s\u0105 przechowywane w magazynie danych indeksu.<\/p>\n<p>Gdyby\u015bmy skorzystali z tej mo\u017cliwo\u015bci i dodali warto\u015b\u0107 e-maila do indeksu, to Postgres nie musia\u0142by szuka\u0107 w kupie tabeli warto\u015bci <code>email<\/code>. Zobaczmy, czy to zadzia\u0142a:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_cust2 ON customer(active) INCLUDE (email);\nCREATE INDEX\npagila=# EXPLAIN SELECT email FROM customer WHERE active=0;\n                                    PLAN ZAPYTANIA\n----------------------------------------------------------------------------------\n Skanowanie tylko indeksu u\u017cywaj\u0105c idx_cust2 na customer  (koszt=0.28..12.29 wierszy=15 szeroko\u015b\u0107=32)\n   Warunek Indeksu: (active = 0)\n(2 wiersze)<\/code><\/pre>\n<p>\n&#171;<code>Skanowanie tylko indeksu<\/code>&#187; m\u00f3wi nam, \u017ce zapytanie teraz wymaga jedynie indeksu, co pomaga unika\u0107 wszystkich operacji wej\u015bcia\/wyj\u015bcia na dysku w celu odczytu tabeli.<\/p>\n<p>Obecnie indeksy pokrywaj\u0105ce s\u0105 dost\u0119pne tylko dla drzew B. Jednak w tym przypadku koszty utrzymania b\u0119d\u0105 wy\u017csze.<\/p>\n<h3>U\u017cycie indeks\u00f3w cz\u0119\u015bciowych<\/h3>\n<p>\nIndeksy cz\u0119\u015bciowe indeksuj\u0105 tylko podzbi\u00f3r wierszy tabeli. Pozwala to zaoszcz\u0119dzi\u0107 miejsce na indeksach i przyspieszy\u0107 skanowanie.<\/p>\n<p>Za\u0142\u00f3\u017cmy, \u017ce musimy uzyska\u0107 list\u0119 adres\u00f3w e-mail naszych klient\u00f3w z Kalifornii. Zapytanie b\u0119dzie wygl\u0105da\u0107 tak:<\/p>\n<pre><code class=\"sql\">SELECT c.email FROM customer c\nJOIN address a ON c.address_id = a.address_id\nWHERE a.district = 'California';\nkt\u00f3re ma plan zapytania obejmuj\u0105cy skanowanie obu po\u0142\u0105czonych tabel:\npagila=# EXPLAIN SELECT c.email FROM customer c\npagila-# JOIN address a ON c.address_id = a.address_id\npagila-# WHERE a.district = 'California';\n                              PLAN ZAPYTANIA\n----------------------------------------------------------------------\n Wewn\u0119trzne po\u0142\u0105czenie  (koszt=15.65..32.22 wierszy=9 szeroko\u015b\u0107=32)\n   Warunek skr\u00f3tu: (c.address_id = a.address_id)\n   -&gt;  Skanowanie sekwencyjne na customer c  (koszt=0.00..14.99 wierszy=599 szeroko\u015b\u0107=34)\n   -&gt;  Skr\u00f3t  (koszt=15.54..15.54 wierszy=9 szeroko\u015b\u0107=4)\n         -&gt;  Skanowanie sekwencyjne na address a  (koszt=0.00..15.54 wierszy=9 szeroko\u015b\u0107=4)\n               Filtr: (district = 'California'::text)\n(6 wierszy)<\/code><\/pre>\n<p>\nCo nam dadz\u0105 zwyk\u0142e indeksy:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_address1 ON address(district);\nINDeks zosta\u0142 utworzony\npagila=# EXPLAIN SELECT c.email FROM customer c\npagila-# JOIN address a ON c.address_id = a.address_id\npagila-# WHERE a.district = 'California';\n                                      PLAN ZAPYTANIA\n---------------------------------------------------------------------------------------\n Wewn\u0119trzne po\u0142\u0105czenie  (koszt=12.98..29.55 wierszy=9 szeroko\u015b\u0107=32)\n   Warunek skr\u00f3tu: (c.address_id = a.address_id)\n   -&gt;  Skanowanie sekwencyjne na customer c  (koszt=0.00..14.99 wierszy=599 szeroko\u015b\u0107=34)\n   -&gt;  Skr\u00f3t  (koszt=12.87..12.87 wierszy=9 szeroko\u015b\u0107=4)\n         -&gt;  Skanowanie bitmapy na address a  (koszt=4.34..12.87 wierszy=9 szeroko\u015b\u0107=4)\n               Ponowne sprawdzenie warunku: (district = 'California'::text)\n               -&gt;  Skanowanie indeksu bitmapy na idx_address1  (koszt=0.00..4.34 wierszy=9 szeroko\u015b\u0107=0)\n                     Warunek indeksu: (district = 'California'::text)\n(8 wierszy)<\/code><\/pre>\n<p>\nSkanowanie <code>address<\/code> zosta\u0142o zast\u0105pione skanowaniem indeksu <code>idx_address1<\/code>, a nast\u0119pnie przeskanowano kopi\u0119 <code>address<\/code>.<\/p>\n<p>Poniewa\u017c jest to cz\u0119ste zapytanie i musi by\u0107 zoptymalizowane, mo\u017cemy u\u017cy\u0107 indeksu cz\u0119\u015bciowego, kt\u00f3ry indeksuje tylko te wiersze z adresami, w kt\u00f3rych dzielnica <code>\u2018California\u2019<\/code>:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_address2 ON address(address_id) WHERE district='California';\nINDeks zosta\u0142 utworzony\npagila=# EXPLAIN SELECT c.email FROM customer c\npagila-# JOIN address a ON c.address_id = a.address_id\npagila-# WHERE a.district = 'California';\n                                           PLAN ZAPYTANIA\n------------------------------------------------------------------------------------------------\n Wewn\u0119trzne po\u0142\u0105czenie  (koszt=12.38..28.96 wierszy=9 szeroko\u015b\u0107=32)\n   Warunek skr\u00f3tu: (c.address_id = a.address_id)\n   -&gt;  Skanowanie sekwencyjne na customer c  (koszt=0.00..14.99 wierszy=599 szeroko\u015b\u0107=34)\n   -&gt;  Skr\u00f3t  (koszt=12.27..12.27 wierszy=9 szeroko\u015b\u0107=4)\n         -&gt;  Skanowanie tylko indeks\u00f3w, korzystaj\u0105c z idx_address2 na address a  (koszt=0.14..12.27 wierszy=9 szeroko\u015b\u0107=4)\n(5 wierszy)<\/code><\/pre>\n<p>\nTeraz zapytanie odczytuje tylko <code>idx_address2<\/code> i nie dotyka tabeli <code>address<\/code>.<\/p>\n<h3>U\u017cycie indeks\u00f3w wielowarto\u015bciowych (Multi-Value Indexes)<\/h3>\n<p>\nNiekt\u00f3re kolumny, kt\u00f3re trzeba zindeksowa\u0107, mog\u0105 nie zawiera\u0107 typu danych skalarnego. Typy kolumn takie jak <code>jsonb<\/code>, <code>tablice<\/code> i <code>tsvector<\/code> mog\u0105 zawiera\u0107 warto\u015bci z\u0142o\u017cone lub mnogie. Je\u015bli musisz zindeksowa\u0107 takie kolumny, zazwyczaj trzeba przeszuka\u0107 wszystkie pojedyncze warto\u015bci w tych kolumnach.<\/p>\n<p>Spr\u00f3bujemy znale\u017a\u0107 tytu\u0142y wszystkich film\u00f3w, zawieraj\u0105cych sceny z nieudanych dubli. W tabeli <code>film<\/code> jest kolumna tekstowa, nazywana <code>special_features<\/code>. Je\u015bli film ma to \u201especjalne w\u0142a\u015bciwo\u015b\u0107\u201d, to w kolumnie znajduje si\u0119 element w postaci tablicy tekstowej <code>Behind The Scenes<\/code>. Aby znale\u017a\u0107 wszystkie takie filmy, musimy wybra\u0107 wszystkie wiersze z \u201eBehind The Scenes\u201d przy <b>wszystkich <\/b>warto\u015bci tablicy <code>special_features<\/code>:<\/p>\n<pre><code class=\"sql\">SELECT title FROM film WHERE special_features @&gt; '{\"Behind The Scenes\"}';<\/code><\/pre>\n<p>\nOperator kontentu (containment operator) <code>@&gt;<\/code> sprawdza, czy prawa strona jest podzbiorem lewej strony.<\/p>\n<p>Plan zapytania:<\/p>\n<pre><code class=\"sql\">pagila=# EXPLAIN SELECT title FROM film\npagila-# WHERE special_features @&gt; '{\"Behind The Scenes\"}';\n                           QUERY PLAN\n-----------------------------------------------------------------\n Seq Scan on film  (cost=0.00..67.50 rows=5 width=15)\n   Filter: (special_features @&gt; '{\"Behind The Scenes\"}'::text[])\n(2 rows)<\/code><\/pre>\n<p>\nKt\u00f3ry \u017c\u0105da pe\u0142nego skanowania heapu o koszcie 67.<\/p>\n<p>Zobaczmy, czy zwyk\u0142y indeks B-drzewa nam pomo\u017ce:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_film1 ON film(special_features);\nCREATE INDEX\npagila=# EXPLAIN SELECT title FROM film\npagila-# WHERE special_features @&gt; '{\"Behind The Scenes\"}';\n                           QUERY PLAN\n-----------------------------------------------------------------\n Seq Scan on film  (cost=0.00..67.50 rows=5 width=15)\n   Filter: (special_features @&gt; '{\"Behind The Scenes\"}'::text[])\n(2 rows)<\/code><\/pre>\n<p>\nIndeks nawet nie zosta\u0142 rozwa\u017cony. Indeks B-drzewa nie ma poj\u0119cia o istnieniu pojedynczych element\u00f3w w indeksowanych warto\u015bciach.<\/p>\n<p>Potrzebujemy indeksu GIN.<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX idx_film2 ON film USING GIN(special_features);\nCREATE INDEX\npagila=# EXPLAIN SELECT title FROM film\npagila-# WHERE special_features @&gt; '{\"Behind The Scenes\"}';\n                                QUERY PLAN\n---------------------------------------------------------------------------\n Bitmap Heap Scan on film  (cost=8.04..23.58 rows=5 width=15)\n   Recheck Cond: (special_features @&gt; '{\"Behind The Scenes\"}'::text[])\n   -&gt;  Bitmap Index Scan on idx_film2  (cost=0.00..8.04 rows=5 width=0)\n         Index Cond: (special_features @&gt; '{\"Behind The Scenes\"}'::text[])\n(4 rows)<\/code><\/pre>\n<p>\nIndeks GIN wspiera dopasowywanie pojedynczych warto\u015bci do indeksowanych warto\u015bci z\u0142o\u017conych, co skutkuje tym, \u017ce koszt planu zapytania zmniejszy si\u0119 o ponad po\u0142ow\u0119.<\/p>\n<h3>Pozbywamy si\u0119 duplikacji indeks\u00f3w.<\/h3>\n<p>\nIndeksy gromadz\u0105 si\u0119 z czasem i czasami nowy indeks mo\u017ce zawiera\u0107 t\u0119 sam\u0105 definicj\u0119, co jeden z wcze\u015bniejszych. Aby uzyska\u0107 czytelne dla cz\u0142owieka definicje SQL indeks\u00f3w, mo\u017cna u\u017cy\u0107 widoku katalogu <code>pg_indexes<\/code>. Mo\u017cesz te\u017c \u0142atwo znale\u017a\u0107 identyczne definicje:<\/p>\n<pre><code class=\"sql\"> SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn\n    FROM pg_indexes\nGROUP BY defn\n  HAVING count(*) &gt; 1;\nA oto wynik po uruchomieniu na domy\u015blnej bazie danych pagila:\npagila=#   SELECT array_agg(indexname) AS indexes, replace(indexdef, indexname, '') AS defn\npagila-#     FROM pg_indexes\npagila-# GROUP BY defn\npagila-#   HAVING count(*) &gt; 1;\n                                indexes                                 |                                defn\n------------------------------------------------------------------------+------------------------------------------------------------------\n {payment_p2017_01_customer_id_idx,idx_fk_payment_p2017_01_customer_id} | CREATE INDEX  ON public.payment_p2017_01 USING btree (customer_id\n {payment_p2017_02_customer_id_idx,idx_fk_payment_p2017_02_customer_id} | CREATE INDEX  ON public.payment_p2017_02 USING btree (customer_id\n {payment_p2017_03_customer_id_idx,idx_fk_payment_p2017_03_customer_id} | CREATE INDEX  ON public.payment_p2017_03 USING btree (customer_id\n {idx_fk_payment_p2017_04_customer_id,payment_p2017_04_customer_id_idx} | CREATE INDEX  ON public.payment_p2017_04 USING btree (customer_id\n {payment_p2017_05_customer_id_idx,idx_fk_payment_p2017_05_customer_id} | CREATE INDEX  ON public.payment_p2017_05 USING btree (customer_id\n {idx_fk_payment_p2017_06_customer_id,payment_p2017_06_customer_id_idx} | CREATE INDEX  ON public.payment_p2017_06 USING btree (customer_id\n(6 rows)\n<\/code><\/pre>\n<p><\/p>\n<h3>Indeksy nadmuj\u0105ce (Superset Indexes)<\/h3>\n<p>\nMo\u017ce si\u0119 zdarzy\u0107, \u017ce zgromadzisz wiele indeks\u00f3w, z kt\u00f3rych jeden indeksuje nadzbiory kolumn, kt\u00f3re indeksuj\u0105 inne indeksy. Mo\u017ce to by\u0107 zar\u00f3wno korzystne, jak i nie \u2014 nadzbi\u00f3r mo\u017ce prowadzi\u0107 do skanowania tylko po indeksach, co jest dobre, ale mo\u017ce zajmowa\u0107 zbyt du\u017co miejsca, lub zapytanie, dla kt\u00f3rego to nadzbiory mia\u0142y by\u0107 zoptymalizowane, ju\u017c nie jest u\u017cywane.<\/p>\n<p>Je\u015bli musisz zautomatyzowa\u0107 okre\u015blanie takich indeks\u00f3w, to mo\u017cna zacz\u0105\u0107 od <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/catalog-pg-index.html\">pg_index<\/a><\/noindex> z tabeli <code>pg_catalog<\/code>.<\/p>\n<h3>Nieczytelne indeksy<\/h3>\n<p>\nW miar\u0119 jak rozwijaj\u0105 si\u0119 aplikacje korzystaj\u0105ce z baz danych, rozwijaj\u0105 si\u0119 r\u00f3wnie\u017c wykorzystywane przez nie zapytania. Indeksy dodane wcze\u015bniej mog\u0105 ju\u017c nie by\u0107 u\u017cywane przez \u017cadne zapytanie. Przy ka\u017cdym skanowaniu indeksu jest on oznaczany przez mened\u017cera statystyk, a w widoku katalogu systemowego <code>pg_stat_user_indexes<\/code> mo\u017cna sprawdzi\u0107 warto\u015b\u0107 <code>idx_scan<\/code>, kt\u00f3ra jest kumulatywnym licznikiem. Monitorowanie tej warto\u015bci przez pewien okres czasu (na przyk\u0142ad miesi\u0105c) da dobry obraz tego, kt\u00f3re indeksy nie s\u0105 u\u017cywane i mog\u0105 by\u0107 usuni\u0119te.<\/p>\n<p>Oto zapytanie o uzyskanie bie\u017c\u0105cych licznik\u00f3w skanowania wszystkich indeks\u00f3w w schemacie <code>'public'<\/code>:<\/p>\n<pre><code class=\"sql\">SELECT relname, indexrelname, idx_scan\nFROM   pg_catalog.pg_stat_user_indexes\nWHERE  schemaname = 'public';\nwyj\u015bcie powinno wygl\u0105da\u0107 nast\u0119puj\u0105co:\npagila=# SELECT relname, indexrelname, idx_scan\npagila-# FROM   pg_catalog.pg_stat_user_indexes\npagila-# WHERE  schemaname = 'public'\npagila-# LIMIT  10;\n    relname    |    indexrelname    | idx_scan\n---------------+--------------------+----------\n customer      | customer_pkey      |    32093\n actor         | actor_pkey         |     5462\n address       | address_pkey       |      660\n category      | category_pkey      |     1000\n city          | city_pkey          |      609\n country       | country_pkey       |      604\n film_actor    | film_actor_pkey    |        0\n film_category | film_category_pkey |        0\n film          | film_pkey          |    11043\n inventory     | inventory_pkey     |    16048\n(10 wierszy)<\/code><\/pre>\n<p><\/p>\n<h3>Rekreacja indeks\u00f3w z mniejsz\u0105 liczb\u0105 blokad<\/h3>\n<p>\nCz\u0119sto konieczne jest rekreowanie indeks\u00f3w, na przyk\u0142ad gdy si\u0119 powi\u0119kszaj\u0105, a rekreacja mo\u017ce przyspieszy\u0107 skanowanie. Indeksy mog\u0105 r\u00f3wnie\u017c ulega\u0107 uszkodzeniu. Zmiana parametr\u00f3w indeksu mo\u017ce r\u00f3wnie\u017c wymaga\u0107 jego rekreacji.<\/p>\n<h3>W\u0142\u0105czamy r\u00f3wnoleg\u0142e tworzenie indeks\u00f3w<\/h3>\n<p>\nW PostgreSQL 11 tworzenie indeksu B-Tree jest konkurencyjne. Aby przyspieszy\u0107 proces tworzenia, mo\u017cna wykorzysta\u0107 kilku r\u00f3wnolegle dzia\u0142aj\u0105cych pracownik\u00f3w. Upewnij si\u0119 jednak, \u017ce te parametry konfiguracyjne s\u0105 ustawione poprawnie:<\/p>\n<pre><code class=\"sql\">SET max_parallel_workers = 32;\nSET max_parallel_maintenance_workers = 16;<\/code><\/pre>\n<p>\nWarto\u015bci domy\u015blne s\u0105 zbyt ma\u0142e. Idealnie, te liczby powinny by\u0107 zwi\u0119kszane wraz z liczb\u0105 rdzeni procesora. Wi\u0119cej informacji znajdziesz w <noindex><a rel=\"nofollow\" href=\"https:\/\/www.postgresql.org\/docs\/current\/runtime-config-resource.html#RUNTIME-CONFIG-RESOURCE-ASYNC-BEHAVIOR\">dokumentacji<\/a><\/noindex>.<\/p>\n<h3>Tworzenie indeks\u00f3w w tle<\/h3>\n<p>\nMo\u017cesz stworzy\u0107 indeks w tle, korzystaj\u0105c z parametru <code>CONCURRENTLY<\/code> polece\u0144 <code>CREATE INDEX<\/code>:<\/p>\n<pre><code class=\"sql\">pagila=# CREATE INDEX CONCURRENTLY idx_address1 ON address(district);\nCREATE INDEX<\/code><\/pre>\n<p>Ta procedura tworzenia indeksu r\u00f3\u017cni si\u0119 od zwyk\u0142ej tym, \u017ce nie wymaga blokowania tabeli, co oznacza, \u017ce nie blokuje operacji zapisu. Z drugiej strony zajmuje wi\u0119cej czasu i zu\u017cywa wi\u0119cej zasob\u00f3w.<\/p>\n<p>Postgres oferuje wiele elastycznych mo\u017cliwo\u015bci tworzenia indeks\u00f3w oraz rozwi\u0105zywania wszelkich szczeg\u00f3lnych przypadk\u00f3w, a tak\u017ce zapewnia sposoby zarz\u0105dzania baz\u0105 danych na wypadek gwa\u0142townie rosn\u0105cej popularno\u015bci twojej aplikacji. Mamy nadziej\u0119, \u017ce te wskaz\u00f3wki pomog\u0105 ci przyspieszy\u0107 zapytania i przygotowa\u0107 baz\u0119 do skalowania.<br \/>\n<br \/>\u0179r\u00f3d\u0142o: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/mailru\/blog\/453046\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u043c\u0438\u0440\u0435 Postgres \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043a\u0440\u0430\u0439\u043d\u0435 \u0432\u0430\u0436\u043d\u044b \u0434\u043b\u044f \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u043d\u0430\u0432\u0438\u0433\u0430\u0446\u0438\u0438 \u043f\u043e \u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0443 \u0431\u0430\u0437\u044b \u0434\u0430\u043d\u043d\u044b\u0445 (\u0435\u0433\u043e \u043d\u0430\u0437\u044b\u0432\u0430\u044e\u0442 \u00ab\u043a\u0443\u0447\u0430\u00bb, heap). Postgres \u043d\u0435 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0434\u043b\u044f \u043d\u0435\u0433\u043e \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e, \u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 MVCC \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u0442\u043e\u043c\u0443, \u0447\u0442\u043e \u0443 \u0432\u0430\u0441 \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043c\u043d\u043e\u0433\u043e \u0432\u0435\u0440\u0441\u0438\u0439 \u043e\u0434\u043d\u043e\u0433\u043e \u0438 \u0442\u043e\u0433\u043e \u0436\u0435 \u043a\u043e\u0440\u0442\u0435\u0436\u0430. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043e\u0447\u0435\u043d\u044c \u0432\u0430\u0436\u043d\u043e \u0443\u043c\u0435\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u0441\u043e\u043f\u0440\u043e\u0432\u043e\u0436\u0434\u0430\u0442\u044c \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u0434\u043b\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0432\u0430\u0448\u0435\u043c\u0443 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u044e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":25931,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-34419","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=\"\u0412 \u043c\u0438\u0440\u0435 Postgres \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043a\u0440\u0430\u0439\u043d\u0435 \u0432\u0430\u0436\u043d\u044b \u0434\u043b\u044f.\" \/>\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\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql\" \/>\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\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432 \u0432 PostgreSQL | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412 \u043c\u0438\u0440\u0435 Postgres \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043a\u0440\u0430\u0439\u043d\u0435 \u0432\u0430\u0436\u043d\u044b \u0434\u043b\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql\" \/>\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=\"2019-10-31T18:58:13+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:58:13+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\udd47Wykorzystujemy wszystkie mo\u017cliwo\u015bci indeks\u00f3w w PostgreSQL | ProHoster","description":"W \u015bwiecie Postgresa indeksy s\u0105 niezwykle wa\u017cne dla.","canonical_url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql","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\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432\u0441\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0438\u043d\u0434\u0435\u043a\u0441\u043e\u0432 \u0432 PostgreSQL | ProHoster","og:description":"\u0412 \u043c\u0438\u0440\u0435 Postgres \u0438\u043d\u0434\u0435\u043a\u0441\u044b \u043a\u0440\u0430\u0439\u043d\u0435 \u0432\u0430\u0436\u043d\u044b \u0434\u043b\u044f.","og:url":"https:\/\/prohoster.info\/pl\/blog\/administrirovanie\/ispolzuem-vse-vozmozhnosti-indeksov-v-postgresql","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":"2019-10-31T18:58:13+00:00","article:modified_time":"2019-10-31T18:58:13+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"34419","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":"2026-01-21 19:13:20","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 13:52:22","updated":"2026-01-21 19:13:20","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\/34419","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=34419"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/posts\/34419\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media\/25931"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/media?parent=34419"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/categories?post=34419"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pl\/wp-json\/wp\/v2\/tags?post=34419"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}