CREATE INDEX (B-Tree, GIN, Partial, CONCURRENTLY) în PostgreSQL

Indecși, performanță și terminalul psql PostgreSQL 9.4+ (INCLUDE din PG 11+, NULLS NOT DISTINCT din PG 15+)

Creează indecși B-Tree, GIN (pentru JSONB și Array), indecși parțiali (WHERE) și indecși pe expresii fără blocarea scrierilor.

Sintaxă SQL
CREATE INDEX CONCURRENTLY idx_nume ON tabel USING gin (coloana_jsonb);nCREATE INDEX idx_partial ON tabel (col) INCLUDE (col_extra) WHERE activ = true;

Ce face CREATE INDEX (B-Tree, GIN, Partial, CONCURRENTLY)

PostgreSQL are unul dintre cele mai bogate sisteme de indexare din lumea bazelor de date. Pe lângă indexul implicit B-Tree (pentru egalități, intervale <, >, BETWEEN și sortări ORDER BY), oferă indecși GIN (Generalized Inverted Index — ideali pentru valori compuse precum JSONB, tablouri ARRAY și căutare full-text), GiST (date geometrice/intervale) și BRIN (tabele uriașe ordonate cronologic).

Mai mult, PostgreSQL suportă indecși parțiali (cu clauza WHERE, care indexează doar un subset de rânduri), indecși pe expresii (ex: LOWER(email)), indecși acoperitori (INCLUDE, pentru Index-Only Scans) și opțiunea CONCURRENTLY, care construiește indexul în producție fără a bloca operațiile INSERT, UPDATE și DELETE.

Clauze, operatori și argumente

Clauză / Operator Descriere
USING btree (implicit) Index echilibrat standard pentru =, <, <=, >, >=, IN, IS NULL și ORDER BY.
USING gin (coloana) Index inversat pentru coloane jsonb (operatorii @>, ?), tablouri ARRAY (@>, &&) și căutare full-text.
CONCURRENTLY Construiește indexul fără a bloca scrierile pe tabel (nu poate fi rulat în interiorul unui bloc BEGIN ... COMMIT).
WHERE conditie Creează un index parțial doar pentru rândurile care satisfac condiția, reducând masiv dimensiunea indexului.
INCLUDE (col1, col2) Atașează coloane suplimentare în frunzele indexului B-Tree pentru a permite Index-Only Scan fără citirea tabelului.
UNIQUE NULLS NOT DISTINCT În PostgreSQL 15+, tratează două valori NULL ca fiind egale într-un index unic.

Exemple

Exemplul 1: Crearea unui index GIN pentru JSONB și a unui index pe expresie (LOWER)

Accelerăm căutările în documentele specificatii cu un index GIN (fără blocarea tabelului prin CONCURRENTLY) și căutările insensibile la majuscule pe email.

CREATE INDEX CONCURRENTLY idx_produse_specificatii_gin
ON produse USING gin (specificatii);

CREATE UNIQUE INDEX CONCURRENTLY idx_utilizatori_email_lower
ON utilizatori (LOWER(email));

Rezultat interogare

CREATE INDEX
CREATE INDEX

Exemplul 2: Index parțial și acoperitor (WHERE + INCLUDE) pentru comenzi active

Dacă 95% din comenzi sunt istorice (livrata) și interogăm frecvent doar comenzile in_procesare, un index parțial ocupă doar 5% din spațiu.

CREATE INDEX CONCURRENTLY idx_comenzi_active_client
ON comenzi (client_id, plasata_la DESC)
INCLUDE (total_lei)
WHERE status = 'in_procesare';

Rezultat interogare

CREATE INDEX

Greșeli frecvente

  • Rularea unui CREATE INDEX simplu (fără CONCURRENTLY) pe un tabel mare în producție: ia un lacăt SHARE care blochează toate comenzile INSERT, UPDATE și DELETE până la terminarea indexării.
  • Dacă un CREATE INDEX CONCURRENTLY eșuează (de exemplu din cauza unui duplicat pe un index UNIQUE), lasă în urmă un index marcat INVALID; verifică cu \d tabel și șterge-l cu DROP INDEX CONCURRENTLY nume_index înainte de a reîncerca.

Comenzi și funcții înrudite

  • EXPLAIN (ANALYZE, BUFFERS): Afișează planul de execuție al optimizatorului, timpii reali pe fiecare nod și blocurile de memorie citite.
  • JSONB și operatorii ->, ->>, @>, ?: Interoghează și filtrează documente binare JSONB folosind operatorii de extracție (->, ->>) și incluziune (@>, ?).
  • VACUUM și ANALYZE: Recuperează spațiul ocupat de rândurile șterse/modificate (MVCC dead tuples) și actualizează statisticile pentru optimizator.