piątek, 25 kwietnia 2014

Instalacja PostgreSQLa ze źródeł v9.3.4

W styczniu opisywałam jak zainstalować i ustawić replikację master-master w MySQL-u (http://db-diary.blogspot.com/2014/01/instalacja-servera-i-replikacji-master.html). Tym razem opiszę jak zainstalować PostgreSQLa i ustawić jego replikację master-slave (PostgreSQL nie ma jeszcze replikacji master-master).

Źródła można pobrać ze strony: http://www.postgresql.org/ftp/source/

Ja chcę zainstalować najwyższą wersję dostępną 9.3.4.
Pierwsze kroki to pobranie i rozpakowanie źródeł:

wget http://ftp.postgresql.org/pub/source/v9.3.4/postgresql-9.3.4.tar.gz
tar -xzf postgresql-9.3.4.tar.gz
cd postgresql-9.3.4

Chce zainstalować PostgreSQLa w dość nietypowej ścieżce bo w katalogu domowym użytkownika postgres, ale najpierw go dodajmy:

sudo adduser postgres
sudo mkdir /home/postgres/psql9.3.4
sudo mkdir /home/postgres/psql9.3.4/data
sudo chown postgres /home/postgres/psql9.3.4/data

Pierwszym krokiem instalacji jest konfiguracja źródeł i wybranie opcji. Służy do tego skrypt configure. Jeśli żadne opcje nie zostaną podane, wybrane zostaną domyślne ścieżki i opcje. Jeśli potrzebujesz pomocy uruchom skrypt z opcją --help. Domyślnie PostgreSQL jest instalowany:
  • w katalogu:  /usr/local/pgsql
  • na porcie 5432
  • z klastrem w katalogu: /usr/local/pgsql/data

./configure --help
./configure --prefix=/usr/local/psql9.3.4 --with-pgport=7432

Zwróć uwagę na wynik działania tego skryptu (WARNINGI i ERRORy). Sprawdza on także czy w twoim systemie są wszystkie biblioteki potrzebne do konfiguracji/instalacji. Być może będzie wymagane aby zainstalować jakieś biblioteki.

Instalacja:

gmake
su
gmake install
su - postgres
/usr/local/psql9.3.4/bin/initdb -D /home/postgres/psql9.3.4/data --username=postgres -W


Pogląd klastra - upewnij się, że są tam pliki konfiguracyjne:

[05:26:30 root@nazgul postgresql-9.3.4] ll /home/postgres/psql9.3.4/data/
razem 100
drwx------ 7 postgres postgres  4096 04-24 05:02 base
drwx------ 2 postgres postgres  4096 04-24 04:43 global
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_clog
-rw------- 1 postgres postgres  4608 04-24 04:46 pg_hba.conf
-rw------- 1 postgres postgres  1636 04-24 03:49 pg_ident.conf
drwx------ 4 postgres postgres  4096 04-24 03:49 pg_multixact
drwx------ 2 postgres postgres  4096 04-24 04:43 pg_notify
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_serial
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_snapshots
drwx------ 2 postgres postgres  4096 04-24 04:43 pg_stat
drwx------ 2 postgres postgres  4096 04-24 05:26 pg_stat_tmp
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_subtrans
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_tblspc
drwx------ 2 postgres postgres  4096 04-24 03:49 pg_twophase
-rw------- 1 postgres postgres     4 04-24 03:49 PG_VERSION
drwx------ 3 postgres postgres  4096 04-24 03:49 pg_xlog
-rw------- 1 postgres postgres 20541 04-24 04:21 postgresql.conf
-rw------- 1 postgres postgres    71 04-24 04:43 postmaster.opts
-rw------- 1 postgres postgres    79 04-24 04:43 postmaster.pid

Na koniec: uruchomienie serwera, stworzenie bazy danych test i testowe podłączenie do serwera:

/usr/local/psql9.3.4/bin/postgres -D /home/postgres/psql9.3.4/data >/usr/local/psql9.3.4/logs/logfile 2>&1 &
/usr/local/psql9.3.4/bin/createdb test
/usr/local/psql9.3.4/bin/psql test

Musimy teraz skonfigurować serwer tak aby można było się do niego zalogować nie tylko z localhosta. Serwer musi nasłuchiwać na wszystkich możliwych adresach dlatego zmienimy plik konfiguracyjny - postgresql.conf, który jest w katalogu klastra:

[04:21:56 root@nazgul data] grep 'CONNECTIONS AND AUTHENTICATION' -A 10 -B1 postgresql.conf
#------------------------------------------------------------------------------
# CONNECTIONS AND AUTHENTICATION
#------------------------------------------------------------------------------

# - Connection Settings -

listen_addresses = '*'  # what IP address(es) to listen on;
     # comma-separated list of addresses;
     # defaults to 'localhost'; use '*' for all
     # (change requires restart)
port = 7432    # (change requires restart)
max_connections = 100   # (change requires restart)

Jednak gdy próbujemy się zalogować dostajemy błąd:

[ela:~ ]$ psql -h192.168.100.167 -Upostgres -p7432
psql: FATAL:  no pg_hba.conf entry for host "192.168.100.152", user "postgres", database "postgres"

pg_hda.conf jest plikiem kontrolującym autoryzację klientów (link do dokumentacji: http://www.postgresql.org/docs/9.3/static/auth-pg-hba-conf.html). Domyślnie możemy się zalogować z localhosta bez żadnego hasła. Nie będę tego zmieniać bo zakładam, użytkownik ma dostęp na serwer jest już użytkownikiem zaufanym. Dodałam jednak jeden wpis dzięki któremu, wszyscy użytkownicy w podsieci 192.168.100.* mogą się zalogować przy pomocy hasła. Ostatecznie wpisy w pg_hba.conf wyglądają tak:

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     trust
# IPv4 local connections:
host    all             all             127.0.0.1/32            trust
# IPv6 local connections:
host    all             all             ::1/128                 trust
# ADDED: can connect to database but you have to put correct password
host    all             all  192.168.100.0/0     md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
#local   replication     postgres                                trust
#host    replication     postgres        127.0.0.1/32            trust
#host    replication     postgres        ::1/128                 trust

Dodajmy jeszcze kilku użytkowników:
  • replication - dla inicjalizacji replikacji
  • admin - z prawami do tworzenia nowych ról i baz danych
  • user - użytkownik z możliwością logowania ale bez tworzenia baz danych

[04:59:53 iloop@nazgul ~] /usr/local/psql9.3.4/bin/createuser --replication --login --pwprompt -U postgres replication
[04:53:01 iloop@nazgul ~] /usr/local/psql9.3.4/bin/createuser --createdb --login --pwprompt --createrole -U postgres admin
[04:59:01 iloop@nazgul ~] /usr/local/psql9.3.4/bin/createuser --no-createdb --login --pwprompt -U postgres user


Każdy krok wykonałam na dwóch maszynach tak aby utworzyć między nimi replikację master-standby. Ale to już w następnym poście.

czwartek, 24 kwietnia 2014

Obliczanie selektywności szukanych wartości na podstawie statystyk PostgreSQLa

W PostgreSQLu możemy zobaczyć informację na temat statystyk danych w naszych tabelkach. Ile mamy unikalnych wartości? Ile jest wartości NULLowych? Ale właściwie to po co nam to wiedzieć? Optymalizator w momencie gdy dostaje do wykonania zapytanie, musi podjąć decyzję jak to zapytanie wykonać. Do tego celu potrzebuje wiedzieć ile lub jaki jest rząd wielkości wierszy, z poszukiwanymi wartościami.
Pokaże Wam jak samemu możemy się dowiedzieć na podstawie statystyk, ile wierszy powinno zwrócić (wziąć pod uwagę) nasze zapytanie.

Do podejrzenia statystyk wykorzystujemy widok pg_stats. Informacje te pochodzą z tabeli pg_statistics (katalog systemowy, dostępny tylko dla super-użytkownika). Więcej informacji na temat pg_statistics znajdziecie tutaj.

Informację, które możecie odczytać z pg_stats:
  • schemaname - nazwa schematu, której znajduje się tabela
  • tablename - nazwa tabeli
  • attname - nazwa kolumny, dla której przestawiane są statystyki
  • inherited - przyjmuje wartości boolowskie. Jeśli jest true w wierszach są kolumny dziedziczące
  • null_frac - współczynnik ilości wierszy, które zawierają wartości NULL
  • avg_width - średnia długość danych w wierszach podanych w bajtach
  • n_distinct - jeśli wartość jest dodatnia, jest estymacją ilości wierszy o wartościach unikalnych. Jeśli jest wartością ujemną, jest liczbą unikalnych wartości podzielną przez ilość wierszy
  • most_common_vals - lista najczęściej występujących wartości w kolumnie
  • most_common_freqs - lista współczynników wystąpień wartości w tabeli most_common_vals
  • histogram_bounds - lista wartości, które dzielą wszystkie wartości w kolumnie na równe grupy. Dane nie są podawane jeśli typ kolumny nie uwzględnia operatora '<' przy porównywaniu danych lub jeśli most_common_vals występują wszystkie możliwe wartości w kolumnie 
  • correlations - statystyczna korelacja uporządkowania wartości kolumn. Podobnie jak dla histogram_bounds tylko dla kolumn które uwzględniają operator '<', dana jest podawana

Od wersji 9.2 doszły dodatkowe informacje: most_common_elems (najczęściej występujące wartości nienullowe), most_common_elem_freqs (współczynnik wystąpień najczęściej występujących wartości nienullowych), elem_count_histogram (histogramu liczby rodzajów różnych nie-zerowych wartości elementów w obrębie wartości kolumny, a następnie przez średnią liczbę odrębnych elementów niezerowych).

Statystyki w praktyce

Przykład tabeli na której będziemy pracować:

               Table "public.event2"
+--------+-----------------------------+-----------+
| Column |            Type             | Modifiers |
+--------+-----------------------------+-----------+
| c1     | integer                     | not null  |
| c2     | character varying(20)       |           |
| c3     | timestamp without time zone |           |
| c4     | integer                     |           |
| c5     | integer                     |           |
+--------+-----------------------------+-----------+

Nasza tabelka ma 500 wierszy. Jeśli jednak nie znany ilości wierszy, mamy dwa wyjścia: policzyć je funkcją count lub sprawdzić na tabeli pg_class:

127.0.0.1:7432 postgres@test # SELECT reltuples, relpages FROM pg_class WHERE relname = 'event2';
+-----------+----------+
| reltuples | relpages |
+-----------+----------+
|       500 |        9 |
+-----------+----------+
(1 row)

Time: 0,442 ms

Statystyki dla kolumny c5:

127.0.0.1:7432 postgres@test # select * from pg_stats where tablename = 'event2' and attname = 'c5';
+-[ RECORD 1 ]------+---------------------------------------------------------------------------------------------------------------------+
| schemaname        | public                                                                                                              |
| tablename         | event2                                                                                                              |
| attname           | c5                                                                                                                  |
| inherited         | f                                                                                                                   |
| null_frac         | 0                                                                                                                   |
| avg_width         | 4                                                                                                                   |
| n_distinct        | 20                                                                                                                  |
| most_common_vals  | {19,16,4,5,6,9,0,12,18,17,3,1,2,15,7,11,10,13,8,14}                                                                 |
| most_common_freqs | {0.074,0.062,0.06,0.06,0.06,0.058,0.056,0.054,0.054,0.052,0.05,0.048,0.048,0.042,0.04,0.04,0.038,0.036,0.034,0.034} |
| histogram_bounds  | NULL                                                                                                                |
| correlation       | 0.067399                                                                                                            |
+-------------------+---------------------------------------------------------------------------------------------------------------------+

Time: 7,469 ms

Chcemy określić ile wierszy pasuje do warunku c2 = 19. Bazując na danych ze statystyk wiemy, że w kolumnie mamy:
  • 20 unikalnych wartości
  • nie ma wartości NULL
  • przykładowo wartość 19 występuje w 7.4% wszystkich wartości czyli dla 500 wszystkich wierszach, jest ich 37 ( => 500 * 7.4%)
Porównajmy nasze obliczenia z explainem (patrzcie na informacje rows):

127.0.0.1:7432 postgres@test # explain select * from event2 where c5 = 19;
+---------------------------------------------------------+
|                       QUERY PLAN                        |
+---------------------------------------------------------+
| Seq Scan on event2  (cost=0.00..15.25 rows=37 width=40) |
|   Filter: (c5 = 19)                                     |
+---------------------------------------------------------+
(2 rows)

Time: 0,356 ms

Podobnie mamy selektywność dla kolumny c2, o ile szukana wartość znajduje się w najczęsciej występujących wartościach:

127.0.0.1:7432 postgres@test # select * from pg_stats where tablename = 'event2' and attname = 'c2';
+-[ RECORD 1 ]------+---------------------------------+
| schemaname        | public                          |
| tablename         | event2                          |
| attname           | c2                              |
| inherited         | f                               |
| null_frac         | 0                               |
| avg_width         | 6                               |
| n_distinct        | 5                               |
| most_common_vals  | {0074a,97a14,f87fa,dc358,85c58} |
| most_common_freqs | {0.336,0.336,0.208,0.066,0.054} |
| histogram_bounds  | NULL                            |
| correlation       | 0.0551021                       |
+-------------------+---------------------------------+

Time: 1,243 ms

Jeśli jednak naszej wartości tam nie ma, selektywność obliczamy następująco:
(1 - sum(most_common_freqs))/(num_distinct / most_common_vals_nr)

A dla naszej tabeli/kolumny będzie to wynosiło:
(1 - (0.336+0.336+0.208+0.066+0.054)) / (5 / 5) = 0


Inny przykład gdy mamy tylko wartości unikalne. Statystyki dla kolumny c1:

127.0.0.1:7432 postgres@test # select * from pg_stats where tablename = 'event2' and attname = 'c1';
+-[ RECORD 1 ]------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| schemaname        | public                                                                                                                                                                                                                                                                                                                                                                                          |
| tablename         | event2                                                                                                                                                                                                                                                                                                                                                                                          |
| attname           | c1                                                                                                                                                                                                                                                                                                                                                                                              |
| inherited         | f                                                                                                                                                                                                                                                                                                                                                                                               |
| null_frac         | 0                                                                                                                                                                                                                                                                                                                                                                                               |
| avg_width         | 4                                                                                                                                                                                                                                                                                                                                                                                               |
| n_distinct        | -1                                                                                                                                                                                                                                                                                                                                                                                              |
| most_common_vals  | NULL                                                                                                                                                                                                                                                                                                                                                                                            |
| most_common_freqs | NULL                                                                                                                                                                                                                                                                                                                                                                                            |
| histogram_bounds  | {1,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180,185,190,195,200,205,210,215,220,225,230,235,240,245,250,255,260,265,270,275,280,285,290,295,300,305,310,315,320,325,330,335,340,345,350,355,360,365,370,375,380,385,390,395,400,405,410,415,420,425,430,435,440,445,450,455,460,465,470,475,480,485,490,495,500} |
| correlation       | 0.998155                                                                                                                                                                                                                                                                                                                                                                                        |
+-------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

Time: 1,250 ms

Tym razem wzór selektywności na podstawie histogram_bounds wygląda następująco:

(full_his_bound_count + (value - his_bound[nr].min)/(his_bound[nr].max - his_bound[nr].min)) / num_his_bound

Gdzie:
  • full_his_bround_count - ilość przedziałów, które w całości bierzemy pod uwagę przy obliczaniu selektywności.
  • value - nasza wartość dla której obliczamy selektywność
  • his_bound[nr] - przedział, w którym jest nasza wartość. Np dla wartości = 8 jest to przedział 2, pomiędzy 5 (min), a 10 (max).
  • num_his_bound - ilość przedziałów w kolumnie histogram_bounds. W powyższym przykładzie wartości mamy od 1 do 500 co 5 dlatego 500/5 = 100

Obliczanie selektywności rekordów dla warunków:
  • c1 < 8, selektywność = (1 + (8 - 5)/(10 - 5))/(100) = 8
  • c1 < 28, selektywność = (5 + (28 - 25)/(30 - 25))/(100) = 28

Sprawdźmy nasze wyniki:

127.0.0.1:7432 postgres@test # explain select * from event2 where c1 < 28;
+----------------------------------------------------------------------------+
|                                 QUERY PLAN                                 |
+----------------------------------------------------------------------------+
| Index Scan using event2_pkey on event2  (cost=0.00..8.86 rows=28 width=40) |
|   Index Cond: (c1 < 28)                                                    |
+----------------------------------------------------------------------------+
(2 rows)

Time: 0,311 ms

Obliczanie selektywności dla dwóch kolumn jest bardzo podobne. Na początku wychodzimy od obliczania selektywności każdej kolumny z osobna, mnożymy je i w ten sposób otrzymujemy selektywność całego warunku.

Przykład dla zapytania:
select * from event2 where c2 = '0074a' and c4 = 30
selektywność = ((selektywność dla c2) * (selektywność dla c4) * (ilość wierszy)) = 0.336 * 0.02 = 0.006
ilość wierszy = 0.006 * 500 = 3

127.0.0.1:7432 postgres@test # explain select * from event2 where c2 = '0074a' and c4 = 30;
+--------------------------------------------------------+
|                       QUERY PLAN                       |
+--------------------------------------------------------+
| Seq Scan on event2  (cost=0.00..16.50 rows=3 width=26) |
|   Filter: (((c2)::text = '0074a'::text) AND (c4 = 30)) |
+--------------------------------------------------------+
(2 rows)

Time: 0,456 ms

Odświeżanie informacji na temat statystyk

Dane w tabeli pg_statistics są aktualizowane na bieżąco oraz po wykonaniu poleceń: ANALYZE i VACCUM ANALYZE.

Aby zmniejszyć/zwiększyć ilość danych statystycznych możemy zmienić wartość zmiennej globalnej konfiguracyjnej: default_statistics_target (domyślnie
przyjmuje wartość 100).

O innych przykładach obliczania selektywności dla zapytań odsyłam do dokumentacji tutaj.

czwartek, 17 kwietnia 2014

B-tree i Hash - najpopularniejsze typy indexów (PostgreSQL)

Pamiętacie może post, w którym opisywałam EXPLAIN plan w PostgreSQLu? Mogliście sie w nim dowiedzieć w jaki sposób czytać informację o tym jak optymalizator odczytuje dane z tabel i jakiego rodzaju indexy wybiera,, aby ta praca była efektywna. Jeśli jednak mamy możliwość zmiany lub utworzenia nowego indexu, dobrze wiedzieć jak one działają i jak są zbudowane.

PostgreSQL ma 4 podstawowe typy indexów:
  • B-tree
  • Hash
  • GiST
  • GIN
Dwa pierwsze z nich istnieją także w innych popularnych silnikach bazodanowych i ich zasada działania jest podobna. GiST i GIN postaram się omówić w innym poście. Teraz przestawię tylko dwa najpopularniejsze typy indexów.


Na potrzeby tego posta stworzyłam tabelę test_indexes. Zapisane w niej jest 1000 rekordów:

            Table "public.test_indexes"
+--------+-----------------------------+-----------+
| Column |            Type             | Modifiers |
+--------+-----------------------------+-----------+
| c1     | integer                     |           |
| c2     | character varying(10)       |           |
| c3     | integer                     |           |
| c4     | boolean                     |           |
| c5     | text                        |           |
| c6     | integer                     |           |
| c7     | timestamp without time zone |           |
| c8     | date                        |           |
+--------+-----------------------------+-----------+
Indexes:
    "idx_test_c5" btree (c5)
    "idx_test_c6_c1" btree (c6, c1)
    "idx_test_c7_c6" btree (c7, c6)
    "idx_test_c8_c6" btree (c8, c6)
    "idx_test_hash_c2" hash (c2)

Pamiętajmy, że wybierając dane dla jednej tabeli jest możliwe tylko użycie jednego indexu.

B-tree

Najpopularniejszy z indeksów. Jego strukturą danych jest drzewo zbilansowane, czyli zrównoważone - aby dotrzeć do dowolnego liścia drzewa, musisz przejść ścieżkę o podobnej długości.

Tego typu index współpracuje z następującymi operatorami: =, >, >=, <, <=, dlatego jest najbardziej popularny.
Index działa na danych typu tekst i numerycznych, a także od wersji 8.3 jest używany do znajdowania lub pominięcia wartości NULL w tabelach. Przy wyszukiwaniu rekordów na danych tekstowych możemy użyć LIKE ale tylko pod warunkiem, że szukany fragment jest na początku.

127.0.0.1:7432 postgres@test # explain analyze select * from test_indexes where c5 like '4f2b67f9%';
+--------------------------------------------------------------------------------------------------------+
|                                               QUERY PLAN                                               |
+--------------------------------------------------------------------------------------------------------+
| Seq Scan on test_indexes  (cost=0.00..42.50 rows=1 width=69) (actual time=0.015..0.386 rows=1 loops=1) |
|   Filter: (c5 ~~ '4f2b67f9%'::text)                                                                    |
| Total runtime: 0.413 ms                                                                                |
+--------------------------------------------------------------------------------------------------------+
(3 rows)

Time: 0,862 ms

Mam nadzieję, że zauważyliście iż index nie został wykorzystany i aby wykonać to zapytanie, optymalizator zdecydował o skanowaniu całej tabeli. Ale dlaczego?

Jeśli nasza baza danych nie używa C locale (domyślny przy porównaniach znaków w indexach), to index nie jest wykorzystywany. Jeśli pracujemy na juz istniejącej bazie danych możemy sprawdzić jakie locale jestało zaintalowane dla naszej bazy danych przy pomocy polecenia show lc_collate;

127.0.0.1:7432 postgres@test # show lc_collate;
+-------------+
| lc_collate  |
+-------------+
| pl_PL.UTF-8 |
+-------------+
(1 row)

Time: 0,258 ms

Aby sprawdzić dostępne locale naszego systemu operacyjnego na którym działa nasz serwer bazodanowy, wykonujemy polecenie locale:

[ela:/opt/PostgreSQL/9.1 ]$ locale -a
C
en_AG
en_AU.utf8
en_BW.utf8
en_CA.utf8
en_DK.utf8
en_GB.utf8
en_HK.utf8
en_IE.utf8
en_IN
en_NG
en_NZ.utf8
en_PH.utf8
en_SG.utf8
en_US.utf8
en_ZA.utf8
en_ZW.utf8
pl_PL.utf8
POSIX

Locale podawane jest przy instalacji bazy danych (initdb) lub przy tworzeniu bazy danych. Jeśli interesuje was ten temat, odsyłam do dokumentacji tutaj.

Aby stworzyć index bez zmian serwerowych i dodatkowych instalacji, przy tworzeniu indexu podajemy operator klasy:
  • text_pattern_ops - dla kolumn typu text
  • varchar_pattern_ops - dla kolumn typu varchar, 
  • bpchar_pattern_ops - dla kolumn typu char

127.0.0.1:7432 postgres@test # create index idx_test_c5_special on test_indexes (c5 text_pattern_ops);
CREATE INDEX
Time: 81,037 ms
127.0.0.1:7432 postgres@test # explain analyze select * from test_indexes where c5 like '4f2b67f9%';
+-----------------------------------------------------------------------------------------------------------------------------------+
|                                                            QUERY PLAN                                                             |
+-----------------------------------------------------------------------------------------------------------------------------------+
| Index Scan using idx_test_c5_special on test_indexes  (cost=0.00..8.27 rows=1 width=69) (actual time=0.082..0.083 rows=1 loops=1) |
|   Index Cond: ((c5 ~>=~ '4f2b67f9'::text) AND (c5 ~<~ '4f2b67f:'::text))                                                          |
|   Filter: (c5 ~~ '4f2b67f9%'::text)                                                                                               |
| Total runtime: 0.115 ms                                                                                                           |
+-----------------------------------------------------------------------------------------------------------------------------------+
(4 rows)

Time: 1,568 ms

Jeśli szukany wzorzec jest w środku lub na końcu, wiązało by się to z przeszukaniem praktycznie całej struktury drzewa indexu, dlatego nie ma to sensu. Pamiętajmy o tym gdy tworzymy nasze zapytania.

Inny przykład dla operatorów mniejszy i większy:

127.0.0.1:7432 postgres@test # explain select count(*) from test_indexes where c1 between 1 and 30;
+---------------------------------------------------------------------------------+
|                                   QUERY PLAN                                    |
+---------------------------------------------------------------------------------+
| Aggregate  (cost=19.08..19.09 rows=1 width=0)                                   |
|   ->  Bitmap Heap Scan on test_indexes  (cost=4.56..19.01 rows=30 width=0)      |
|         Recheck Cond: ((c1 >= 1) AND (c1 <= 30))                                |
|         ->  Bitmap Index Scan on idx_test_c1  (cost=0.00..4.55 rows=30 width=0) |
|               Index Cond: ((c1 >= 1) AND (c1 <= 30))                            |
+---------------------------------------------------------------------------------+
(5 rows)

Time: 0,549 ms

127.0.0.1:7432 postgres@test # explain select * from test_indexes where c6 between 120 and 200 AND c1 = 3;
+------------------------------------------------------------------------------------+
|                                     QUERY PLAN                                     |
+------------------------------------------------------------------------------------+
| Index Scan using idx_test_c6_c1 on test_indexes  (cost=0.00..9.21 rows=1 width=35) |
|   Index Cond: ((c6 >= 120) AND (c6 <= 200) AND (c1 = 3))                           |
+------------------------------------------------------------------------------------+
(2 rows)

Time: 0,475 ms


Hash

W porównaniu do B-tree, hash index jest używany tylko przy operatorze =. Dodatkowo nie pozwala na wartości NULL.

127.0.0.1:7432 postgres@test # explain select * from test_indexes where c2 = 'b2a90e52ed';
+--------------------------------------------------------------------------------------+
|                                      QUERY PLAN                                      |
+--------------------------------------------------------------------------------------+
| Index Scan using idx_test_hash_c2 on test_indexes  (cost=0.00..8.27 rows=1 width=69) |
|   Index Cond: ((c2)::text = 'b2a90e52ed'::text)                                      |
+--------------------------------------------------------------------------------------+
(2 rows)

Time: 75,145 ms

Podsumowanie
B-treeHash
Operatory>=,=, >, <, <==
Wartości NULLTAKNIE


Krótko o samym tworzeniu, usuwaniu i zmianie indexów

Tworzenia indexu:

 CREATE INDEX NAZWA_INDEXU ON NAZWA_TABELI USING INDEX_TYPE (NAZWA_KOLUMNY);

Nazwa indexu musi być unikalna w całym schemacie, a nie tabeli tak jak to jest w MySQL-u.

Usuwanie indexu:

DROP INDEX NAZWA_INDEXU;

Aby zmienić index już istniejący, trzeba go najpierw usunąć i utworzyć na nowo ze zmianami.