== Документација за оптимизација
[[html(views_optimization_documentation.pdf)]]
== Погледи
== v_staff_daily_schedule
Овој view служи за приказ на дневниот распоред на вработените.
Табелата `appointment` е главната табела бидејќи ги содржи сите информации за закажаните термини.
Се спојуваат:
* `user` за име на вработениот.
* `staff` за локацијата.
* `company_location` за адресата.
* `client` и `user` за информации за клиентот.
Се користат два `LATERAL JOIN`:
* Првиот ги агрегира сите улоги на вработениот од `staff_type`.
* Вториот ги агрегира сите услуги поврзани со терминот од `appointment_service`.
Филтерот:
{{{
WHERE status <> 'cancelled'
AND status <> 'completed'
}}}
се извршува најрано со што значително се намалува бројот на обработени термини.
Функцијата `LEAD()` пресметува временски јаз помеѓу два последователни термини без дополнителни self-join операции.
---
== v_staff_open_slots
Овој view ги враќа сите слободни термини за закажување.
Најпрво се креираат три мали агрегирани множества:
* `staff_roles`
* `staff_services`
* `staff_rating`
Со ова агрегирањето се извршува само еднаш.
Главната табела е `staff_time_slot`.
Филтрите:
{{{
appointment_id IS NULL
slot_start >= NOW()
slot_start < NOW() + INTERVAL '30 days'
}}}
се применуваат веднаш.
Потоа се прави JOIN со:
* `staff`
* `user`
* `company_location`
и LEFT JOIN со:
* `blocked_time`
за елиминација на блокираните термини.
Со условот:
{{{
b.block_id IS NULL
}}}
се задржуваат само реално достапните слотови.
---
== v_companies_by_category
Овој view овозможува пребарување компании според категорија и услуги.
CTE `company_services` прво ги агрегира сите активни услуги по компанија.
Филтерот:
{{{
WHERE s.is_active = TRUE
}}}
се применува пред агрегацијата.
Потоа се приклучуваат:
* `company_company_category`
* `company_category`
* `company`
На овој начин главниот SELECT работи со значително помал број редови.
---
== v_staff_service_menu
Овој view прикажува кои услуги ги нуди секој вработен.
Во CTE `staff_service_ratings` однапред се пресметуваат:
* просечна оцена
* број на рецензии
* број на извршувања
Само термините со статус:
{{{
completed
}}}
учествуваат во пресметката.
Ова значително ја намалува количината на податоци бидејќи не се анализираат активни или откажани термини.
---
== v_monthly_revenue_by_company
Овој view служи за финансиски извештаи.
Се користат само табелите:
* `invoice`
* `appointment`
* `company_location`
* `company`
Бидејќи `invoice` е значително помала од `appointment_service`, пресметката е многу поефикасна.
Сите финансиски агрегати:
* SUM
* AVG
* COUNT
се пресметуваат во една единствена GROUP BY операција.
---
== v_future_appointments_client_o
Овој view ги враќа идните термини на клиентите.
Филтерот:
{{{
appointment_date >= CURRENT_DATE
status <> 'cancelled'
}}}
се применува уште на почетокот.
Со тоа се елиминираат сите историски записи.
Се користи `LATERAL JOIN` за агрегација на услугите на секој термин поединечно наместо глобално GROUP BY врз целата табела `appointment_service`.
За овој view е креиран индекс:
{{{
idx_appointment_client_future
}}}
бидејќи пребарувањето најчесто се врши според клиент и датум.
---
== v_client_dashboard
Овој view е наменет за почетниот екран на клиентот.
Се користат две CTE структури:
* `upcoming`
* `recent_spend`
Тие однапред ги пресметуваат:
* идните термини
* потрошувачката во последните 30 дена
Потоа главниот SELECT само ги приклучува готовите агрегирани резултати.
Ова е поефикасно отколку секој пат да се пресметуваат агрегатите за секој клиент одново.
---
== mv_staff_avg_rating
Ова е Materialized View.
Наместо просечниот рејтинг да се пресметува секој пат кога се отвора профил на вработен, резултатот однапред се чува физички во базата.
Предности:
* многу побрзо читање
* помал број JOIN операции
* помал CPU трошок
Се освежува преку:
{{{
REFRESH MATERIALIZED VIEW CONCURRENTLY
}}}
што овозможува истовремено користење на податоците.
---
== v_staff_profile_m
Овој view прикажува целосен профил на вработен.
Наместо повторно да се пресметуваат оценки од `review`, се користи:
{{{
mv_staff_avg_rating
}}}
што значително го намалува времето на извршување.
Дополнително се користат два `LATERAL JOIN`:
* агрегирање на услуги
* агрегирање на улоги
Само активни корисници учествуваат во резултатот:
{{{
WHERE u.is_active = TRUE
}}}
---
== v_invoice_detail_o
Овој view е најдеталниот финансиски поглед.
Главната табела е `invoice`, бидејќи фактурите се значително помалку од сите термини и услуги во системот.
Се користат три `LATERAL JOIN`:
* агрегација на услуги од терминот
* агрегација на промо кодови
* агрегација на улоги на вработениот
Со ова секоја агрегација се извршува само за конкретната фактура.
Овој пристап е поефикасен од глобални GROUP BY операции над целата база.
---
== Индекси
Во решението се користи минимален број индекси:
* `idx_appointment_client_future`
* индекс над `mv_staff_avg_rating`
* `idx_appointment_staff_rating`
Целта е да се избегне прекумерно индексирање кое би ја забавило работата при INSERT, UPDATE и DELETE операции.
Избраните индекси покриваат само најчестите пребарувања:
* идни термини по клиент
* рејтинзи по вработен
* профил на вработен
Со ова се постигнува баланс помеѓу брзина на читање и брзина на запишување на податоци.