Changes between Version 6 and Version 7 of normalization
- Timestamp:
- 09/20/25 15:31:41 (4 weeks ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
normalization
v6 v7 1 == Нормализација и подобрувања на дизајнот==1 == Нормализација (од глобална релација до 3NF) — методологија и докази == 2 2 3 Во оваа секција е прикажана нормализацијата на целокупниот ER модел до трета нормална форма (3NF), за да се отстранат зависностите, се избегне дуплирање на податоци и да се подобри интегритетот. 3 Овој дел ја прикажува нормализацијата преку глобален модел и формални чекори до 3NF, 4 со цел елиминација на повторувања, парцијални и транзитивни зависности и аномалии 5 при INSERT/UPDATE/DELETE. 4 6 5 7 [attachment:normalized_ddl_schema.sql] 6 8 7 === Објаснување на нормализацијата===9 === 1) Глобална универзална релација и атрибути === 8 10 9 Н ормализацијата беше извршена како анализа на целиот модел составен од 12 табели, при што се разгледуваа зависностите помеѓу табелите, а не само во рамки на секоја одделно. На тој начин се овозможи откривање на заеднички функционални зависности и елиминирање на дуплирани ентитети и атрибути.11 Нека глобалната релација е составена од следните 11 ентитети: 10 12 11 Клучни подобрувања: 12 - Централизација на статусите преку единствена табела **statuses**, користена и во **subscription** и **notifications**. 13 - Централизација на земјите преку табелата **countries**, споделена од **actors** и **locations**. 14 - Елиминирање на транзитивни зависности преку атрибути како **role_id**, **country_code**, и **type_code**. 15 - Генерација на дополнителни референтни табели како **actor_types**, **roles**, и **statuses** со foreign keys за интегритет. 13 * **Events**: `global_event_id, sql_date, month_year, year, fraction_date, is_root_event, event_code, goldstein_scale, num_mentions, num_sources, num_articles, avg_tone` 14 * **Actors**: `actor_id, actor_code, actor_name, country_code, type_code` 15 * **Locations**: `location_id, full_name, country_code, adm1_code, latitude, longitude, feature_id` 16 * **Event Details**: `global_event_id, actor_id, location_id` 17 * **Users**: `user_id, first_name, last_name, email, password_hash, role_id, last_login_date, register_date` 18 * **Roles**: `role_id, role_name` 19 * **Plan**: `plan_id, plan_name, max_events, max_notifications, max_predictions` 20 * **Subscription**: `subscription_id, user_id, plan_id, start_date, end_date, status` 21 * **Notifications**: `notification_id, user_id, event_id, notification_date, status` 22 * **Predictions**: `prediction_id, event_id, actor_id, predicted_date, prediction_type, confidence_score` 23 * **Conflict Risk**: `conflict_id, actor1_id, actor2_id, risk_score, predicted_date, description` 24 * **Event Analytics**: `analytics_id, actor_id, event_id, date, conflict_coefficient, mentions_count, avg_tone, description` 16 25 17 Со оваа нормализација до 3NF, се подобрува конзистентноста, се намалува дуплирањето на податоци и се поедноставува одржувањето на базата. 26 === 2) Клучни функционални зависности (F) === 18 27 28 Изведени oд PK/FK и бизнис-правила: 19 29 20 === **actors**(**actor_id**, **actor_code**, **actor_name**, **country_code**, **type_code**) === 30 * `global_event_id → sql_date, month_year, year, fraction_date, is_root_event, event_code, goldstein_scale, num_mentions, num_sources, num_articles, avg_tone` 31 * `actor_id → actor_code, actor_name, country_code, type_code` 32 * `location_id → full_name, country_code, adm1_code, latitude, longitude, feature_id` 33 * `user_id → first_name, last_name, email, password_hash, role_id, last_login_date, register_date` 34 * `role_id → role_name` 35 * `plan_id → plan_name, max_events, max_notifications, max_predictions` 36 * `subscription_id → user_id, plan_id, start_date, end_date, status` 37 * `notification_id → user_id, event_id, notification_date, status` 38 * `prediction_id → event_id, actor_id, predicted_date, prediction_type, confidence_score` 39 * `conflict_id → actor1_id, actor2_id, risk_score, predicted_date, description` 40 * `analytics_id → actor_id, event_id, date, conflict_coefficient, mentions_count, avg_tone, description` 21 41 22 Функционални зависности: 23 **actor_id** → **actor_code**, **actor_name**, **country_code**, **type_code** 24 **country_code** → **country_name** 25 **type_code** → **type_description** 42 Транзитивни зависности: 43 * `country_code → country_name` 44 * `type_code → type_description` 45 * `status → status_description` 26 46 27 1NF: Атомски вредности / 28 2NF: Сите атрибути зависат од примарниот клуч / 29 3NF: Постои транзитивна зависност → **actor_id** → **country_code** → **country_name** 47 === 3) Прва нормална форма (1NF) === 30 48 31 Декомпозиција: 32 **actors**(**actor_id**, **actor_code**, **actor_name**, **country_code**, **type_code**) 33 **countries**(**country_code**, **country_name**) 34 **actor_types**(**type_code**, **type_description**) 49 Сите атрибути се атомски и нема повторувачки групи. 50 Мултивредносните атрибути за актери и локации кај настаните се издвоени во 51 посебна релација со составен клуч: 35 52 36 === **locations**(**location_id**, **full_name**, **country_code**, **adm1_code**, **latitude**, **longitude**, **feature_id**) === 53 {{{ 54 EventDetails(global_event_id, actor_id, location_id) 55 PK = (global_event_id, actor_id, location_id) 56 }}} 37 57 38 Функционални зависности: 39 **location_id** → **full_name**, **country_code**, **adm1_code**, **latitude**, **longitude**, **feature_id** 40 **country_code** → **country_name** 58 Со ова сите релации се во 1NF. 41 59 42 1NF: Атомски вредности / 43 2NF: Сите атрибути зависат од примарниот клуч / 44 3NF: Транзитивна зависност преку **country_code** 60 === 4) Втора нормална форма (2NF) === 45 61 46 Декомпозиција: 47 **locations**(**location_id**, **full_name**, **country_code**, **adm1_code**, **latitude**, **longitude**, **feature_id**) 48 **countries**(**country_code**, **country_name**) 62 Критериум: кај релации со составен PK, ниту еден нефункционален атрибут да не зависи само од дел од PK. 49 63 50 === **users**(**user_id**, **first_name**, **last_name**, **email**, **password_hash**, **role_id**, **last_login_date**, **register_date**) === 64 *Проверка:* 65 {{{ 66 R_EventDetails(global_event_id, actor_id, location_id) 67 FDs: (global_event_id, actor_id, location_id) → ∅ 68 }}} 51 69 52 Функционални зависности: 53 **user_id** → **first_name**, **last_name**, **email**, **password_hash**, **role_id**, **last_login_date**, **register_date** 54 **role_id** → **role_name** 70 Нема нефункционални атрибути што зависат од дел од составениот клуч. 71 Кај сите останати ентитети PK е едноставен, па по дефиниција се во 2NF. 55 72 56 1NF: Атомски вредности / 57 2NF: Зависности од целиот клуч / 58 3NF: Транзитивна зависност преку **role_id** 73 Со тоа сите релации се во 2NF. 59 74 60 Декомпозиција: 61 **users**(**user_id**, **first_name**, **last_name**, **email**, **password_hash**, **role_id**, **last_login_date**, **register_date**) 62 **roles**(**role_id**, **role_name**) 75 === 5) Трета нормална форма (3NF) === 63 76 64 === **subscription**(**subscription_id**, **user_id**, **plan_id**, **start_date**, **end_date**, **status**) === 77 Критериум: атрибут што не е клуч да не зависи транзитивно од клуч преку друг атрибут што не е клуч. 65 78 66 Функционални зависности: 67 **subscription_id** → **user_id**, **plan_id**, **start_date**, **end_date**, **status** 68 **status** → **status_description** 79 Транзитивни зависности во глобалната релација: 80 {{{ 81 country_code → country_name 82 type_code → type_description 83 status → status_description 84 }}} 69 85 70 1NF: Атомски вредности / 71 2NF: Сите зависности од клучот / 72 3NF: Транзитивна зависност преку **status** 86 Разложување со проекции: 87 {{{ 88 Actors = π_{actor_id, actor_code, actor_name, country_code, type_code}(R) 89 Countries = π_{country_code, country_name}(R) 90 ActorTypes = π_{type_code, type_description}(R) 73 91 74 Декомпозиција: 75 **subscription**(**subscription_id**, **user_id**, **plan_id**, **start_date**, **end_date**, **status_code**) 76 **statuses**(**status_code**, **status_description**) 92 Locations = π_{location_id, full_name, country_code, adm1_code, latitude, longitude, feature_id}(R) 93 Countries = π_{country_code, country_name}(R) 77 94 78 === **notifications**(**notification_id**, **user_id**, **event_id**, **notification_date**, **status**) === 95 Subscription = π_{subscription_id, user_id, plan_id, start_date, end_date, status}(R) 96 Notifications = π_{notification_id, user_id, event_id, notification_date, status}(R) 97 Statuses = π_{status, status_description}(R) 98 }}} 79 99 80 Функционални зависности: 81 **notification_id** → **user_id**, **event_id**, **notification_date**, **status** 82 **status** → **status_description** 100 Lossless-join услови: 101 {{{ 102 R = Actors ⨝ Countries ⨝ ActorTypes 103 R = Locations ⨝ Countries 104 R = Subscription ⨝ Statuses 105 R = Notifications ⨝ Statuses 106 }}} 83 107 84 1NF: Атомски вредности / 85 2NF: Зависности од целиот клуч / 86 3NF: Транзитивна зависност преку **status** 108 Зачувување на зависности: 109 * `actor_id → actor_code, actor_name, country_code, type_code` во Actors 110 * `country_code → country_name` во Countries 111 * `type_code → type_description` во Actor Types 112 * `location_id → full_name, country_code, adm1_code, latitude, longitude, feature_id` во Locations 113 * `subscription_id → …, status` во Subscription 114 * `notification_id → …, status` во Notifications 115 * `status → status_description` во Statuses 87 116 88 Декомпозиција: 89 **notifications**(**notification_id**, **user_id**, **event_id**, **notification_date**, **status_code**) 90 **statuses**(**status_code**, **status_description**) 117 Со ова сите транзитивни зависности се елиминирани, а сите релации се lossless и ги зачувуваат функционалните зависности. 118 Затоа глобалната релација е во 3NF. 91 119 92 === **predictions**(**prediction_id**, **event_id**, **actor_id**, **predicted_date**, **prediction_type**, **confidence_score**)===120 === 6) Резултантна 3NF шема === 93 121 94 Функционални зависности: 95 **prediction_id** → **event_id**, **actor_id**, **predicted_date**, **prediction_type**, **confidence_score** 122 * Fact-Detail: `events`, `event_details`, `predictions`, `conflict_risk`, `event_analytics` 123 * Dimensions-Master: `actors`, `locations`, `users`, `roles`, `plan`, `countries`, `actor_types`, `statuses` 124 * Operational: `subscription`, `notifications` 96 125 97 1NF: Атомски вредности / 98 2NF: Нема составен клуч, сите зависности се од примарниот клуч / 99 3NF: Нема транзитивни зависности 126 === 7) Нефункционални подобрувања (не ја менуваат 3NF) === 100 127 101 Декомпозиција: / (нема потреба) 128 {{{ 129 -- UNIQUE клучеви: 130 ALTER TABLE actors ADD CONSTRAINT uq_actors_code UNIQUE (actor_code); 131 ALTER TABLE locations ADD CONSTRAINT uq_locations_feat UNIQUE (feature_id); 102 132 103 === **conflict_risk**(**conflict_id**, **actor1_id**, **actor2_id**, **risk_score**, **predicted_date**, **description**) === 133 -- Индекси за споеви/филтри: 134 CREATE INDEX ix_event_details_event ON event_details (global_event_id); 135 CREATE INDEX ix_event_details_actor ON event_details (actor_id); 136 CREATE INDEX ix_event_details_loc ON event_details (location_id); 104 137 105 Функционални зависности: 106 **conflict_id** → **actor1_id**, **actor2_id**, **risk_score**, **predicted_date**, **description** 138 CREATE INDEX ix_notifications_user ON notifications (user_id, notification_date); 139 CREATE INDEX ix_notifications_event ON notifications (event_id); 107 140 108 1NF: Атомски вредности / 109 2NF: Сите зависности се од примарниот клуч / 110 3NF: Нема транзитивни зависности 141 CREATE INDEX ix_predictions_event ON predictions (event_id); 142 CREATE INDEX ix_predictions_actor ON predictions (actor_id); 111 143 112 Декомпозиција: / (нема потреба) 144 CREATE INDEX ix_analytics_event_actor ON event_analytics (event_id, actor_id, date); 145 CREATE INDEX ix_conflict_pair_date ON conflict_risk (actor1_id, actor2_id, predicted_date); 113 146 114 === **event_analytics**(**analytics_id**, **actor_id**, **event_id**, **date**, **conflict_coefficient**, **mentions_count**, **avg_tone**, **description**) === 147 -- CHECK ограничувања: 148 ALTER TABLE subscription ADD CONSTRAINT ck_sub_dates CHECK (end_date IS NULL OR end_date >= start_date); 149 ALTER TABLE events ADD CONSTRAINT ck_year CHECK (year BETWEEN 1900 AND 2100); 150 ALTER TABLE predictions ADD CONSTRAINT ck_conf_score CHECK (confidence_score BETWEEN 0 AND 100); 151 ALTER TABLE conflict_risk ADD CONSTRAINT ck_risk_score CHECK (risk_score BETWEEN 0 AND 100); 152 }}} 115 153 116 Функционални зависности: 117 **analytics_id** → **actor_id**, **event_id**, **date**, **conflict_coefficient**, **mentions_count**, **avg_tone**, **description** 154 === 8) Финален заклучок === 118 155 119 1NF: Атомски вредности / 120 2NF: Сите зависности се од клучот / 121 3NF: Нема транзитивни зависности 122 123 Декомпозиција: / (нема потреба) 124 125 === **Нови релации по нормализација** === 126 127 CREATE TABLE **countries** ( 128 **country_code** VARCHAR(5) PRIMARY KEY, 129 **country_name** VARCHAR(100) 130 ); 131 132 CREATE TABLE **actor_types** ( 133 **type_code** VARCHAR(10) PRIMARY KEY, 134 **type_description** VARCHAR(100) 135 ); 136 137 CREATE TABLE **roles** ( 138 **role_id** SERIAL PRIMARY KEY, 139 **role_name** VARCHAR(50) NOT NULL 140 ); 141 142 CREATE TABLE **statuses** ( 143 **status_code** VARCHAR(20) PRIMARY KEY, 144 **status_description** TEXT 145 ); 156 * Нормализацијата од 11 ентитети создаде уште 3 нови референтни ентитети: `Countries`, `ActorTypes`, `Statuses`. Вкупно: 14 ентитети. 157 * Индексите, UNIQUE и CHECK ограничувањата се опционални подобрувања за перформанси и квалитет на податоци и не ја менуваат нормалната форма.