| 477 | | Бидејќи погледот користи сложени aggregation операции како {{{SUM}}}, {{{AVG}}}, {{{COUNT}}} и {{{GROUP BY}}}, planner-от проценува дека sequential processing е поефикасен од index traversal при обработка на голем број редици. |
| | 469 | Бидејќи погледот користи сложени aggregation операции како {{{SUM}}}, {{{AVG}}}, {{{COUNT}}} и {{{GROUP BY}}}, planner-от проценува дека sequential processing е поефикасен од index traversal при обработка на голем број редици. Поради ова, беше одлучено да се примени дополнителна оптимизација преку Materijализиран Поглед. |
| | 470 | |
| | 471 | === Оптимизација со Материјализиран Поглед === |
| | 472 | Бидејќи индексите не можеа значително да го подобрат времето на извршување поради природата на query-от (full-table aggregation со {{{GROUP BY}}}), беше креиран Материјализиран Поглед ({{{MATERIALIZED VIEW}}}) кој ја зачувува пресметаната агрегација и овозможува директно пребарување врз резултатот. |
| | 473 | |
| | 474 | За разлика од обичниот поглед кој го извршува query-от секој пат, Материјализираниот Поглед ги зачувува резултатите физички на диск, со што филтерот {{{WHERE average_rating >= 4.5}}} работи врз само 600 редици наместо врз милиони. |
| | 475 | {{{ |
| | 476 | CREATE MATERIALIZED VIEW mv_artist_dashboard AS |
| | 477 | SELECT |
| | 478 | b.bookable_id, |
| | 479 | b.display_name, |
| | 480 | COUNT(bk.booking_id) AS total_bookings, |
| | 481 | SUM( |
| | 482 | CASE |
| | 483 | WHEN p.payment_status = 'PAID' THEN p.amount |
| | 484 | ELSE 0 |
| | 485 | END |
| | 486 | ) AS total_earnings, |
| | 487 | ROUND(AVG(r.rating), 2) AS average_rating |
| | 488 | FROM Bookable b |
| | 489 | LEFT JOIN Offer o ON b.bookable_id = o.bookable_id |
| | 490 | LEFT JOIN Booking bk ON bk.offer_id = o.offer_id |
| | 491 | LEFT JOIN Payment p ON p.booking_id = bk.booking_id |
| | 492 | LEFT JOIN Review r ON r.booking_id = bk.booking_id |
| | 493 | GROUP BY b.bookable_id, b.display_name; |
| | 494 | |
| | 495 | CREATE UNIQUE INDEX idx_mv_dashboard_bookable_id |
| | 496 | ON mv_artist_dashboard(bookable_id); |
| | 497 | |
| | 498 | CREATE INDEX idx_mv_dashboard_rating |
| | 499 | ON mv_artist_dashboard(average_rating); |
| | 500 | }}} |
| | 501 | |
| | 502 | === Време на извршување со Материјализиран Поглед === |
| | 503 | '''5.1 - 0.111 ms''' |
| | 504 | {{{ |
| | 505 | Seq Scan on mv_artist_dashboard (cost=0.00..15.50 rows=200 width=394) (actual time=0.090..0.090 rows=0 loops=1) |
| | 506 | Filter: (average_rating >= 4.5) |
| | 507 | Rows Removed by Filter: 600 |
| | 508 | Planning Time: 0.321 ms |
| | 509 | Execution Time: 0.111 ms |
| | 510 | }}} |
| | 511 | |
| | 512 | По креирањето на Материјализираниот Поглед беше забележано драстично подобрување: |
| | 513 | * од ~31.3 s (со индекси) |
| | 514 | * на ~0.1 ms (со Материјализиран Поглед) |
| | 515 | |
| | 516 | Наместо да ги скенира милионите редици од табелите {{{Offer}}}, {{{Booking}}}, {{{Payment}}} и {{{Review}}}, PostgreSQL сега скенира само 600 редици од зачуваниот резултат. Ова претставува подобрување од околу '''281,000 пати''' во споредба со оригиналниот query со индекси. |
| | 517 | |
| | 518 | За да останат податоците ажурирани, Материјализираниот Поглед се освежува по секоја промена на релевантните табели: |
| | 519 | {{{ |
| | 520 | REFRESH MATERIALIZED VIEW CONCURRENTLY mv_artist_dashboard; |
| | 521 | }}} |
| | 522 | |