| 89 | | |
| 90 | | |
| 91 | | |
| 92 | | |
| 93 | | |
| 94 | | |
| | 89 | == ИНДЕКСИ |
| | 90 | |
| | 91 | Индексите се посебни структури на податоци кои го забрзуваат пребарувањето и пристапот до податоци во табелите. Без индекси, PostgreSQL мора да изврши последователно скенирање(sequential scan) на целата табела за да ги најде потребните редови. Со индекси, пребарувањето е значително побрзо, особено кај табели со голем број на редови. |
| | 92 | |
| | 93 | |
| | 94 | Типови на индекси во PostgreSQL: |
| | 95 | |
| | 96 | * '''B-tree''' - стандарден индекс, погоден за пребарување по еднаквост и опсег (=, <, >, <=, >=, BETWEEN) |
| | 97 | * '''Hash''' - за едноставни споредби со (=) |
| | 98 | * '''GiST''' - за геометриски податоци и full-text податоци. Нуди повеќе стратегии како nearest neighbor и делумно совпаѓање со пребарувањето. |
| | 99 | * '''GIN''' (Generalized Inverted Index) - за колони со повеќевредносни податоци (JSONB, arrays, full-text search) |
| | 100 | * '''BRIN''' (Block Range Index) - компактен индекс наменет за екстремно големи табели. Наместо да го индексира секој ред поединечно, ги групира редовите во блокови и чува сумарни информации за секој блок, што заштедува значителен простор на диск. |
| | 101 | |
| | 102 | Креирањето индекси значително ги подобрува перформансите при SELECT операции и JOIN-операции, особено кај големи табели. Од друга страна, секое додавање на нов индекс го зголемува просторот на дискот и операциите како што се INSERT, UPDATE и DELETE стануваат по спори бидејќи индексите мора да се ажурираат заедно со табелата. Затоа, индексите треба да се креираат внимателно само на колони што навистина се користат во WHERE или JOIN операции. |
| | 103 | |
| | 104 | Некој од најчестите прашалници за FilmRentalDB се: |
| | 105 | |
| | 106 | * Пребарување на филмови по наслов |
| | 107 | |
| | 108 | {{{ |
| | 109 | EXPLAIN ANALYSE |
| | 110 | SELECT f.title |
| | 111 | FROM film f |
| | 112 | WHERE f.title = 'Film #500'; |
| | 113 | }}} |
| | 114 | |
| | 115 | |
| | 116 | [[Image(query1_result.png)]] |
| | 117 | |
| | 118 | PostgreSQL прави последователно скенирање на целата film табела, што значи дека мора да ги прочита сите редови за да го најде точниот наслов. Ова резултира со поголемо време за извршување, особено кај табела со голем број на редови. |
| | 119 | |
| | 120 | По креирањето на индексот повторно го извршуваме истиот прашалник. |
| | 121 | |
| | 122 | {{{ CREATE INDEX index_film_title ON film(title); }}} |
| | 123 | |
| | 124 | [[Image(query1_result_index.png)]] |
| | 125 | |
| | 126 | Додавањето индекс на колоната title значително ги подобри перформансите на пребарувањето. PostgreSQL повеќе не ја скенира целата табела, туку директно пристапува до точниот запис преку индексот. |
| | 127 | |
| | 128 | |
| | 129 | * Пребарување на филмови по категорија |
| | 130 | |
| | 131 | {{{ |
| | 132 | EXPLAIN ANALYSE |
| | 133 | SELECT * |
| | 134 | FROM customer |
| | 135 | WHERE last_name = 'Lastname320'; |
| | 136 | }}} |
| | 137 | |
| | 138 | [[Image(query2_result.png)]] |
| | 139 | |
| | 140 | {{{ CREATE INDEX index_customer_lastname ON customer(last_name); }}} |
| | 141 | |
| | 142 | [[Image(query2_result_index.png)]] |
| | 143 | |
| | 144 | |
| | 145 | * Пребарување на филмови по категорија |
| | 146 | |
| | 147 | {{{ |
| | 148 | EXPLAIN ANALYSE |
| | 149 | SELECT f.title |
| | 150 | FROM film f |
| | 151 | JOIN film_category fc ON f.film_id = fc.film_id |
| | 152 | JOIN category c ON c.category_id = fc.category_id |
| | 153 | WHERE c.name = 'Category 5'; |
| | 154 | }}} |
| | 155 | |
| | 156 | [[Image(query3_result.png)]] |
| | 157 | |
| | 158 | Овој прашалник бара поврзување на три табели. PostgreSQL извршуваше целосно скенирање на табелата film_category, и тоа како '''Parallel Seq Scan''', што значи дека мора да ги прочита сите 200.000 редови за да го најде соодветниот category_id. Ова резултираше со време на извршување од околу 59 ms. |
| | 159 | |
| | 160 | Додавање на индекси. |
| | 161 | |
| | 162 | {{{ |
| | 163 | CREATE INDEX idx_category_name ON category(name); |
| | 164 | CREATE INDEX idx_film_category_category_id ON film_category(category_id); |
| | 165 | CREATE INDEX idx_film_category_film_id ON film_category(film_id); |
| | 166 | }}} |
| | 167 | |
| | 168 | [[Image(query3_result_index.png)]] |
| | 169 | |
| | 170 | По додавањето на индексите PostgreSQL започна да користи '''Bitmap Index Scan''', кој многу поефикасно ги лоцира сите редови што припаѓаат на Category 5 и чита само релевантни страници од дискот. Времето на извршување се намали на 34 ms, што претставува значително подобрување. |
| | 171 | |
| | 172 | |
| | 173 | * Историја на изнајмување на клиент сортирана според датум |
| | 174 | |
| | 175 | {{{ |
| | 176 | EXPLAIN ANALYSE |
| | 177 | SELECT |
| | 178 | c.first_name, |
| | 179 | c.last_name, |
| | 180 | f.title, |
| | 181 | r.rental_date, |
| | 182 | r.return_date |
| | 183 | FROM customer c |
| | 184 | JOIN rental r ON c.customer_id = r.customer_id |
| | 185 | JOIN inventory i ON r.inventory_id = i.inventory_id |
| | 186 | JOIN film f ON i.film_id = f.film_id |
| | 187 | WHERE c.customer_id = 100 |
| | 188 | ORDER BY r.rental_date DESC; |
| | 189 | }}} |
| | 190 | |
| | 191 | [[Image(query4_result.png)]] |
| | 192 | |
| | 193 | Пред додавање индекси, PostgreSQL правеше Parallel Sequential Scan на табелата rental и ги скенираше сите 300.000 редови за да ги најде само 10 што припаѓаат на клиентот со ID = 100. Целосното скенирање, филтрирање и финалното сортирање резултираше со време на извршување од 34.78 ms. |
| | 194 | |
| | 195 | |
| | 196 | {{{ CREATE INDEX index_rental_customer_date ON rental(customer_id, rental_date DESC); }}} |
| | 197 | |
| | 198 | |
| | 199 | [[Image(query4_result_index.png)]] |
| | 200 | |
| | 201 | PostgreSQL веднаш ги лоцира само релевантните записи преку Index Scan, без потреба од сортирање (податоците се веќе сортирани во индексот). Новото време на извршување е само 0.334 ms што е многу побрзо од извршување без индекс. |
| | 202 | |
| | 203 | |