| | 1 | = Преглед: v_customer_loyalty_full_v2 = |
| | 2 | |
| | 3 | ||= Датотека ||= `views/06_customer_loyalty_view_v2.sql` || |
| | 4 | ||= Шема ||= `kbnteam` || |
| | 5 | ||= Категорија ||= Договори, Фактурирање и Верност || |
| | 6 | ||= Поврзани индекси ||= `indexes/v_customer_loyalty_full_v2_index.sql` || |
| | 7 | ||= Статус ||= '''Канонска верзија''' — препорачана за употреба наместо `v_customer_loyalty_full` || |
| | 8 | |
| | 9 | == Опис == |
| | 10 | Прикажува статус на верност, податоци за ниво и статистика на нарачки на купувачи. Користи CTE `order_stats` за агрегирање на вкупен приход, број на нарачки и последна нарачка по купувач. V2 верзијата е почиста и поефикасна од `v_customer_loyalty_full` бидејќи CTE-то е поделено наместо вградено подпрашање. |
| | 11 | |
| | 12 | == Зависности == |
| | 13 | ||= Табела ||= Тип на употреба || |
| | 14 | || `kbnteam.customer_loyalty` || Главна табела || |
| | 15 | || `kbnteam.customer` || JOIN — купувач || |
| | 16 | || `kbnteam.company` || JOIN — компанија || |
| | 17 | || `kbnteam.api_user` || JOIN — детали за корисник || |
| | 18 | || `kbnteam.customer_loyalty_status` || JOIN — статус на верност || |
| | 19 | || `kbnteam.loyalty_tier` || JOIN — ниво на верност || |
| | 20 | || `kbnteam.customer_order` || LEFT JOIN (CTE) — статистика на нарачки || |
| | 21 | |
| | 22 | == SQL Дефиниција == |
| | 23 | {{{ |
| | 24 | #!sql |
| | 25 | CREATE OR REPLACE VIEW kbnteam.v_customer_loyalty_full_v2 AS |
| | 26 | WITH order_stats AS ( |
| | 27 | SELECT |
| | 28 | o.customer_user_id, |
| | 29 | COUNT(*) AS order_count, |
| | 30 | COALESCE(SUM(o.order_total), 0)::numeric(14,2) AS total_spent, |
| | 31 | MAX(o.order_datetime) AS last_order_at |
| | 32 | FROM kbnteam.customer_order o |
| | 33 | GROUP BY o.customer_user_id |
| | 34 | ) |
| | 35 | SELECT |
| | 36 | cl.cus_loyalty_id, |
| | 37 | cl.user_id AS customer_user_id, |
| | 38 | cu.company_id, |
| | 39 | cmp.company_name, |
| | 40 | au.user_first_name, |
| | 41 | au.user_last_name, |
| | 42 | au.user_email, |
| | 43 | au.user_phone_no, |
| | 44 | cl.cus_loyalty_curr_points, |
| | 45 | cl.cus_loyalty_joined_at, |
| | 46 | cls.cus_loyalty_status_id, |
| | 47 | cls.cus_loyalty_status_name, |
| | 48 | lt.tier_id, |
| | 49 | lt.tier_name, |
| | 50 | lt.tier_discount_percentage, |
| | 51 | lt.tier_free_delivery_eligibility, |
| | 52 | lt.tier_priority_support, |
| | 53 | COALESCE(os.order_count, 0) AS order_count, |
| | 54 | COALESCE(os.total_spent, 0)::numeric(14,2) AS total_spent, |
| | 55 | os.last_order_at |
| | 56 | FROM kbnteam.customer_loyalty cl |
| | 57 | JOIN kbnteam.customer cu |
| | 58 | ON cu.user_id = cl.user_id |
| | 59 | JOIN kbnteam.company cmp |
| | 60 | ON cmp.company_id = cu.company_id |
| | 61 | JOIN kbnteam.api_user au |
| | 62 | ON au.user_id = cl.user_id |
| | 63 | JOIN kbnteam.customer_loyalty_status cls |
| | 64 | ON cls.cus_loyalty_status_id = cl.cus_loyalty_status_id |
| | 65 | JOIN kbnteam.loyalty_tier lt |
| | 66 | ON lt.tier_id = cl.tier_id |
| | 67 | LEFT JOIN order_stats os |
| | 68 | ON os.customer_user_id = cl.user_id; |
| | 69 | }}} |
| | 70 | |
| | 71 | == Тестирање на перформанси == |
| | 72 | |
| | 73 | === Препорачано тест прашање === |
| | 74 | {{{ |
| | 75 | #!sql |
| | 76 | SET search_path TO kbnteam; |
| | 77 | SET statement_timeout = '60s'; |
| | 78 | |
| | 79 | -- Тест 1: по компанија |
| | 80 | EXPLAIN (ANALYZE, BUFFERS, VERBOSE) |
| | 81 | SELECT * FROM kbnteam.v_customer_loyalty_full_v2 |
| | 82 | WHERE company_id = 1; |
| | 83 | |
| | 84 | -- Тест 2: по ниво на верност |
| | 85 | EXPLAIN (ANALYZE, BUFFERS, VERBOSE) |
| | 86 | SELECT * FROM kbnteam.v_customer_loyalty_full_v2 |
| | 87 | WHERE tier_id = 1; |
| | 88 | |
| | 89 | -- Тест 3: по купувач (директна точка пристап) |
| | 90 | EXPLAIN (ANALYZE, BUFFERS, VERBOSE) |
| | 91 | SELECT * FROM kbnteam.v_customer_loyalty_full_v2 |
| | 92 | WHERE customer_user_id = 1; |
| | 93 | }}} |
| | 94 | |
| | 95 | === Резултати пред индексирање === |
| | 96 | ||= Метрика ||= Тест 1 (company) ||= Тест 2 (tier) ||= Тест 3 (customer) || |
| | 97 | || Planning Time || ___ ms || ___ ms || ___ ms || |
| | 98 | || Execution Time || ___ ms || ___ ms || ___ ms || |
| | 99 | || Rows Returned || ___ || ___ || ___ || |
| | 100 | || customer_order scan || ___ || ___ || ___ || |
| | 101 | |
| | 102 | {{{ |
| | 103 | -- Излезот од EXPLAIN ANALYZE овде (пред индексирање) |
| | 104 | }}} |
| | 105 | |
| | 106 | === Применети индекси === |
| | 107 | {{{ |
| | 108 | #!sql |
| | 109 | -- indexes/v_customer_loyalty_full_v2_index.sql |
| | 110 | CREATE INDEX IF NOT EXISTS idx_customer_order_customer_user_id_order_datetime |
| | 111 | ON kbnteam.customer_order (customer_user_id, order_datetime DESC); |
| | 112 | }}} |
| | 113 | |
| | 114 | === Резултати по индексирање === |
| | 115 | ||= Метрика ||= Тест 1 (company) ||= Тест 2 (tier) ||= Тест 3 (customer) || |
| | 116 | || Planning Time || ___ ms || ___ ms || ___ ms || |
| | 117 | || Execution Time || ___ ms || ___ ms || ___ ms || |
| | 118 | || Rows Returned || ___ || ___ || ___ || |
| | 119 | || customer_order scan || ___ || ___ || ___ || |
| | 120 | |
| | 121 | {{{ |
| | 122 | -- Излезот од EXPLAIN ANALYZE овде (по индексирање) |
| | 123 | }}} |
| | 124 | |
| | 125 | === Анализа на подобрување === |
| | 126 | ||= Индекс ||= Помага на ||= Очекувана промена || |
| | 127 | || `idx_customer_order_customer_user_id_order_datetime` || CTE `order_stats` GROUP BY + MAX(order_datetime) || Seq Scan → Index Scan || |
| | 128 | |
| | 129 | ||= Метрика ||= Пред ||= По ||= Δ Подобрување || |
| | 130 | || Execution Time (Тест 3) || ___ ms || ___ ms || ___ % || |
| | 131 | |
| | 132 | '''Напомена:''' Индексот е особено ефективен при Тест 3 (по купувач) бидејќи CTE-то `order_stats` може директно да го скенира по `customer_user_id`. При целосен скен (Тест 1 или 2), подобрувањето зависи од бројот на редови. |