| | 1 | Нормализација |
| | 2 | == Де-нормализирана база на податоци |
| | 3 | |
| | 4 | Се тргнува од една глобална, де-нормализирана релација што ги содржи атрибутите од целиот модел: |
| | 5 | |
| | 6 | R = { user_id, email, username, password, training_user_id, training_gender, training_age, training_weight, training_id, training_date, training_type, training_duration, training_calories, investor_user_id, asset_id, asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity, weight_user_id, weight_current, weight_height, weight_goal_weight, weight_goal_calories, daily_intake_id, daily_intake_date, daily_intake_calories, discipline_user_id, custom_tracking_id, custom_tracking_name, task_id, task_name, task_finished, daily_completion_id, daily_completion_date, daily_completion_percent, finance_user_id, finance_spending_budget, finance_saving_budget, finance_investing_budget, finance_donation_budget, finance_credit, income_id, income_date, income_amount } |
| | 7 | |
| | 8 | Оваа релација е де-нормализирана затоа што содржи повторливи групи, како и зависности од атрибути што не се клуч. |
| | 9 | |
| | 10 | == Функционални зависности: |
| | 11 | |
| | 12 | FD1: user_id -> email, username, password |
| | 13 | FD2: email -> user_id, username, password |
| | 14 | FD3: username -> user_id, email, password |
| | 15 | FD4: training_user_id -> training_gender, training_age, training_weight |
| | 16 | FD5: training_id -> training_user_id, training_date, training_type, training_duration, training_calories |
| | 17 | FD6: investor_user_id -> user_id |
| | 18 | FD7: asset_id -> investor_user_id, asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity |
| | 19 | FD8: weight_user_id -> weight_current, weight_height, weight_goal_weight, weight_goal_calories |
| | 20 | FD9: daily_intake_id -> weight_user_id, daily_intake_date, daily_intake_calories |
| | 21 | FD10: discipline_user_id -> user_id |
| | 22 | FD11: custom_tracking_id -> user_id, custom_tracking_name |
| | 23 | FD12: task_id -> discipline_user_id, custom_tracking_id, task_name, task_finished |
| | 24 | FD13: daily_completion_id -> user_id, daily_completion_date, daily_completion_percent |
| | 25 | FD14: (task_id, daily_completion_id) -> / |
| | 26 | FD15: finance_user_id -> finance_spending_budget, finance_saving_budget, finance_investing_budget, finance_donation_budget, finance_credit |
| | 27 | FD16: income_id -> finance_user_id, income_date, income_amount |
| | 28 | Леви и десен дел: |
| | 29 | |
| | 30 | Леви: user_id, email, username, training_user_id, training_id, investor_user_id, asset_id, weight_user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, finance_user_id, income_id |
| | 31 | Десен: password, training_gender, training_age, training_weight, training_date, training_type, training_duration, training_calories, asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity, weight_current, weight_height, weight_goal_weight, weight_goal_calories, daily_intake_date, daily_intake_calories, custom_tracking_name, task_name, task_finished, daily_completion_date, daily_completion_percent, finance_spending_budget, finance_saving_budget, finance_investing_budget, finance_donation_budget, finance_credit, income_date, income_amount |
| | 32 | Леви и десен дел: |
| | 33 | |
| | 34 | user_id, training_user_id, training_id, investor_user_id, asset_id, weight_user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, finance_user_id, income_id |
| | 35 | == Глобална релација |
| | 36 | |
| | 37 | R = { user_id, email, username, password, training_user_id, training_gender, training_age, training_weight, training_id, training_date, training_type, training_duration, training_calories, investor_user_id, asset_id, asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity, weight_user_id, weight_current, weight_height, weight_goal_weight, weight_goal_calories, daily_intake_id, daily_intake_date, daily_intake_calories, discipline_user_id, custom_tracking_id, custom_tracking_name, task_id, task_name, task_finished, daily_completion_id, daily_completion_date, daily_completion_percent, finance_user_id, finance_spending_budget, finance_saving_budget, finance_investing_budget, finance_donation_budget, finance_credit, income_id, income_date, income_amount } |
| | 38 | |
| | 39 | == Покривачи |
| | 40 | |
| | 41 | user_id+ = { user_id, email, username, password } -> не ги содржи сите атрибути |
| | 42 | training_user_id+ = { training_user_id, training_gender, training_age, training_weight } -> не ги содржи сите атрибути |
| | 43 | training_id+ = { training_id, training_user_id, training_date, training_type, training_duration, training_calories } -> не ги содржи сите атрибути |
| | 44 | investor_user_id+ = { investor_user_id, user_id } -> не ги содржи сите атрибути |
| | 45 | asset_id+ = { asset_id, investor_user_id, asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity } -> не ги содржи сите атрибути |
| | 46 | weight_user_id+ = { weight_user_id, weight_current, weight_height, weight_goal_weight, weight_goal_calories } -> не ги содржи сите атрибути |
| | 47 | daily_intake_id+ = { daily_intake_id, weight_user_id, daily_intake_date, daily_intake_calories } -> не ги содржи сите атрибути |
| | 48 | discipline_user_id+ = { discipline_user_id, user_id } -> не ги содржи сите атрибути |
| | 49 | custom_tracking_id+ = { custom_tracking_id, user_id, custom_tracking_name } -> не ги содржи сите атрибути |
| | 50 | task_id+ = { task_id, discipline_user_id, custom_tracking_id, task_name, task_finished } -> не ги содржи сите атрибути |
| | 51 | daily_completion_id+ = { daily_completion_id, user_id, daily_completion_date, daily_completion_percent } -> не ги содржи сите атрибути |
| | 52 | finance_user_id+ = { finance_user_id, finance_spending_budget, finance_saving_budget, finance_investing_budget, finance_donation_budget, finance_credit } -> не ги содржи сите атрибути |
| | 53 | income_id+ = { income_id, finance_user_id, income_date, income_amount } -> не ги содржи сите атрибути |
| | 54 | {task_id, daily_completion_id}+ = { task_id, daily_completion_id } -> не ги содржи сите атрибути |
| | 55 | == Спојување покривачи |
| | 56 | |
| | 57 | Бидејќи атрибутите што се појавуваат само на левата страна не можат да се изведат на друг начин, тие мора да бидат дел од примарниот клуч. |
| | 58 | |
| | 59 | Земајќи ги сите леви атрибути заедно, добиваме минимален суперклуч: |
| | 60 | |
| | 61 | { user_id, training_user_id, training_id, investor_user_id, asset_id, weight_user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, finance_user_id, income_id } |
| | 62 | |
| | 63 | Во нашата нормализирана конструкција, ова е теоретскиот глобален кандидат-ключ на де-нормализираната релација. |
| | 64 | |
| | 65 | Избран примарен клуч: { user_id, training_user_id, training_id, investor_user_id, asset_id, weight_user_id, daily_intake_id, discipline_user_id, custom_tracking_id, task_id, daily_completion_id, finance_user_id, income_id } |
| | 66 | |
| | 67 | == Проверка за 1НФ |
| | 68 | |
| | 69 | Бидејќи релацијата содржи повторливи групи и неатомски листи во де-нормализираниот поглед, не ја задоволува 1НФ. |
| | 70 | |
| | 71 | == Декомпозиција по 1НФ |
| | 72 | |
| | 73 | Релација што се анализира |
| | 74 | R |
| | 75 | |
| | 76 | Проблем |
| | 77 | Лист атрибутите и повторливите групи не се атомски. |
| | 78 | |
| | 79 | Прва декомпозиција |
| | 80 | TASKS(task_id, discipline_user_id, custom_tracking_id, task_name, task_finished) |
| | 81 | TASK_DAILY_COMPLETION(task_id, daily_completion_id) |
| | 82 | Резултат |
| | 83 | Се добиваат атомски вредности и релации со локални клучеви. |
| | 84 | |
| | 85 | == Проверка за 2НФ |
| | 86 | |
| | 87 | R не ја задоволува 2НФ поради парцијални зависности, на пример: |
| | 88 | |
| | 89 | user_id -> email, username, password |
| | 90 | training_user_id -> training_gender, training_age, training_weight |
| | 91 | asset_id -> asset_ticker_symbol, asset_buy_price, asset_buy_date, asset_quantity |
| | 92 | == Декомпозиција по 2НФ |
| | 93 | |
| | 94 | Атрибутите се групираат според тоа од кој клуч зависат: |
| | 95 | |
| | 96 | USERS(user_id, email, username, password) |
| | 97 | TRAINING_USERS(user_id, gender, age, weight) |
| | 98 | TRAINING_SESSIONS(training_id, training_user_id, date, type, duration, calories) |
| | 99 | INVESTOR_USERS(user_id) |
| | 100 | ASSETS(asset_id, user_id, ticker_symbol, buy_price, buy_date, quantity) |
| | 101 | WEIGHT_USERS(user_id, weight, height, goal_weight, goal_calories) |
| | 102 | DAILY_INTAKES(daily_intake_id, user_id, date, calories) |
| | 103 | DISCIPLINE_USERS(user_id) |
| | 104 | CUSTOM_TRACKING_CATEGORIES(custom_tracking_id, user_id, name) |
| | 105 | TASKS(task_id, discipline_user_id, custom_tracking_id, task_name, task_finished) |
| | 106 | DAILY_COMPLETION(daily_completion_id, user_id, date, procent) |
| | 107 | TASK_DAILY_COMPLETION(task_id, daily_completion_id) |
| | 108 | FINANCE_USERS(user_id, spending_budget, saving_budget, investing_budget, donation_budget, credit) |
| | 109 | INCOMES(income_id, user_id, date, amount) |
| | 110 | == Проверка за 3НФ |
| | 111 | |
| | 112 | Ги разгледуваме релациите добиени по 2НФ. |
| | 113 | |
| | 114 | Проблематични транзитивни/изведени атрибути се: |
| | 115 | |
| | 116 | num_tasks |
| | 117 | tasks |
| | 118 | weight_user_id во TRAINING_SESSIONS како непотребна зависност за оваа верзија на моделот |
| | 119 | == Декомпозиција по 3НФ |
| | 120 | |
| | 121 | DISCIPLINE_USERS(user_id) -> се задржува само идентификаторот што ја врзува дисциплинската улога со USERS. |
| | 122 | |
| | 123 | CUSTOM_TRACKING_CATEGORIES(custom_tracking_id, user_id, name) -> се задржува само името на категоријата, без броење и листи на задачи. |
| | 124 | |
| | 125 | TRAINING_SESSIONS(training_id, training_user_id, date, type, duration, calories) -> сесијата се врзува само со training_user_id. |
| | 126 | |
| | 127 | Резултат |
| | 128 | Нема не-клучен атрибут што зависи од друг не-клучен атрибут во истата релација. |
| | 129 | |
| | 130 | == Проверка за БКНФ |
| | 131 | |
| | 132 | Сите добиени релации се во БКНФ, бидејќи секој детерминант е кандидат-ключ во својата релација. |
| | 133 | |
| | 134 | Особено: |
| | 135 | |
| | 136 | USERS ги задржува алтернативните клучеви email и username |
| | 137 | TASK_DAILY_COMPLETION(task_id, daily_completion_id) е спојна релација без не-клучни атрибути |
| | 138 | профилните релации со user_id се чисти 1:1 продолжувања на USERS |
| | 139 | == Финален резултат и дискусија |
| | 140 | |
| | 141 | == Нормализиран релациски модел |
| | 142 | |
| | 143 | Финалниот модел што го користиме во тековната имплементација е: |
| | 144 | |
| | 145 | USERS |
| | 146 | TRAINING_USERS |
| | 147 | TRAINING_SESSIONS |
| | 148 | INVESTOR_USERS |
| | 149 | ASSETS |
| | 150 | WEIGHT_USERS |
| | 151 | DAILY_INTAKES |
| | 152 | DISCIPLINE_USERS |
| | 153 | CUSTOM_TRACKING_CATEGORIES |
| | 154 | TASKS |
| | 155 | DAILY_COMPLETION |
| | 156 | TASK_DAILY_COMPLETION |
| | 157 | FINANCE_USERS |
| | 158 | INCOMES |
| | 159 | == Дискусија |
| | 160 | |
| | 161 | Разлики во однос на претходниот дизајн: |
| | 162 | |
| | 163 | Се отстранети num_tasks и tasks од дисциплинските табели. |
| | 164 | Се отстранета непотребната релација weight_user_id од TRAINING_SESSIONS. |
| | 165 | Се задржуваат профилните табели со user_id како заеднички примарен и странски клуч. |
| | 166 | Одлука за следните фази: |
| | 167 | |
| | 168 | Овој нормализиран модел останува извор на вистина. |
| | 169 | API форматот може да остане стабилен, додека внатрешната шема е нормализирана. |
| | 170 | DDL и DML скриптите треба да ја следат оваа шема. |