Changes between Initial Version and Version 1 of Normalization


Ignore:
Timestamp:
05/24/26 17:14:45 (35 hours ago)
Author:
202033
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • Normalization

    v1 v1  
     1= P5: Нормализација =
     2
     3== 1. Почетна де-нормализирана релација ==
     4
     5Почетно се разгледува една глобална де-нормализирана релација со уникатни имиња на атрибути:
     6
     7{{{
     8R(
     9u_user_id, u_full_name, u_email, u_phone, u_created_at, u_password_hash,
     10ur_user_id, ur_role_id, r_role_name,
     11lc_card_id, lc_user_id, lc_points,
     12a_appointment_id, a_appointment_time, a_end_time, a_notes, a_type,
     13a_total_price, a_points_awarded, a_user_id, a_status_id, st_status_name,
     14aps_appointment_id, aps_service_id,
     15s_service_id, s_service_name, s_price, s_duration_minutes,
     16s_category_id, c_category_id, c_category_name,
     17p_payment_id, p_amount, p_method, p_timestamp, p_status,
     18p_appointment_id, p_points_used, p_package_purchase_id,
     19rv_review_id, rv_rating, rv_comment, rv_created_at, rv_payment_id,
     20pkg_package_id, pkg_name, pkg_max_usage, pkg_total_price,
     21ps_package_id, ps_service_id, ps_discounted_price,
     22upp_purchase_id, upp_user_id, upp_package_id,
     23upp_purchased_at, upp_total_uses, upp_remaining_uses,
     24upp_status, upp_expires_at,
     25apu_appointment_id, apu_purchase_id, apu_service_id,
     26apu_used_units, apu_finalized_at,
     27av_availability_id, av_date, av_start_time,
     28av_end_time, av_is_closed
     29)
     30}}}
     31
     32Во оваа форма податоците од повеќе независни ентитети и M:N релации се споени во една глобална релација, што создава:
     33
     34 * повторување на податоци,
     35 * update/delete аномалии,
     36 * мултивредносни групи,
     37 * зависности меѓу атрибути што не се дел од ист ентитет.
     38
     39Глобалната релација концептуално ги опфаќа следните ентитети и релации:
     40
     41 * `"User"`
     42 * `role`
     43 * `userrole`
     44 * `category`
     45 * `service`
     46 * `status`
     47 * `appointment`
     48 * `appointmentservice`
     49 * `payment`
     50 * `review`
     51 * `package`
     52 * `packageservice`
     53 * `userpackagepurchase`
     54 * `appointmentpackageusage`
     55 * `availability`
     56 * `loyaltycard`
     57
     58== 2. Функционални зависности ==
     59
     60{{{
     61"User".user_id
     62    -> full_name, email, phone, created_at, password_hash
     63
     64"User".email
     65    -> user_id, full_name, phone, created_at, password_hash
     66
     67role.role_id
     68    -> role.name
     69
     70category.category_id
     71    -> category.name
     72
     73status.status_id
     74    -> status.name
     75
     76service.service_id
     77    -> service.name, service.price,
     78       service.duration_minutes, service.category_id
     79
     80appointment.appointment_id
     81    -> appointment_time, end_time,
     82       notes, type, total_price,
     83       user_id, status_id, points_awarded
     84
     85payment.payment_id
     86    -> amount, method, timestamp,
     87       status, appointment_id,
     88       points_used, package_purchase_id
     89
     90review.review_id
     91    -> rating, comment, created_at, payment_id
     92
     93package.package_id
     94    -> name, max_usage, total_price
     95
     96userpackagepurchase.purchase_id
     97    -> user_id, package_id,
     98       purchased_at, total_uses,
     99       remaining_uses, status, expires_at
     100
     101availability.availability_id
     102    -> date, start_time, end_time, is_closed
     103
     104(packageservice.package_id, packageservice.service_id)
     105    -> discounted_price
     106}}}
     107
     108Дополнително:
     109
     110{{{
     111(userrole.user_id, userrole.role_id)
     112    -> /
     113
     114(appointmentservice.appointment_id,
     115 appointmentservice.service_id)
     116    -> /
     117}}}
     118
     119Овие релации немаат не-клучни атрибути.
     120
     121== 3. Кандидат-клучеви и избор на примарен клуч ==
     122
     123Во глобалната де-нормализирана релација не постои единечен атрибут што ги одредува сите останати атрибути, бидејќи се комбинирани повеќе независни repeating groups:
     124
     125 * повеќе улоги по корисник,
     126 * повеќе услуги по термин,
     127 * повеќе услуги по пакет,
     128 * повеќе package purchases,
     129 * повеќе availability windows,
     130 * повеќе payments и reviews.
     131
     132Поради тоа, глобалниот кандидат-клуч мора да биде композитен.
     133
     134Теоретски кандидат-клуч:
     135
     136{{{
     137K_R =
     138(
     139ur_user_id,
     140ur_role_id,
     141aps_appointment_id,
     142aps_service_id,
     143p_payment_id,
     144ps_package_id,
     145ps_service_id,
     146upp_purchase_id,
     147av_availability_id
     148)
     149}}}
     150
     151Почетната глобална релација не ја задоволува 1НФ и се наоѓа во UNF форма.
     152
     153== 4. Декомпозиција до 1НФ ==
     154
     155=== Релација што се анализира ===
     156
     157{{{
     158R
     159}}}
     160
     161=== Проблем ===
     162
     163Во глобалната релација постојат повторувачки групи и мултивредносни атрибути:
     164
     165 * повеќе улоги по корисник,
     166 * повеќе услуги по термин,
     167 * повеќе услуги по пакет,
     168 * повеќе package purchases,
     169 * повеќе availability windows.
     170
     171=== Декомпозиција ===
     172
     173{{{
     174"User"(user_id, full_name, email, phone, created_at, password_hash)
     175
     176role(role_id, name)
     177
     178userrole(user_id, role_id)
     179
     180category(category_id, name)
     181
     182service(service_id, name, price,
     183duration_minutes, category_id)
     184
     185status(status_id, name)
     186
     187appointment(
     188appointment_id,
     189appointment_time,
     190end_time,
     191notes,
     192type,
     193total_price,
     194user_id,
     195status_id,
     196points_awarded
     197)
     198
     199appointmentservice(
     200appointment_id,
     201service_id
     202)
     203
     204payment(
     205payment_id,
     206amount,
     207method,
     208timestamp,
     209status,
     210appointment_id,
     211points_used,
     212package_purchase_id
     213)
     214
     215review(
     216review_id,
     217rating,
     218comment,
     219created_at,
     220payment_id
     221)
     222
     223package(
     224package_id,
     225name,
     226max_usage,
     227total_price
     228)
     229
     230packageservice(
     231package_id,
     232service_id,
     233discounted_price
     234)
     235
     236userpackagepurchase(
     237purchase_id,
     238user_id,
     239package_id,
     240purchased_at,
     241total_uses,
     242remaining_uses,
     243status,
     244expires_at
     245)
     246
     247appointmentpackageusage(
     248appointment_id,
     249purchase_id,
     250service_id,
     251used_units,
     252finalized_at
     253)
     254
     255availability(
     256availability_id,
     257date,
     258start_time,
     259end_time,
     260is_closed
     261)
     262
     263loyaltycard(
     264card_id,
     265points,
     266user_id
     267)
     268}}}
     269
     270=== Клучеви ===
     271
     272Едноставни PK:
     273
     274{{{
     275user_id
     276role_id
     277category_id
     278service_id
     279status_id
     280appointment_id
     281payment_id
     282review_id
     283package_id
     284purchase_id
     285availability_id
     286card_id
     287}}}
     288
     289Композитни PK:
     290
     291{{{
     292userrole(user_id, role_id)
     293
     294appointmentservice(
     295appointment_id,
     296service_id
     297)
     298
     299packageservice(
     300package_id,
     301service_id
     302)
     303}}}
     304
     305=== Lossless Join ===
     306
     307Декомпозицијата е lossless бидејќи сите релации се поврзани преку PK/FK врски.
     308
     309=== Dependency Preservation ===
     310
     311Функционалните зависности се зачувани во новите релации.
     312
     313== 5. Декомпозиција до 2НФ ==
     314
     315=== Релации што се анализираат ===
     316
     317 * `userrole`
     318 * `appointmentservice`
     319 * `packageservice`
     320
     321=== Проверка ===
     322
     323Во `userrole` и `appointmentservice` нема не-клучни атрибути.
     324
     325Во `packageservice`:
     326
     327{{{
     328(package_id, service_id)
     329    -> discounted_price
     330}}}
     331
     332`discounted_price` зависи од целата комбинација, а не од дел од клучот.
     333
     334=== Заклучок ===
     335
     336Постојната шема веќе ја задоволува 2НФ.
     337
     338Нема потреба од дополнителна декомпозиција.
     339
     340== 6. Декомпозиција до 3НФ ==
     341
     342=== Транзитивни зависности ===
     343
     344{{{
     345service.service_id
     346    -> service.category_id
     347    -> category.name
     348
     349appointment.appointment_id
     350    -> appointment.status_id
     351    -> status.name
     352
     353"User".user_id
     354    -> userrole.role_id
     355    -> role.name
     356}}}
     357
     358=== Решение ===
     359
     360Транзитивните зависности се отстранети преку издвојување на lookup релации:
     361
     362 * `category`
     363 * `status`
     364 * `role`
     365
     366Дополнително:
     367
     368 * `review` е одвоена од `payment`
     369 * `payment` е одвоена од `appointment`
     370 * `package` е одвоена од `userpackagepurchase`
     371
     372=== Заклучок ===
     373
     374Релациите ја задоволуваат 3НФ.
     375
     376== 7. Проверка за BCNF ==
     377
     378Во најголем дел релациите ја задоволуваат BCNF бидејќи детерминантите се кандидат-клучеви.
     379
     380Особено:
     381
     382 * `"User"`
     383 * `role`
     384 * `category`
     385 * `status`
     386 * `service`
     387 * `appointment`
     388 * `payment`
     389 * `review`
     390 * `package`
     391 * `userpackagepurchase`
     392 * `availability`
     393 * `loyaltycard`
     394
     395Контролирани де-нормализирани атрибути:
     396
     397 * `appointment.total_price`
     398 * `package.total_price`
     399 * `payment.amount`
     400 * `appointment.points_awarded`
     401
     402Овие атрибути се свесно задржани за:
     403
     404 * перформанси,
     405 * историска конзистентност,
     406 * поедноставување на трансакциската логика.
     407
     408Конзистентноста се одржува преку DB-first логика:
     409
     410=== Functions / Procedures ===
     411
     412{{{
     413fn_recalculate_appointment
     414fn_validate_appointment
     415sp_create_appointment
     416sp_apply_package_to_appointment
     417sp_create_payment
     418sp_mark_payment_paid
     419sp_award_loyalty_points
     420}}}
     421
     422=== Triggers ===
     423
     424{{{
     425appointmentservice_recalculate
     426appointment_validate
     427payment_validate
     428appointment_prevent_price_change
     429}}}
     430
     431== 8. Финален нормализиран модел ==
     432
     433Финалниот нормализиран модел е составен од:
     434
     435{{{
     436"User"
     437role
     438userrole
     439category
     440service
     441status
     442appointment
     443appointmentservice
     444payment
     445review
     446package
     447packageservice
     448userpackagepurchase
     449appointmentpackageusage
     450availability
     451loyaltycard
     452}}}
     453
     454== 9. Споредба со Phase 2 дизајнот ==
     455
     456Нормализацијата покажува дека тековниот модел веќе е во голем дел усогласен со 3НФ/BCNF.
     457
     458Во постојниот дизајн:
     459
     460 * ентитетите се раздвоени,
     461 * M:N релациите се реализирани преку junction табели,
     462 * lookup податоците се издвоени,
     463 * транзитивните зависности се отстранети,
     464 * business logic е имплементирана во базата.
     465
     466=== Дали е потребно реструктурирање? ===
     467
     468Не е потребно значајно реструктурирање на базата.
     469
     470Опционални подобрувања:
     471
     472 * конзистентно именување на табели,
     473 * дополнително стандардизирање на status вредности.
     474
     475== 10. Заклучок ==
     476
     477Финалниот дизајн:
     478
     479 * ја намалува редундантноста,
     480 * избегнува insert/update/delete аномалии,
     481 * ги зачувува функционалните зависности,
     482 * овозможува lossless join,
     483 * и поддржува DB-first имплементација преку SQL функции, процедури, тригери и views