Praktický návod

Jak vytvořit správné indexy v PostgreSQL

Index nenavrhuj podle názvu sloupce. Navrhni ho podle konkrétního filtru, řazení a objemu dat.

25 minut · PostgreSQL

Nejdřív stručně

Index je zrychlení za určitou cenu

Databázový index pomáhá PostgreSQL najít a seřadit řádky bez procházení celé tabulky. Každý index ale zabírá místo a zpomaluje INSERT, UPDATE i DELETE.

Správný index vychází ze skutečného SQL dotazu. Pořadí sloupců, podmínka částečného indexu i zahrnuté hodnoty musí odpovídat tomu, co aplikace opravdu filtruje a vrací.

Připrav si

Co budeš potřebovat

Nejdřív vyber pomalý nebo často volaný dotaz. Index bez konkrétního dotazu nemá ověřitelný cíl.

  • Přesné SQL včetně WHERE, JOIN, ORDER BY a LIMIT, ideálně z produkčních statistik.
  • Reprezentativní objem a rozložení dat. Index nad tisícem testovacích řádků může vypadat jinak než nad miliony.
  • Výstup EXPLAIN (ANALYZE, BUFFERS) před změnou a očekávaný čas odezvy.
  • Přehled existujících indexů a možnost sledovat jejich velikost i použití po nasazení.

Kroky 1 až 3

Navrhni index od dotazu

Začni běžným B-tree indexem. Specializovaný typ použij až tehdy, když odpovídá operátorům konkrétního dotazu.

1. Přečti filtr a řazení

  1. Najdi sloupce porovnávané rovností, rozsahem a JOINem. Ověř také ORDER BY a zda dotaz vrací jen malou část tabulky.
  2. Sekvenční scan není automaticky chyba. Pro velkou část malé tabulky může být levnější než skákání přes index.
  3. Porovnej odhadované a skutečné řádky. Velký rozdíl může znamenat zastaralé statistiky, ne chybějící index.
  4. Zapiš výchozí execution time, počet bufferů a počet vrácených řádků.
EXPLAIN (ANALYZE, BUFFERS) SELECT id, total FROM orders WHERE customer_id = 42 AND status = 'paid' ORDER BY created_at DESC LIMIT 20;
Oficiální PostgreSQL dokumentace k EXPLAIN

2. Zvol sloupce a typ indexu

  1. U vícesloupcového B-tree indexu dej zpravidla nejdřív sloupce s rovností, potom rozsah nebo řazení. Ověř to na konkrétním plánu.
  2. Částečný index použij, pokud dotazy opakovaně pracují s malou stabilní podmnožinou, například jen s nezpracovanými objednávkami.
  3. INCLUDE může umožnit index-only scan pro vracené sloupce, ale zvětšuje index. Nezahrnuj automaticky celý řádek.
  4. GIN, GiST nebo BRIN vybírej podle operátorů a dat, ne podle pověsti. B-tree je správný výchozí bod pro rovnost, rozsah a řazení.
CREATE INDEX idx_orders_customer_created ON orders (customer_id, created_at DESC) INCLUDE (total) WHERE status = 'paid';
Oficiální PostgreSQL přehled indexů

3. Vytvoř index bezpečně a změř dopad

  1. Na vytížené produkční tabulce zvaž CREATE INDEX CONCURRENTLY, aby běžné zápisy nebyly blokované po celou dobu sestavení.
  2. CONCURRENTLY nelze spustit uvnitř transakčního bloku a po neúspěchu může zůstat neplatný index. Stav vždy zkontroluj.
  3. Zopakuj stejný EXPLAIN ANALYZE a ověř změnu plánu, bufferů i času. Malý rozdíl nemusí ospravedlnit další index.
  4. Po nasazení sleduj pg_stat_user_indexes, velikost indexu a latenci zápisů. Nepoužívaný index po ověření odstraň.
CREATE INDEX CONCURRENTLY idx_orders_customer_created ON orders (customer_id, created_at DESC) INCLUDE (total) WHERE status = 'paid';
Oficiální dokumentace k CREATE INDEX CONCURRENTLY

Krok 4

Ověř čtení i cenu zápisu

Nový index je užitečný jen tehdy, když pomůže důležitému dotazu a nezpůsobí nepřiměřenou režii jinde.

  1. Porovnej plán před a po změně

    Použij stejná data a parametry. Ověř skutečné řádky, loops, buffery a celkový čas, ne pouze název Index Scan.

    EXPLAIN (ANALYZE, BUFFERS) SELECT ...;
  2. Zkontroluj stav a velikost

    Neplatný nebo překvapivě velký index nepropouštěj dál do deploye.

    SELECT indexrelid::regclass, indisvalid, pg_size_pretty(pg_relation_size(indexrelid)) FROM pg_index WHERE indrelid = 'orders'::regclass;
  3. Změř běžné zápisy

    Porovnej INSERT a UPDATE před změnou a po ní. Sleduj také růst disku a replikační lag.

Když to zlobí

Nejčastější chyby

Planner stále volí Seq Scan

Může to být správně, pokud dotaz vrací velkou část tabulky. Ověř selektivitu, statistiky, datové typy parametrů a skutečný čas obou plánů.

ANALYZE orders;
Vícesloupcový index pomáhá jen některým dotazům

Zkontroluj pořadí sloupců a pravidla levého prefixu. Jeden široký index nenahrazuje různé přístupové vzory.

Po vytvoření indexu se zpomalily zápisy

Každý zápis musí udržovat další strukturu. Odstraň duplicitní a nepoužívané indexy a INCLUDE omez na skutečně potřebné sloupce.

CONCURRENTLY zanechalo neplatný index

Najdi ho přes pg_index.indisvalid, odstraň ho bezpečně a po vyřešení příčiny sestavení zopakuj. Neplatný index nenechávej bez kontroly.

Hotovo

Index má jasný důvod i měřitelný přínos.

Index teď odpovídá konkrétnímu dotazu a jeho dopad je ověřený na čtení i zápis. Stejný postup opakuj před každým dalším CREATE INDEX.

Zavolejte mi

Zavolám vám následující pracovní den mezi 9:00 a 17:00.

Můžete mi také zavolat rovnou.

+420 605 181 728

Nechte mi telefonní číslo a pošlete žádost o zpětné zavolání.

Odesláním souhlasíte se zpracováním údajů pro vyřízení žádosti.