| 308 | | Во вакви ситуации planner-от проценува дека sequential processing е поефикасен од index traversal, па индексите имаат ограничено влијание врз вкупното време на извршување. |
| | 300 | Во вакви ситуации planner-от проценува дека sequential processing е поефикасен од index traversal, па индексите имаат ограничено влијание врз вкупното време на извршување. Поради ова, беше одлучено да се примени дополнителна оптимизација преку Материјализиран Поглед. |
| | 301 | |
| | 302 | === Оптимизација со Материјализиран Поглед === |
| | 303 | Бидејќи индексите не можеа значително да го подобрат времето на извршување поради природата на query-от (full-table aggregation со {{{GROUP BY}}} и повеќе {{{Hash Join}}} операции), беше креиран Материјализиран Поглед ({{{MATERIALIZED VIEW}}}) кој ја зачувува пресметаната агрегација и овозможува директно пребарување врз резултатот. |
| | 304 | |
| | 305 | За разлика од обичниот поглед кој го извршува query-от секој пат, Материјализираниот Поглед ги зачувува резултатите физички на диск, со што филтерот {{{WHERE city = 'Skopje'}}} работи врз само неколку стотици редици наместо врз милиони. |
| | 306 | {{{ |
| | 307 | CREATE MATERIALIZED VIEW mv_public_artist_profiles AS |
| | 308 | SELECT |
| | 309 | b.bookable_id, |
| | 310 | b.display_name, |
| | 311 | b.bookable_type, |
| | 312 | l.city, |
| | 313 | g.genre_name, |
| | 314 | ROUND(AVG(r.rating), 2) AS average_rating, |
| | 315 | COUNT(r.review_id) AS total_reviews |
| | 316 | FROM Bookable b |
| | 317 | LEFT JOIN Location l ON b.location_id = l.location_id |
| | 318 | LEFT JOIN BookableGenre bg ON b.bookable_id = bg.bookable_id |
| | 319 | LEFT JOIN Genre g ON bg.genre_id = g.genre_id |
| | 320 | LEFT JOIN Offer o ON b.bookable_id = o.bookable_id |
| | 321 | LEFT JOIN Booking bk ON bk.offer_id = o.offer_id |
| | 322 | LEFT JOIN Review r ON r.booking_id = bk.booking_id |
| | 323 | GROUP BY b.bookable_id, b.display_name, b.bookable_type, l.city, g.genre_name; |
| | 324 | |
| | 325 | CREATE UNIQUE INDEX idx_mv_profiles_bookable_id |
| | 326 | ON mv_public_artist_profiles(bookable_id); |
| | 327 | |
| | 328 | CREATE INDEX idx_mv_profiles_city |
| | 329 | ON mv_public_artist_profiles(city); |
| | 330 | |
| | 331 | CREATE INDEX idx_mv_profiles_rating |
| | 332 | ON mv_public_artist_profiles(average_rating DESC); |
| | 333 | }}} |
| | 334 | |
| | 335 | === Време на извршување со Материјализиран Поглед === |
| | 336 | '''3.1 - 0.147 ms''' |
| | 337 | {{{ |
| | 338 | Bitmap Heap Scan on mv_public_artist_profiles (cost=4.35..24.46 rows=9 width=856) (actual time=0.040..0.114 rows=213 loops=1) |
| | 339 | Recheck Cond: ((city)::text = 'Skopje'::text) |
| | 340 | Heap Blocks: exact=16 |
| | 341 | -> Bitmap Index Scan on idx_mv_profiles_city (cost=0.00..4.34 rows=9 width=0) (actual time=0.022..0.022 rows=213 loops=1) |
| | 342 | Index Cond: ((city)::text = 'Skopje'::text) |
| | 343 | Planning Time: 0.275 ms |
| | 344 | Execution Time: 0.147 ms |
| | 345 | }}} |
| | 346 | |
| | 347 | По креирањето на Материјализираниот Поглед беше забележано драстично подобрување: |
| | 348 | * од ~15.2 s (со индекси) |
| | 349 | * на ~0.147 ms (со Материјализиран Поглед) |
| | 350 | |
| | 351 | Наместо да ги скенира милионите редици од табелите {{{Offer}}}, {{{Booking}}} и {{{Review}}}, PostgreSQL сега користи {{{Bitmap Index Scan}}} директно врз зачуваниот резултат преку индексот на {{{city}}}. Ова претставува подобрување од околу '''103,000 пати''' во споредба со оригиналниот query со индекси. |
| | 352 | |
| | 353 | За да останат податоците ажурирани, Материјализираниот Поглед се освежува по секоја промена на релевантните табели: |
| | 354 | {{{ |
| | 355 | REFRESH MATERIALIZED VIEW CONCURRENTLY mv_public_artist_profiles; |
| | 356 | }}} |