| | 1 | = Оптимизација = |
| | 2 | |
| | 3 | |
| | 4 | == Интегритетни ограничувања (UNIQUE, CHECK) == |
| | 5 | За да спречиме аномалии и дупликати, додадовме: |
| | 6 | |
| | 7 | {{{ |
| | 8 | #!sql |
| | 9 | -- UNIQUE: деловни правила |
| | 10 | ALTER TABLE "User" ADD CONSTRAINT uq_user_email UNIQUE (email); |
| | 11 | ALTER TABLE "User" ADD CONSTRAINT uq_user_username UNIQUE (username); |
| | 12 | ALTER TABLE "Instructor" ADD CONSTRAINT uq_instr_email UNIQUE (instructor_email); |
| | 13 | ALTER TABLE "Training" ADD CONSTRAINT uq_training_name UNIQUE (training_name); |
| | 14 | ALTER TABLE "Package" ADD CONSTRAINT uq_package_name UNIQUE (package_name); |
| | 15 | ALTER TABLE "Merch_Items" ADD CONSTRAINT uq_merch_item UNIQUE (item_name); |
| | 16 | |
| | 17 | -- "Slot" уникатност: спречува дупликат термини/локации |
| | 18 | ALTER TABLE "Class" |
| | 19 | ADD CONSTRAINT uq_class_slot UNIQUE (date, start_time, location, instructor_id); |
| | 20 | ALTER TABLE "Event" |
| | 21 | ADD CONSTRAINT uq_event_slot UNIQUE (event_name, date, time, location); |
| | 22 | |
| | 23 | -- CHECK: едноставни бизнис правила |
| | 24 | ALTER TABLE "Class" |
| | 25 | ADD CONSTRAINT ck_class_time_order CHECK (end_time > start_time), |
| | 26 | ADD CONSTRAINT ck_class_capacity_nonneg CHECK (capacity IS NULL OR capacity >= 0), |
| | 27 | ADD CONSTRAINT ck_seats_not_overflow CHECK (seats_available IS NULL OR capacity IS NULL OR seats_available <= capacity), |
| | 28 | ADD CONSTRAINT ck_seats_nonneg CHECK (seats_available IS NULL OR seats_available >= 0); |
| | 29 | |
| | 30 | ALTER TABLE "Package" |
| | 31 | ADD CONSTRAINT ck_package_price_pos CHECK (price > 0), |
| | 32 | ADD CONSTRAINT ck_package_num_pos CHECK (num_classes > 0); |
| | 33 | |
| | 34 | ALTER TABLE "Merch_Items" |
| | 35 | ADD CONSTRAINT ck_merch_price_pos CHECK (price > 0); |
| | 36 | }}} |
| | 37 | |
| | 38 | Забелешка: при обид за дупликат UNIQUE, PostgreSQL враќа грешка 23505 (unique violation) – тоа во апликацијата го прикажуваме како “Email already taken”, итн. |
| | 39 | |
| | 40 | == Индекси за перформанси == |
| | 41 | |
| | 42 | Индекси на мостови (по „другата“ страна од PK, за побрзи филтри): |
| | 43 | {{{ |
| | 44 | #!sql |
| | 45 | CREATE INDEX IF NOT EXISTS idx_ubc_class ON "User_Booked_Class"(class_id); |
| | 46 | CREATE INDEX IF NOT EXISTS idx_cht_training ON "Class_Includes_Training"(training_id); |
| | 47 | CREATE INDEX IF NOT EXISTS idx_ue_event ON "User_Event"(event_id); |
| | 48 | CREATE INDEX IF NOT EXISTS idx_upp_package ON "User_Purchased_Package"(package_id); |
| | 49 | CREATE INDEX IF NOT EXISTS idx_upm_merch ON "User_Purchased_Merch"(merch_id); |
| | 50 | CREATE INDEX IF NOT EXISTS idx_pic_class ON "Package_Includes_Class"(class_id); |
| | 51 | }}} |
| | 52 | |
| | 53 | Индекси за честите листања: |
| | 54 | {{{ |
| | 55 | #!sql |
| | 56 | CREATE INDEX IF NOT EXISTS idx_event_date_time ON "Event"(date, time); |
| | 57 | CREATE INDEX IF NOT EXISTS idx_class_date_time ON "Class"(date, start_time); |
| | 58 | }}} |
| | 59 | |
| | 60 | == Заклучок == |
| | 61 | Со декомпозиција по ентитети и мостови ги елиминиравме транзитивните зависности и постигнавме 3NФ/BCNF. UNIQUE/CHECK ограничувањата ги зацврстуваат бизнис правилата, а индексирањето ги забрзува најчестите барања (листaње часови/настани и повратни врски преку мостовите). |
| | 62 | |