| | 1 | = Преглед: v_contracts_revenue = |
| | 2 | |
| | 3 | ||= Датотека ||= `views/05_contracts_revenue_view.sql` || |
| | 4 | ||= Шема ||= `kbnteam` || |
| | 5 | ||= Категорија ||= Договори, Фактурирање и Верност || |
| | 6 | ||= Поврзани индекси ||= `indexes/v_contracts_revenue_index.sql` || |
| | 7 | ||= Сложеност ||= Висока — 2 CTE со UNION + агрегации || |
| | 8 | |
| | 9 | == Опис == |
| | 10 | Резимира приход по компанија и ресторан под активни договори. Го користи CTE `order_restaurants` за да определи кој ресторан го послужил секој редослед преку `UNION` на `order_meal` и `order_drink`. Вториот CTE `contract_metrics` агрегира броеви на нарачки и вкупен приход. Важен преглед за финансиско известување. |
| | 11 | |
| | 12 | == Зависности == |
| | 13 | ||= Табела ||= Тип на употреба || |
| | 14 | || `kbnteam.contract` || Главна табела || |
| | 15 | || `kbnteam.company` || JOIN — компанија || |
| | 16 | || `kbnteam.restaurant` || JOIN — ресторан || |
| | 17 | || `kbnteam.contract_status` || JOIN — статус на договор || |
| | 18 | || `kbnteam.customer_order` || JOIN (CTE) — нарачки || |
| | 19 | || `kbnteam.company_order` || JOIN (CTE) — компаниски нарачки || |
| | 20 | || `kbnteam.order_meal` || JOIN (CTE, UNION) — оброци во нарачки || |
| | 21 | || `kbnteam.meal` || JOIN (CTE) — ресторан на оброкот || |
| | 22 | || `kbnteam.order_drink` || JOIN (CTE, UNION) — пијачи во нарачки || |
| | 23 | || `kbnteam.drink` || JOIN (CTE) — ресторан на пијачот || |
| | 24 | |
| | 25 | == SQL Дефиниција == |
| | 26 | {{{ |
| | 27 | #!sql |
| | 28 | CREATE OR REPLACE VIEW kbnteam.v_contracts_revenue AS |
| | 29 | WITH order_restaurants AS ( |
| | 30 | SELECT DISTINCT |
| | 31 | om.order_id, |
| | 32 | m.rest_id |
| | 33 | FROM kbnteam.order_meal om |
| | 34 | JOIN kbnteam.meal m ON m.meal_id = om.meal_id |
| | 35 | |
| | 36 | UNION |
| | 37 | |
| | 38 | SELECT DISTINCT |
| | 39 | od.order_id, |
| | 40 | d.rest_id |
| | 41 | FROM kbnteam.order_drink od |
| | 42 | JOIN kbnteam.drink d ON d.drink_id = od.drink_id |
| | 43 | ), |
| | 44 | contract_metrics AS ( |
| | 45 | SELECT |
| | 46 | co.company_id, |
| | 47 | orr.rest_id, |
| | 48 | COUNT(DISTINCT co.comp_order_id) AS company_order_count, |
| | 49 | COUNT(DISTINCT o.order_id) AS customer_order_count, |
| | 50 | COALESCE(SUM(o.order_total), 0)::numeric(14,2) AS total_revenue |
| | 51 | FROM kbnteam.customer_order o |
| | 52 | JOIN kbnteam.company_order co ON co.comp_order_id = o.comp_order_id |
| | 53 | JOIN order_restaurants orr ON orr.order_id = o.order_id |
| | 54 | GROUP BY co.company_id, orr.rest_id |
| | 55 | ) |
| | 56 | SELECT |
| | 57 | ct.contract_id, |
| | 58 | cmp.company_id, |
| | 59 | cmp.company_name, |
| | 60 | r.rest_id, |
| | 61 | r.rest_name, |
| | 62 | cs.contract_status_name, |
| | 63 | ct.contract_start_date, |
| | 64 | ct.contract_end_date, |
| | 65 | COALESCE(cm.company_order_count, 0) AS company_order_count, |
| | 66 | COALESCE(cm.customer_order_count, 0) AS customer_order_count, |
| | 67 | COALESCE(cm.total_revenue, 0)::numeric(14,2) AS total_revenue |
| | 68 | FROM kbnteam.contract ct |
| | 69 | JOIN kbnteam.company cmp ON cmp.company_id = ct.company_id |
| | 70 | JOIN kbnteam.restaurant r ON r.rest_id = ct.rest_id |
| | 71 | JOIN kbnteam.contract_status cs ON cs.contract_status_id = ct.contract_status_id |
| | 72 | LEFT JOIN contract_metrics cm |
| | 73 | ON cm.company_id = ct.company_id |
| | 74 | AND cm.rest_id = ct.rest_id; |
| | 75 | }}} |
| | 76 | |
| | 77 | == Тестирање на перформанси == |
| | 78 | |
| | 79 | === Препорачано тест прашање === |
| | 80 | {{{ |
| | 81 | #!sql |
| | 82 | SET search_path TO kbnteam; |
| | 83 | SET statement_timeout = '60s'; |
| | 84 | |
| | 85 | -- Тест 1: по компанија (тестира idx на contract) |
| | 86 | EXPLAIN (ANALYZE, BUFFERS, VERBOSE) |
| | 87 | SELECT * FROM kbnteam.v_contracts_revenue |
| | 88 | WHERE company_id = 1; |
| | 89 | |
| | 90 | -- Тест 2: по ресторан |
| | 91 | EXPLAIN (ANALYZE, BUFFERS, VERBOSE) |
| | 92 | SELECT * FROM kbnteam.v_contracts_revenue |
| | 93 | WHERE rest_id = 1; |
| | 94 | }}} |
| | 95 | |
| | 96 | === Резултати пред индексирање === |
| | 97 | ||= Метрика ||= Тест 1 (по company_id) ||= Тест 2 (по rest_id) || |
| | 98 | || Planning Time || ___ ms || ___ ms || |
| | 99 | || Execution Time || ___ ms || ___ ms || |
| | 100 | || Rows Returned || ___ || ___ || |
| | 101 | || contract scan || ___ || ___ || |
| | 102 | || order_meal scan || ___ || ___ || |
| | 103 | || customer_order scan || ___ || ___ || |
| | 104 | |
| | 105 | {{{ |
| | 106 | -- Излезот од EXPLAIN ANALYZE овде (пред индексирање) |
| | 107 | }}} |
| | 108 | |
| | 109 | === Применети индекси === |
| | 110 | {{{ |
| | 111 | #!sql |
| | 112 | -- indexes/v_contracts_revenue_index.sql |
| | 113 | CREATE INDEX IF NOT EXISTS idx_order_meal_order_id_meal_id |
| | 114 | ON kbnteam.order_meal (order_id, meal_id); |
| | 115 | |
| | 116 | CREATE INDEX IF NOT EXISTS idx_order_drink_order_id_drink_id |
| | 117 | ON kbnteam.order_drink (order_id, drink_id); |
| | 118 | |
| | 119 | CREATE INDEX IF NOT EXISTS idx_customer_order_comp_order_id |
| | 120 | ON kbnteam.customer_order (comp_order_id); |
| | 121 | |
| | 122 | CREATE INDEX IF NOT EXISTS idx_contract_company_id_rest_id |
| | 123 | ON kbnteam.contract (company_id, rest_id); |
| | 124 | }}} |
| | 125 | |
| | 126 | === Резултати по индексирање === |
| | 127 | ||= Метрика ||= Тест 1 (по company_id) ||= Тест 2 (по rest_id) || |
| | 128 | || Planning Time || ___ ms || ___ ms || |
| | 129 | || Execution Time || ___ ms || ___ ms || |
| | 130 | || Rows Returned || ___ || ___ || |
| | 131 | || contract scan || ___ || ___ || |
| | 132 | || order_meal scan || ___ || ___ || |
| | 133 | || customer_order scan || ___ || ___ || |
| | 134 | |
| | 135 | {{{ |
| | 136 | -- Излезот од EXPLAIN ANALYZE овде (по индексирање) |
| | 137 | }}} |
| | 138 | |
| | 139 | === Анализа на подобрување === |
| | 140 | ||= Индекс ||= Помага на ||= Очекувана промена || |
| | 141 | || `idx_contract_company_id_rest_id` || JOIN-от во `contract_metrics` и главниот SELECT || Seq Scan → Index Scan || |
| | 142 | || `idx_customer_order_comp_order_id` || JOIN со `company_order` во CTE || Seq Scan → Index Scan || |
| | 143 | || `idx_order_meal_order_id_meal_id` || CTE `order_restaurants` UNION || Seq Scan → Index Scan || |
| | 144 | || `idx_order_drink_order_id_drink_id` || CTE `order_restaurants` UNION || Seq Scan → Index Scan || |
| | 145 | |
| | 146 | ||= Метрика ||= Пред ||= По ||= Δ Подобрување || |
| | 147 | || Execution Time (Тест 1) || ___ ms || ___ ms || ___ % || |
| | 148 | || Execution Time (Тест 2) || ___ ms || ___ ms || ___ % || |