| | 1 | Анализата е направена со `EXPLAIN (ANALYZE, BUFFERS)`, при што се споредува планот за извршување пред и по додавање на дополнителните индекси. Во почетната состојба базата ги содржи само индексите кои PostgreSQL автоматски ги креира за `PRIMARY KEY` и `UNIQUE` ограничувања. Овие индекси не се третираат како дополнителна оптимизација, туку како дел од основната релациска структура на базата. |
| | 2 | |
| | 3 | Во моментот на тестирањето, базата ја има следната количина на податоци: |
| | 4 | |
| | 5 | ||= Табела =||= Број на редови =|| |
| | 6 | || `user` || 3 || |
| | 7 | || `transaction` || 12 || |
| | 8 | || `transaction_account` || 5 || |
| | 9 | || `transaction_breakdown` || 11 || |
| | 10 | || `tag` || 11 || |
| | 11 | || `tag_assigned_to_transaction` || 16 || |
| | 12 | |
| | 13 | Поради малата количина на податоци, очекувано е PostgreSQL во повеќе случаи да избере `Seq Scan`, бидејќи целосното читање на мала табела е поевтино од пристап преку индекс. Затоа, во анализата не се гледа само времето на извршување, туку и дали индексот навистина се користи во execution plan-от. |
| | 14 | |
| | 15 | ==== Предложени дополнителни индекси ==== |
| | 16 | |
| | 17 | Следните индекси се предложени затоа што колоните често се користат во `JOIN` и `WHERE` услови во аналитичките извештаи: |
| | 18 | |
| | 19 | {{{#!sql |
| | 20 | CREATE INDEX IF NOT EXISTS idx_transaction_date |
| | 21 | ON "transaction"(date); |
| | 22 | |
| | 23 | CREATE INDEX IF NOT EXISTS idx_transaction_account_user_id |
| | 24 | ON transaction_account(user_id); |
| | 25 | |
| | 26 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_transaction_id |
| | 27 | ON transaction_breakdown(transaction_id); |
| | 28 | |
| | 29 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_account_id |
| | 30 | ON transaction_breakdown(transaction_account_id); |
| | 31 | |
| | 32 | CREATE INDEX IF NOT EXISTS idx_tag_assigned_transaction_id |
| | 33 | ON tag_assigned_to_transaction(transaction_id); |
| | 34 | |
| | 35 | CREATE INDEX IF NOT EXISTS idx_tag_assigned_tag_id |
| | 36 | ON tag_assigned_to_transaction(tag_id); |
| | 37 | }}} |
| | 38 | |
| | 39 | Индексот `idx_transaction_date` е наменет за извештаи кои филтрираат трансакции според временски период. Индексот `idx_transaction_account_user_id` е наменет за извештаи кои ги ограничуваат резултатите на конкретен корисник. Индексите на `transaction_breakdown` и `tag_assigned_to_transaction` се наменети за побрзо поврзување на трансакциите со сметки и тагови. |
| | 40 | |
| | 41 | ==== Сценарио 1: Трендови на трошење според тагови за корисник ==== |
| | 42 | |
| | 43 | '''Цел:''' |
| | 44 | Овој извештај ја прикажува потрошувачката по тагови за конкретен корисник во последните шест месеци. Прашалникот е комплексен затоа што ги поврзува табелите `tag_assigned_to_transaction`, `transaction`, `transaction_breakdown`, `transaction_account` и `tag`, а дополнително врши филтрирање по корисник и датум, групирање по таг и месец, и сумирање на потрошената сума. |
| | 45 | |
| | 46 | '''Анализиран SQL:''' |
| | 47 | |
| | 48 | {{{#!sql |
| | 49 | EXPLAIN (ANALYZE, BUFFERS) |
| | 50 | SELECT |
| | 51 | tg.tag_name, |
| | 52 | DATE_TRUNC('month', t.date) AS month, |
| | 53 | SUM(tb.spent_amount) AS total_spent |
| | 54 | FROM tag_assigned_to_transaction tat |
| | 55 | JOIN "transaction" t |
| | 56 | ON tat.transaction_id = t.transaction_id |
| | 57 | JOIN transaction_breakdown tb |
| | 58 | ON t.transaction_id = tb.transaction_id |
| | 59 | JOIN transaction_account ta |
| | 60 | ON tb.transaction_account_id = ta.transaction_account_id |
| | 61 | JOIN tag tg |
| | 62 | ON tat.tag_id = tg.tag_id |
| | 63 | WHERE |
| | 64 | ta.user_id = 1 |
| | 65 | AND t.date >= DATE_TRUNC('month', CURRENT_DATE - INTERVAL '6 MONTHS') |
| | 66 | GROUP BY |
| | 67 | tg.tag_name, month |
| | 68 | ORDER BY |
| | 69 | tg.tag_name, month; |
| | 70 | }}} |
| | 71 | |
| | 72 | '''Релевантни индекси за ова сценарио:''' |
| | 73 | |
| | 74 | {{{#!sql |
| | 75 | CREATE INDEX IF NOT EXISTS idx_transaction_date |
| | 76 | ON "transaction"(date); |
| | 77 | |
| | 78 | CREATE INDEX IF NOT EXISTS idx_transaction_account_user_id |
| | 79 | ON transaction_account(user_id); |
| | 80 | |
| | 81 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_transaction_id |
| | 82 | ON transaction_breakdown(transaction_id); |
| | 83 | |
| | 84 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_account_id |
| | 85 | ON transaction_breakdown(transaction_account_id); |
| | 86 | |
| | 87 | CREATE INDEX IF NOT EXISTS idx_tag_assigned_transaction_id |
| | 88 | ON tag_assigned_to_transaction(transaction_id); |
| | 89 | |
| | 90 | CREATE INDEX IF NOT EXISTS idx_tag_assigned_tag_id |
| | 91 | ON tag_assigned_to_transaction(tag_id); |
| | 92 | }}} |
| | 93 | |
| | 94 | '''План пред додавање на индексите:''' |
| | 95 | |
| | 96 | {{{#!sql |
| | 97 | GroupAggregate (cost=6.54..6.77 rows=9 width=53) (actual time=0.176..0.189 rows=7 loops=1) |
| | 98 | Group Key: tg.tag_name, (date_trunc('month'::text, t.date)) |
| | 99 | Buffers: shared hit=5 |
| | 100 | -> Sort (cost=6.54..6.57 rows=9 width=25) (actual time=0.162..0.167 rows=16 loops=1) |
| | 101 | Sort Key: tg.tag_name, (date_trunc('month'::text, t.date)) |
| | 102 | Sort Method: quicksort Memory: 25kB |
| | 103 | -> Hash Join (cost=4.99..6.40 rows=9 width=25) (actual time=0.119..0.142 rows=16 loops=1) |
| | 104 | Hash Cond: (tat.tag_id = tg.tag_id) |
| | 105 | -> Hash Join (cost=3.74..5.10 rows=9 width=16) (actual time=0.086..0.099 rows=16 loops=1) |
| | 106 | Hash Cond: (tat.transaction_id = t.transaction_id) |
| | 107 | -> Hash Join (cost=2.35..3.67 rows=10 width=16) (actual time=0.057..0.066 rows=16 loops=1) |
| | 108 | Hash Cond: (tat.transaction_id = tb.transaction_id) |
| | 109 | -> Seq Scan on tag_assigned_to_transaction tat |
| | 110 | -> Hash |
| | 111 | -> Hash Join |
| | 112 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 113 | -> Seq Scan on transaction_breakdown tb |
| | 114 | -> Hash |
| | 115 | -> Seq Scan on transaction_account ta |
| | 116 | Filter: (user_id = 1) |
| | 117 | Rows Removed by Filter: 2 |
| | 118 | -> Hash |
| | 119 | -> Seq Scan on transaction t |
| | 120 | Filter: (date >= date_trunc('month'::text, (CURRENT_DATE - '6 mons'::interval))) |
| | 121 | -> Hash |
| | 122 | -> Seq Scan on tag tg |
| | 123 | Planning Time: 0.733 ms |
| | 124 | Execution Time: 0.296 ms |
| | 125 | }}} |
| | 126 | |
| | 127 | '''План по додавање на индексите:''' |
| | 128 | |
| | 129 | {{{#!sql |
| | 130 | GroupAggregate (cost=6.54..6.77 rows=9 width=53) (actual time=0.154..0.166 rows=7 loops=1) |
| | 131 | Group Key: tg.tag_name, (date_trunc('month'::text, t.date)) |
| | 132 | Buffers: shared hit=5 |
| | 133 | -> Sort (cost=6.54..6.57 rows=9 width=25) (actual time=0.142..0.146 rows=16 loops=1) |
| | 134 | Sort Key: tg.tag_name, (date_trunc('month'::text, t.date)) |
| | 135 | Sort Method: quicksort Memory: 25kB |
| | 136 | -> Hash Join (cost=4.99..6.40 rows=9 width=25) (actual time=0.100..0.122 rows=16 loops=1) |
| | 137 | Hash Cond: (tat.tag_id = tg.tag_id) |
| | 138 | -> Hash Join (cost=3.74..5.10 rows=9 width=16) (actual time=0.068..0.081 rows=16 loops=1) |
| | 139 | Hash Cond: (tat.transaction_id = t.transaction_id) |
| | 140 | -> Hash Join (cost=2.35..3.67 rows=10 width=16) (actual time=0.040..0.049 rows=16 loops=1) |
| | 141 | Hash Cond: (tat.transaction_id = tb.transaction_id) |
| | 142 | -> Seq Scan on tag_assigned_to_transaction tat |
| | 143 | -> Hash |
| | 144 | -> Hash Join |
| | 145 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 146 | -> Seq Scan on transaction_breakdown tb |
| | 147 | -> Hash |
| | 148 | -> Seq Scan on transaction_account ta |
| | 149 | Filter: (user_id = 1) |
| | 150 | Rows Removed by Filter: 2 |
| | 151 | -> Hash |
| | 152 | -> Seq Scan on transaction t |
| | 153 | Filter: (date >= date_trunc('month'::text, (CURRENT_DATE - '6 mons'::interval))) |
| | 154 | -> Hash |
| | 155 | -> Seq Scan on tag tg |
| | 156 | Planning Time: 0.921 ms |
| | 157 | Execution Time: 0.242 ms |
| | 158 | }}} |
| | 159 | |
| | 160 | '''Споредба:''' |
| | 161 | |
| | 162 | ||= Метрика =||= Пред индекси =||= По индекси =|| |
| | 163 | || Planning Time || 0.733 ms || 0.921 ms || |
| | 164 | || Execution Time || 0.296 ms || 0.242 ms || |
| | 165 | || Тип на скенирање || `Seq Scan` || `Seq Scan` || |
| | 166 | || Дали новите индекси се користат || Не || Не || |
| | 167 | |
| | 168 | '''Заклучок:''' |
| | 169 | Времето на извршување се намали од 0.296 ms на 0.242 ms, што претставува намалување од приближно 18.2%. Сепак, execution plan-от и по додавање на индексите користи `Seq Scan` над сите релевантни табели, а не `Index Scan` или `Bitmap Index Scan`. Затоа подобрувањето не може да се припише директно на индексите. Најверојатната причина е малата количина на податоци и фактот што сите блокови се веќе во shared buffers. Индексите остануваат логични за идно зголемување на бројот на трансакции, тагови и breakdown записи. |
| | 170 | |
| | 171 | ==== Сценарио 2: Сметки со највисоко вкупно трошење во изминатата година ==== |
| | 172 | |
| | 173 | '''Цел:''' |
| | 174 | Овој извештај ги прикажува сметките со најголема вкупна потрошувачка во последната година. Прашалникот користи `JOIN` помеѓу `transaction_breakdown`, `transaction` и `transaction_account`, филтрирање по датум, `SUM` агрегација, `GROUP BY`, `ORDER BY` и `LIMIT`. |
| | 175 | |
| | 176 | '''Анализиран SQL:''' |
| | 177 | |
| | 178 | {{{#!sql |
| | 179 | EXPLAIN (ANALYZE, BUFFERS) |
| | 180 | SELECT |
| | 181 | ta.account_name, |
| | 182 | COALESCE(SUM(tb.spent_amount), 0) AS total_spent |
| | 183 | FROM transaction_breakdown tb |
| | 184 | JOIN "transaction" t |
| | 185 | ON tb.transaction_id = t.transaction_id |
| | 186 | JOIN transaction_account ta |
| | 187 | ON tb.transaction_account_id = ta.transaction_account_id |
| | 188 | WHERE |
| | 189 | t.date >= NOW() - INTERVAL '1 YEAR' |
| | 190 | GROUP BY |
| | 191 | ta.account_name |
| | 192 | ORDER BY |
| | 193 | total_spent DESC |
| | 194 | LIMIT 10; |
| | 195 | }}} |
| | 196 | |
| | 197 | '''Релевантни индекси за ова сценарио:''' |
| | 198 | |
| | 199 | {{{#!sql |
| | 200 | CREATE INDEX IF NOT EXISTS idx_transaction_date |
| | 201 | ON "transaction"(date); |
| | 202 | |
| | 203 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_transaction_id |
| | 204 | ON transaction_breakdown(transaction_id); |
| | 205 | |
| | 206 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_account_id |
| | 207 | ON transaction_breakdown(transaction_account_id); |
| | 208 | }}} |
| | 209 | |
| | 210 | '''План пред додавање на индексите:''' |
| | 211 | |
| | 212 | {{{#!sql |
| | 213 | Limit (cost=3.85..3.86 rows=5 width=40) (actual time=0.110..0.114 rows=3 loops=1) |
| | 214 | Buffers: shared hit=3 |
| | 215 | -> Sort (cost=3.85..3.86 rows=5 width=40) (actual time=0.108..0.111 rows=3 loops=1) |
| | 216 | Sort Key: (COALESCE(sum(tb.spent_amount), '0'::numeric)) DESC |
| | 217 | Sort Method: quicksort Memory: 25kB |
| | 218 | -> HashAggregate (cost=3.73..3.79 rows=5 width=40) (actual time=0.097..0.101 rows=3 loops=1) |
| | 219 | Group Key: ta.account_name |
| | 220 | -> Hash Join (cost=2.47..3.67 rows=11 width=12) (actual time=0.059..0.069 rows=11 loops=1) |
| | 221 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 222 | -> Hash Join (cost=1.36..2.51 rows=11 width=8) (actual time=0.032..0.038 rows=11 loops=1) |
| | 223 | Hash Cond: (tb.transaction_id = t.transaction_id) |
| | 224 | -> Seq Scan on transaction_breakdown tb |
| | 225 | -> Hash |
| | 226 | -> Seq Scan on transaction t |
| | 227 | Filter: (date >= (now() - '1 year'::interval)) |
| | 228 | -> Hash |
| | 229 | -> Seq Scan on transaction_account ta |
| | 230 | Planning Time: 0.403 ms |
| | 231 | Execution Time: 0.191 ms |
| | 232 | }}} |
| | 233 | |
| | 234 | '''План по додавање на индексите:''' |
| | 235 | |
| | 236 | {{{#!sql |
| | 237 | Limit (cost=3.85..3.86 rows=5 width=40) (actual time=0.100..0.104 rows=3 loops=1) |
| | 238 | Buffers: shared hit=3 |
| | 239 | -> Sort (cost=3.85..3.86 rows=5 width=40) (actual time=0.098..0.101 rows=3 loops=1) |
| | 240 | Sort Key: (COALESCE(sum(tb.spent_amount), '0'::numeric)) DESC |
| | 241 | Sort Method: quicksort Memory: 25kB |
| | 242 | -> HashAggregate (cost=3.73..3.79 rows=5 width=40) (actual time=0.086..0.090 rows=3 loops=1) |
| | 243 | Group Key: ta.account_name |
| | 244 | -> Hash Join (cost=2.47..3.67 rows=11 width=12) (actual time=0.060..0.070 rows=11 loops=1) |
| | 245 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 246 | -> Hash Join (cost=1.36..2.51 rows=11 width=8) (actual time=0.030..0.036 rows=11 loops=1) |
| | 247 | Hash Cond: (tb.transaction_id = t.transaction_id) |
| | 248 | -> Seq Scan on transaction_breakdown tb |
| | 249 | -> Hash |
| | 250 | -> Seq Scan on transaction t |
| | 251 | Filter: (date >= (now() - '1 year'::interval)) |
| | 252 | -> Hash |
| | 253 | -> Seq Scan on transaction_account ta |
| | 254 | Planning Time: 0.451 ms |
| | 255 | Execution Time: 0.166 ms |
| | 256 | }}} |
| | 257 | |
| | 258 | '''Споредба:''' |
| | 259 | |
| | 260 | ||= Метрика =||= Пред индекси =||= По индекси =|| |
| | 261 | || Planning Time || 0.403 ms || 0.451 ms || |
| | 262 | || Execution Time || 0.191 ms || 0.166 ms || |
| | 263 | || Тип на скенирање || `Seq Scan` || `Seq Scan` || |
| | 264 | || Дали новите индекси се користат || Не || Не || |
| | 265 | |
| | 266 | '''Заклучок:''' |
| | 267 | Времето на извршување се намали од 0.191 ms на 0.166 ms, што претставува намалување од приближно 13.1%. Сепак, планот за извршување не користи ниту еден од новите индекси. PostgreSQL продолжува со `Seq Scan` на `transaction`, `transaction_breakdown` и `transaction_account`, затоа што табелите имаат многу мал број редови и читањето на целата табела е поевтино од пристап преку индекс. Поради тоа, малото подобрување не се смета како директен ефект од индексите. Индексот на `transaction.date` сепак е оправдан за идно зголемување на бројот на трансакции, бидејќи извештајот филтрира според временски период. |
| | 268 | |
| | 269 | ==== Сценарио 3: Годишни трендови на трансакции за корисник ==== |
| | 270 | |
| | 271 | '''Цел:''' |
| | 272 | Овој извештај ја прикажува потрошувачката по квартали за конкретен корисник во тековната година. Прашалникот користи `JOIN` помеѓу `transaction_breakdown`, `transaction` и `transaction_account`, филтрирање по корисник и временски период, `SUM` агрегации со `CASE WHEN`, `GROUP BY` и `ORDER BY`. |
| | 273 | |
| | 274 | Во анализата условот за година е напишан како временски опсег, наместо само со `EXTRACT(YEAR FROM t.date)`, за B-Tree индексот на `date` да може поефикасно да се користи кога табелата ќе порасне. |
| | 275 | |
| | 276 | '''Анализиран SQL:''' |
| | 277 | |
| | 278 | {{{#!sql |
| | 279 | EXPLAIN (ANALYZE, BUFFERS) |
| | 280 | SELECT |
| | 281 | ta.account_name, |
| | 282 | SUM(CASE WHEN EXTRACT(QUARTER FROM t.date) = 1 THEN tb.spent_amount ELSE 0 END) AS q1_spent, |
| | 283 | SUM(CASE WHEN EXTRACT(QUARTER FROM t.date) = 2 THEN tb.spent_amount ELSE 0 END) AS q2_spent, |
| | 284 | SUM(CASE WHEN EXTRACT(QUARTER FROM t.date) = 3 THEN tb.spent_amount ELSE 0 END) AS q3_spent, |
| | 285 | SUM(CASE WHEN EXTRACT(QUARTER FROM t.date) = 4 THEN tb.spent_amount ELSE 0 END) AS q4_spent |
| | 286 | FROM transaction_breakdown tb |
| | 287 | JOIN "transaction" t |
| | 288 | ON tb.transaction_id = t.transaction_id |
| | 289 | JOIN transaction_account ta |
| | 290 | ON tb.transaction_account_id = ta.transaction_account_id |
| | 291 | WHERE |
| | 292 | ta.user_id = 1 |
| | 293 | AND t.date >= DATE_TRUNC('year', CURRENT_DATE) |
| | 294 | AND t.date < DATE_TRUNC('year', CURRENT_DATE) + INTERVAL '1 YEAR' |
| | 295 | GROUP BY |
| | 296 | ta.account_name |
| | 297 | ORDER BY |
| | 298 | ta.account_name; |
| | 299 | }}} |
| | 300 | |
| | 301 | '''Релевантни индекси за ова сценарио:''' |
| | 302 | |
| | 303 | {{{#!sql |
| | 304 | CREATE INDEX IF NOT EXISTS idx_transaction_date |
| | 305 | ON "transaction"(date); |
| | 306 | |
| | 307 | CREATE INDEX IF NOT EXISTS idx_transaction_account_user_id |
| | 308 | ON transaction_account(user_id); |
| | 309 | |
| | 310 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_transaction_id |
| | 311 | ON transaction_breakdown(transaction_id); |
| | 312 | |
| | 313 | CREATE INDEX IF NOT EXISTS idx_transaction_breakdown_account_id |
| | 314 | ON transaction_breakdown(transaction_account_id); |
| | 315 | }}} |
| | 316 | |
| | 317 | '''План пред додавање на индексите:''' |
| | 318 | |
| | 319 | {{{#!sql |
| | 320 | Sort (cost=4.16..4.17 rows=3 width=136) (actual time=0.141..0.144 rows=3 loops=1) |
| | 321 | Sort Key: ta.account_name |
| | 322 | Sort Method: quicksort Memory: 25kB |
| | 323 | Buffers: shared hit=3 |
| | 324 | -> HashAggregate (cost=4.08..4.14 rows=3 width=136) (actual time=0.126..0.131 rows=3 loops=1) |
| | 325 | Group Key: ta.account_name |
| | 326 | -> Hash Join (cost=2.35..3.85 rows=7 width=20) (actual time=0.070..0.089 rows=11 loops=1) |
| | 327 | Hash Cond: (t.transaction_id = tb.transaction_id) |
| | 328 | -> Seq Scan on transaction t |
| | 329 | Filter: ((date >= date_trunc('year'::text, (CURRENT_DATE)::timestamp with time zone)) |
| | 330 | AND (date < (date_trunc('year'::text, (CURRENT_DATE)::timestamp with time zone) + '1 year'::interval))) |
| | 331 | -> Hash |
| | 332 | -> Hash Join |
| | 333 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 334 | -> Seq Scan on transaction_breakdown tb |
| | 335 | -> Hash |
| | 336 | -> Seq Scan on transaction_account ta |
| | 337 | Filter: (user_id = 1) |
| | 338 | Rows Removed by Filter: 2 |
| | 339 | Planning Time: 0.402 ms |
| | 340 | Execution Time: 0.242 ms |
| | 341 | }}} |
| | 342 | |
| | 343 | '''План по додавање на индексите:''' |
| | 344 | |
| | 345 | {{{#!sql |
| | 346 | Sort (cost=4.16..4.17 rows=3 width=136) (actual time=0.131..0.135 rows=3 loops=1) |
| | 347 | Sort Key: ta.account_name |
| | 348 | Sort Method: quicksort Memory: 25kB |
| | 349 | Buffers: shared hit=3 |
| | 350 | -> HashAggregate (cost=4.08..4.14 rows=3 width=136) (actual time=0.117..0.122 rows=3 loops=1) |
| | 351 | Group Key: ta.account_name |
| | 352 | -> Hash Join (cost=2.35..3.85 rows=7 width=20) (actual time=0.063..0.082 rows=11 loops=1) |
| | 353 | Hash Cond: (t.transaction_id = tb.transaction_id) |
| | 354 | -> Seq Scan on transaction t |
| | 355 | Filter: ((date >= date_trunc('year'::text, (CURRENT_DATE)::timestamp with time zone)) |
| | 356 | AND (date < (date_trunc('year'::text, (CURRENT_DATE)::timestamp with time zone) + '1 year'::interval))) |
| | 357 | -> Hash |
| | 358 | -> Hash Join |
| | 359 | Hash Cond: (tb.transaction_account_id = ta.transaction_account_id) |
| | 360 | -> Seq Scan on transaction_breakdown tb |
| | 361 | -> Hash |
| | 362 | -> Seq Scan on transaction_account ta |
| | 363 | Filter: (user_id = 1) |
| | 364 | Rows Removed by Filter: 2 |
| | 365 | Planning Time: 0.500 ms |
| | 366 | Execution Time: 0.212 ms |
| | 367 | }}} |
| | 368 | |
| | 369 | '''Споредба:''' |
| | 370 | |
| | 371 | ||= Метрика =||= Пред индекси =||= По индекси =|| |
| | 372 | || Planning Time || 0.402 ms || 0.500 ms || |
| | 373 | || Execution Time || 0.242 ms || 0.212 ms || |
| | 374 | || Тип на скенирање || `Seq Scan` || `Seq Scan` || |
| | 375 | || Дали новите индекси се користат || Не || Не || |
| | 376 | |
| | 377 | '''Заклучок:''' |
| | 378 | Времето на извршување се намали од 0.242 ms на 0.212 ms, што претставува намалување од приближно 12.4%. Сепак, планот останува ист во однос на пристапот до табелите: PostgreSQL користи `Seq Scan`, а не новите индекси. Причината е малата количина на податоци: `transaction` има 12 редови, `transaction_breakdown` има 11 редови, а `transaction_account` има 5 редови. За ваква големина, секвенцијалното читање е поевтино од пристап преку индекс. Индексите сепак се соодветни за идно зголемување на базата, особено затоа што извештајот филтрира по `user_id` и по временски период. |
| | 379 | |
| | 380 | ==== Финален заклучок од анализата ==== |
| | 381 | |
| | 382 | Во сите три сценарија, PostgreSQL продолжи да користи `Seq Scan` и по додавање на предложените индекси. Тоа значи дека индексите не беа реално искористени во моменталниот execution plan. |
| | 383 | |
| | 384 | Ова однесување е очекувано поради малата количина на податоци во тест базата. Во моментот на тестирањето, најголемите релевантни табели имаат само 12 трансакции, 11 breakdown записи и 16 tag-assignment записи. За вакви табели, PostgreSQL правилно проценува дека целосно скенирање на табелата е поевтино од користење индекс. |
| | 385 | |
| | 386 | Иако execution time се намали во сите три сценарија, тоа не може директно да се припише на индексите, бидејќи execution plan-от не покажува `Index Scan`, `Bitmap Index Scan` или `Index Only Scan`. Малите разлики во времето најверојатно се резултат на кеширање, повторно користење на податоци во shared buffers и нормална варијација при извршување. |
| | 387 | |
| | 388 | Сепак, предложените индекси остануваат оправдани како подготовка за поголема количина на податоци. Со раст на бројот на корисници, трансакции, сметки, тагови и breakdown записи, индексите на `transaction.date`, `transaction_account.user_id`, `transaction_breakdown.transaction_id`, `transaction_breakdown.transaction_account_id`, `tag_assigned_to_transaction.transaction_id` и `tag_assigned_to_transaction.tag_id` ќе овозможат поефикасно филтрирање и поврзување на податоците во аналитичките извештаи. |