You are on page 1of 236

Основні поняття

База даних (БД, DataBase, DB) — впорядкований набір логічно взаємопов'язаних даних,
що використовуються спільно та призначені для задоволення інформаційних
потреб користувачів. У технічному розумінні включно й система керування БД.

Головне завдання БД — гарантоване збереження значних обсягів інформації (так


звані записи даних) та надання доступу до неї користувачеві або ж прикладній програмі.
Таким чином, БД складається з двох частин: збереженої інформації та системи керування
нею.

Існує величезна кількість різновидів баз даних, що відрізняються за різними критеріями.

Класифікація за моделі даних


1. Ієрархічна
2. Об'єктна і об'єктно-орієнтована
3. Об'єктно-реляційна
4. Реляційна
5. Мережева

Ієрархічна модель даних - подання бази даних у вигляді деревовидної (ієрархічної )


структури, що складається з об'єктів (даних ) різних рівнів. Між об'єктами існують зв'язки,
кожен об'єкт може включати в себе декілька об'єктів нижчого рівня. Такі об'єкти
перебувають у відношенні предка (об'єкт більш близький до кореня ) до нащадка (об'єкт
більш низького рівня), при цьому можлива ситуація, коли об'єкт - предок не має нащадків
або має їх кілька, тоді як у об'єкта - нащадка обов'язково тільки один предок. Об'єкти, що
мають загального предка , називаються близнюками ( в програмуванні стосовно до
структури даних дерево усталене назва брати) .

Об'єктні бази даних - це модель роботи з


об'єктними даними. Така модель баз даних, незважаючи на те, що вона існує вже багато
років, вважається новою. І її створення відкриває великі перспективи, в зв'язку з тим, що
використання об'єктної моделі баз даних легко сприймається користувачем, так як
створюється високий рівень абстракції ...

Об'єктно-реляційна СУБД (ОРСУБД) - реляційна СУБД (РСУБД), підтримуюча деякі


технології, що реалізують об'єктно-орієнтований підхід: об'єкти, класи і
спадкування реалізовані в структурі баз даних і мовою запитів.

Реляційна модель даних (РМД) - логічна модель даних, прикладна теорія


побудови баз даних, яка є додатком до завдань обробки даних таких розділів
математики як теорії множин і логіка першого порядку.

Мережева модель даних - логічна модель даних, що


є розширенням ієрархічного підходу, сувора математична теорія, що описує структурний
аспект, аспект цілісності та аспект обробки даних в мережевих базах даних.

Класифікація за середовищі постійного зберігання


У вторинній пам'яті, або традиційна (conventional database): середовищем постійного
зберігання є периферійна незалежна пам'ять (вторинна пам'ять ) - як правило жорсткий
диск .
В оперативну пам'ять СУБД поміщає лише кеш і дані для поточної обробки.
В оперативній пам'яті (in - memory database, memory - resident database, main memory
database): всі дані на стадії виконання знаходяться в оперативній пам'яті.
У третинної пам'яті (tertiary database ): середовищем постійного зберігання є від'єднується
від сервера пристрій масового зберігання (третинна пам'ять), як правило на основі
магнітних стрічок або оптичних дисків.
У вторинній пам'яті сервера зберігається лише каталог даних третинної пам'яті, файловий
кеш і дані для поточної обробки; завантаження ж самих даних вимагає спеціальної
процедури.

Класифікація по вмісту
- Географічна
- історична
- наукова
- мультимедійна
- Клієнтська.

Система керування базами даних (СКБД) — комп'ютерна програма чи комплекс


програм, що забезпечує користувачам можливість створення, збереження, оновлення,
пошук інформації та контролю доступу в базах даних.

Основні характеристики СКБД


 Контроль за надлишковістю даних
 Несуперечливість даних
 Підтримка цілісності бази даних (коректність та несуперечливість)
 Цілісність описується за допомогою обмежень
 Незалежність прикладних програм від даних
 Спільне використання даних
 Підвищений рівень безпеки

Основні можливості СКБД


 Дозволяється створювати БД (здійснюється за допомогою мови визначення
даних DDL (Data Definition Language))
 Дозволяється додавання, оновлення, видалення та читання інформації з БД (за
допомогою мови маніпулювання даними DML, яку часто називають мовою запитів)
 Можна надавати контрольований доступ до БД за допомогою:
1. Системи забезпечення захисту, яка запобігає несанкціонованому доступу до БД;
2. Системи керування паралельною роботою прикладних програм, яка контролює
процеси спільного доступу до БД;
3. Система відновлення — дозволяє відновлювати БД до попереднього
несуперечливого стану, що був порушений в результаті збою апаратного або
програмного забезпечення

Основні компоненти середовища


1. апаратне забезпечення
2. програмне забезпечення
3. дані
4. процедури — інструкції та правила, які повинні враховуватись при проектуванні та
використанні БД
5. користувачі
1. адміністратори даних (керування даними, проектування БД, розробка
алгоритмів, процедур);
адміністратори БД (фізичне проектування, відповідальність за безпеку та
цілісність даних);
2. розробники БД;
3. прикладні програмісти;
4. кінцеві користувачі;

За ступенем розподіленості
Централізована, або зосереджена (centralized database ): БД , повністю підтримувана на
одному комп'ютері.
Розподілена (distributed database): БД, складові частини якої розміщуються в різних вузлах
комп'ютерної мережі відповідно з яким-небудь критерієм .
Неоднорідна (heterogeneous distributed database): фрагменти розподіленої БД в різних
вузлах мережі підтримуються засобами більше однієї СУБД
Однорідна (homogeneous distributed database): фрагменти розподіленої БД в різних вузлах
мережі підтримуються засобами однієї і тієї ж СУБД.
Фрагментована, або секціонірованная (partitioned database): методом розподілу даних є
фрагментованість (партіціонірованіе, секціонування), вертикальне чи горизонтальне.
Тиражована (replicated database): методом розподілу даних є тиражування ( реплікація ) .

Файл- серверні
У файл- серверних СУБД файли даних розташовуються централізовано на файл- сервері.
СУБД розташовується на кожному клієнтському комп'ютері ( робочої станції). Доступ СУБД
до даних здійснюється через локальну мережу. Синхронізація читань і оновлень
здійснюється за допомогою файлових блокувань.
Перевагою цієї архітектури є низьке навантаження на процесор файлового сервера.
Недоліки: потенційно високе завантаження локальної мережі; ускладненість або
неможливість централізованого управління; ускладненість або неможливість забезпечення
таких важливих характеристик як висока надійність, висока доступність і висока безпека .
Застосовуються найчастіше в локальних додатках, які використовують функції управління
БД; в системах з низькою інтенсивністю обробки даних і низькими піковими
навантаженнями на БД.
На даний момент файл-серверна технологія вважається застарілою, а її використання у
великих інформаційних системах - недоліком.
Приклади: Microsoft Access , Paradox , dBase , FoxPro , Visual FoxPro .

Клієнт – серверні
Клієнт -серверна СУБД розташовується на сервері разом з БД і здійснює доступ до БД
безпосередньо , в монопольному режимі. Всі клієнтські запити на обробку даних
обробляються клієнт- серверної СУБД централізовано.
Недолік клієнт- серверних СУБД полягає в підвищених вимогах до сервера.
Переваги: потенційно більш низьке завантаження локальної мережі; зручність
централізованого управління ; зручність забезпечення таких важливих характеристик як
висока надійність , висока доступність і висока безпека .
Приклади: Oracle , Firebird , Interbase , IBM DB2 , Informix , MS SQL Server , Sybase Adaptive
Server Enterprise , PostgreSQL , MySQL , Caché , Лінтер .

Вбудовувані
Вбудована СУБД - СУБД, яка може поставлятися як складова частина деякого програмного
продукту, не вимагаючи процедури самостійної установки.
Призначена для локального зберігання даних свого додатку і не розрахована на колективне
використання в мережі.
Фізично вбудовується СУБД найчастіше реалізована у вигляді підключається бібліотеки.
Доступ до даних з боку додатка може відбуватися через SQL або через спеціальні програмні
інтерфейси.
Приклади: OpenEdge , SQLite , BerkeleyDB , Firebird Embedded , Microsoft SQL Server
Compact, Лінтер .

Архітектура СКБД
Існує трирівнева система організації СКБД ANSI-SPARC, при якій існує незалежний рівень
для ізоляції програми від особливостей представлення даних на нижчому рівні.
Рівні:
1. Зовнішній — представлення БД з точки зору користувача.
2. Концептуальний — узагальнене представлення БД, описує які дані зберігаються в
БД і зв'язки між ними. Підтримує зовнішні представлення, підтримується внутрішнім
рівнем.
3. Внутрішній — фізичне представлення БД в комп'ютері.
Логічна незалежність — повна захищеність зовнішніх моделей від змін, що вносяться в
концептуальну модель.
Фізична незалежність — захищеність концептуальної моделі від змін, які вносяться у
внутрішню модель.
Рис. 1.1. Трирівнева модель системи управління базою даних, запропонована ANSI
1. Рівень зовнішніх моделей - самий верхній рівень, де кожна модель має своє "бачення"
даних. Цей рівень визначає точку зору на БД окремих застосувань. Кожне застосування
бачить і обробляє тільки ті дані, які необхідні саме цьому застосуванню. Наприклад, система
розподілу робіт використовує зведення про кваліфікацію співробітника, але її не цікавлять
відомості про оклад, домашню адресу і телефон співробітника, і навпаки, саме ці відомості
використовуються в підсистемі відділу кадрів.
2. Концептуальний рівень - центральна ланка, що управляє, тут база даних
представлена в найбільш загальному вигляді, який об'єднує дані, використовувані всіма
застосуваннями, що працюють з даною базою даних. Фактично концептуальний рівень
відображає узагальнену модель наочної області (об'єктів реального миру), для якої
створювалася база даних. Як будь-яка модель, концептуальна модель відображає тільки
істотні, з погляду обробки, особливості об'єктів реального миру.
3. Фізичний рівень - власне дані, розташовані у файлах або в сторінкових структурах,
розташованих на зовнішніх носіях інформації.
Ця архітектура дозволяє забезпечити логічну (між рівнями 1 і 2) і фізичну (між рівнями 2
і 3) незалежність при роботі з даними. Логічна незалежність припускає можливість зміни
одного застосування без коректування інших застосувань, що працюють з цією ж базою
даних. Фізична незалежність припускає можливість перенесення інформації, що
зберігається, з одних носіїв на інших при збереженні працездатності всіх застосувань, що
працюють з даною базою даних. Це саме те, чого не вистачало при використанні файлових
систем.
Виділення концептуального рівня дозволило розробити апарат централізованого
управління базою даних.
Життєвий цикл бази даних - це сукупність етапів, які проходить база даних на своєму
шляху від створення до закінчення використання.
1. Дослідження та аналіз проблеми , для вирішення якої створюється база даних.
2. Побудова інфологічну і даталогіческую моделі .
3. Нормалізація отриманих інфологічну і даталогіческую моделей. По закінченні цього
етапу, як правило отримують заготовки таблиці БД і набір зв'язків між ними (первинні та
вторинні ключі )
4. Перевірка цілісності БД
5. Вибір фізичного способу зберігання та експлуатації (тех. засобу ) бази даних .
6. Проектування вхідних і вихідних форм .
7. Розробка інтерфейсу програми.
8. Функціональне наповнення додатки
9. Налагодження: перевірка на коректність роботи функціонального наповнення системи
10. Тестування: тест на коректність введення виведення даних , тест на максимальну
кількість активних сесій і т. д.
11. Введення в експлуатацію: налагодження ІТ-інфраструктури, навчання користувачів та
ІТ- персоналу.
12. Виведення з експлуатації: перенесення даних в нову СУБД.

Цілісність бази даних (database integrity) - відповідність наявної в базі даних інформації
її внутрішній логіці, структурі і всім явно заданими правилами.
Кожне правило, оскiльки воно має деяке обмеження на можливий стан бази даних,
називається обмеженням цілісності (integrity constraint ).
Приклади правил: вага деталі повинен бути позитивним ; кількість знаків в телефонному
номері не повинно перевищувати 25 ; вік батьків не може бути менше віку їх біологічної
дитини і т.д.
Завдання аналітика і проектувальника бази даних - можливо більш повно виявити всі
наявні обмеження цілісності і задати їх в базі даних.
Цілісність БД не гарантує достовірності інформації, але забезпечує принаймні
правдоподібність цієї інформації, відкидаючи свідомо неймовірні, неможливі значення.
Не слід плутати цілісність БД з достовірністю БД. Достовірність (або істинність) є
відповідність фактів, що зберігаються в базі даних, реальному світу. Очевидно, що для
визначення достовірності БД потрібно володіння повними знаннями як про вміст БД, так і
про реальний світ. Для визначення цілісності БД потрібно лише володіння знаннями про
вміст БД і про задані для неї правилах. Тому СУБД може (і повинна) контролювати цілісність
БД, але принципово не в змозі контролювати достовірність БД. Контроль достовірності БД
може бути покладено тільки на людину , та й то в обмежених масштабах , оскільки в ряді
випадків люди теж не мають повноти знань про реальний світ .

Процес обробки запиту користувача


Взаємодія користувача, СУБД і ОС при обробці запиту на отримання даних. Цифрами
помічена послідовність взаємодій:
Рис. 1.2. Схема проходження запиту до БД

1. Користувач посилає СУБД запит на отримання даних з БД.


2. Аналіз прав користувача і зовнішньої моделі даних, відповідної даному користувачеві,
підтверджує або забороняє доступ даного користувача до запитаних даних.
3. В разі заборони на доступ до даних СУБД повідомляє користувача про це (стрілка 12)
і припиняє подальший процес обробки даних, інакше СУБД визначає частка концептуальної
моделі, яка зачіпається запитом користувача.
4. СУБД запрошують інформацію про частку концептуальної моделі.
5. СУБД отримує інформацію про запитану частку концептуальної моделі.
6. СУБД запрошує інформацію про місце розташування даних на фізичному рівні (файли
або фізичні адреси).
7. У СУБД повертається інформація про місце розташування даних в термінах
операційної системи.
8. СУБД ввічливо просить операційну систему надати необхідні дані, використовуючи
засоби операційної системи.
9. Операційна система здійснює перекачування інформації з пристроїв зберігання і
пересилає його в системний буфер.
10. Операційна система оповіщає СУБД про закінчення пересилки.
11. СУБД вибирає з доставленої інформації, що знаходиться в системному буфері, тільки
те, що потрібне користувачеві, і пересилає ці дані в робочу область користувача.
БМД - це База Метаданих, саме тут і зберігається вся інформація про використовувані
структури даних, логічну організацію даних, права доступу користувачів і, нарешті, фізичне
розташування даних. Для управління БМД існує спеціальне програмне забезпечення
адміністрування баз даних, яке призначене для коректного використання єдиного
інформаційного простору багатьма користувачами.
Чи завжди запит проходить повний цикл? Звичайно, немає. СУБД володіє достатньо
розвиненим інтелектом, який дозволяє їй не повторювати безглуздих дій. І тому, наприклад,
якщо цей же користувач повторно звернеться до СУБД з новим запитом, то для нього вже
не перевірятимуться зовнішня модель і права доступу, а якщо подальший аналіз запиту
покаже, що дані можуть знаходитися в системному буфері, то СУБД здійснить тільки 11 і 12
кроків в обробці запиту.
Моделі баз даних

1. Основні типи моделей і їх еквівалентність


2. Ієрархічна модель
3. Мережева модель

Основні типи моделей і їх еквівалентність


Наявність в СУБД певної, допустимої структури даних приводить до поняття структурованих
баз даних, тобто дані в таких БД мають бути представлені як сукупність взаємозв'язаних
елементів. Якщо допустити можливість породження нових типів і динамічний процес
встановлення зв'язків (під час появи об'єкту в БД), то ми прийдемо до поняття баз
неструктурованих даних. Допустимі і проміжні варіанти, які носять назву БД з частково
детермінованою схемою. Таке ділення БД з погляду ступеня структурованості даних, що
зберігаються, виявляється істотним моментом при виборі СУБД, що несе, для реалізації ІС,
оскільки конкретна СУБД зазвичай підтримує певну модель даних. З іншого боку, слід мати
на увазі, що для кожного з приведених типів БД використовуються відповідні моделі даних,
тобто існує деяка безліч моделей даних.

В даний час для структурованих баз даних розрізняють трьох основних типів логічних
моделей даних залежно від характеру підтримуваних ними зв'язків між елементами даних -
мережеву, ієрархічну і реляційну. Класифікуючими ознаками в цих моделях є: ступінь
жорсткості (фіксації) зв'язку, математичне представлення структури моделі і допустимі типи
даних (див. таблицю 1.1). Допустимі типи даних обговорюватимуться далі при вивченні
реляційної моделі.

Загальні характеристики моделей даних


Модель даних Характер зв'язку між об'єктами Формальне уявлення
Мережева Напівжорсткі зв'язки Довільний граф
Ієрархічна Жорсткі зв'язки Деревовидна структура
Реляційна Мінливі зв'язки Плоский файл
На рисунку проілюстровані особливості кожної моделі даних. При зіставленні моделей слід
пам'ятати, що всі вони теоретично еквівалентні. Еквівалентність моделей полягає в тому,
що вони можуть бути зведені одна до іншої шляхом формальних перетворень.

В практиці обробки даних СУБД характеризуються по їх здатності підтримувати певного типа


БД. У найзагальнішому виді БД підрозділяють на:

 фактографічні, які зберігають сукупність фактів інтегрованих, можливо, з різних


документів;
 документальні, які орієнтовані на зберігання документів;
 документально-фактографічні, які володіють рисами і тих і інших.

У багатьох випадках для розробників ІС буває поважно ділення СУБД (і БД) по характеру
обробки: на централізованих і розподілених.

Ієрархічна модель
Ієрархічна модель даних організовує дані у вигляді деревовидної структури і є реалізацією
логічних зв'язків між даними типу родових стосунків або стосунків "частинне-ціле".
Прикладом простого ієрархічного уявлення може служити адміністративна структура
організації.
Особливістю такого представлення даних є наявність декількох підлеглих рівнів. У
ієрархічній моделі є кореневий вузол або корінь дерева. Він розташовується на 1-му,
найвищому рівні і не має вузлів-попередників. Решта вузлів називається породженими і
зв'язані між собою таким чином: кожен вузол має початковий, такий, що знаходиться на
вищестоящому рівні. На наступному рівні кожен вузол може мати більш за один вузол-
нащадок або не мати нащадків зовсім. Вузли, що не мають породжених, називаються
листям. У ієрархії розглядують рівні, на яких розташований той або інший вузол або
сукупність вузлів.

Між початковим вузлом і породженими вузлами по умові моделі існує зв'язок "один-ко-
многим" (або "многие-к-одному").

Ієрархія повинна задовольняти наступним умовам:


- Ієрархія має початковий вузол (корінь), з якого будується дерево. Кожне дерево має тільки
один корінь.
- Вузол має непорожню множину атрибутів, які описують об'єкт, що моделюється в даному
вузлі.
- Породжені вузли можуть додаватися в дерево як у вертикальному, так і в горизонтальному
напрямі.
- Доступ до породжених вузлів можливий тільки через початковий вузол, тому існує тільки
один шлях доступу до кожного вузла.
- Можливе існування декількох екземплярів кожного вузла кожного рівня. При цьому кожен
екземпляр початкового вузла починає логічний запис.

До основних недоліків ієрархічної моделі можна віднести:


- складність відображення зв'язку "многие-к-многим"
- ускладнення операції включення нових об'єктів і видалення застарілих об'єктів
безпосередньо в базі даних (особливо оновлення і видалення зв'язків);
- неоднозначність представлення даних про предметну область.

Приклад. Хай потрібно побудувати ієрархічну модель про викладачів, студентів і


дисципліни, які викладачі викладають, а студенти вивчають.

Припустимо, що кожен викладач може читати декілька дисциплін, а кожен студент також
може вивчати декілька дисциплін.

Один з можливих варіантів побудови ієрархічної моделі може бути таким. Кореневим вузлом
є студент (Номер студента, ФІО, Номер групи). Для кожного студента при даному уявленні
є екземпляр кореневого вузла. Викладач і дисципліна об'єднуються в один породжений
вузол (Табельний номер викладача, ФІО, Вчене звання, Кафедра, Дисципліна, Дата іспиту,
Оцінка, Залік).

При такій організації даних достатньо легко отримувати відповіді на запити типу "видати
інформацію про складання іспитів студентами по різних дисциплінах". Проте при відповіді
на питання, які викладачі приймають іспити по ВТ, необхідно проглянути всі записи
породжених вузлів для кожного кореневого вузла. Для цього питання більш підходить
модель, в якій кореневим вузлом є викладач (Табельний номер викладача, ФІО, вчене
звання, кафедра), а породженим є студент (номер студента, ФІО, номер групи, дисципліна,
дата здачі, оцінка, залік).
У першому варіанті моделі для кожного студента дублюється інформація (у екземплярі
породженого вузла) про викладачів і дисципліну, а в другому - для кожного викладача про
студентів. Звідси виникають проблеми включення і видалення даних. З принципу ієрархії
виходить, що екземпляр породженого вузла не може існувати у відсутність відповідного
йому екземпляра початкового вузла. Таким чином, неможливо без залучення додаткових
способів включити в базу даних інформацію про викладачів, які не приймають іспити (для
першого варіанту схеми).

При видаленні початкового вузла автоматично видаляються екземпляри породжених вузлів.


Так, для другого варіанту представлення моделі видалення зведення про викладача
(звільнився) віддаляються всі відомості про студентів, у нього що навчалися, а отже,
втрачається інформація, необхідна для оцінки якості навчання студентів.

Першопричиною цих проблем є та обставина, що ієрархічна модель не підтримує


відношення M:N.

Основною одиницею обробки тут є запис, до якого застосовні операції ЗАПАМ'ЯТАТИ,


МОДИФІКУВАТИ, ВИДАЛИТИ, ВИТЯГУВАТИ, ЗНАЙТИ. У операціях створення і знищення
зв'язків для цієї моделі немає необхідності тому, що всі зв'язки зумовлені заздалегідь
деревовидною структурою стосунків. Операція "знайти" зводиться до однієї з трьох
процедур обходу дерева.

При використанні ієрархічної моделі актуальною є проблема відстежування зв'язків, хоча і


в простішому варіанті. До можливих недоліків ієрархічної моделі можна віднести вірогідну
асиметрію стосунків між суттю наочної області БД і незручність у відображенні
горизонтальних зв'язків, які потрібно виражати через вертикальні зв'язки.

Мережева модель
Зупинимося на понятті мережевої структури, покладеної в основу мережевої моделі даних.
Розгледимо відношення між наступними об'єктами: Студентський колектив, Студентська
група, Кімната в гуртожитку і Студент. Взаємозв'язок між цими об'єктами не є ієрархічним,
оскільки породжений елемент Студент має два початкових - Студентська група і Кімната в
гуртожитку. Такі стосунки, коли породжений елемент має більш одного початкового,
описуються у вигляді мережевої структури. У такій структурі будь-який елемент може бути
пов'язаний з будь-яким іншим елементом.

Як і у разі ієрархічної моделі, мережеву структуру можна описати в термінах початкових і


породжуваних вузлів, а також представити її так, щоб породжені вузли розташовувалися
нижче початкових. При розгляді деяких мережевих структур можна говорити про рівні. Так
розглянута мережева структура має три рівні.

Розгледимо, як в мережевій моделі будуть представлені взаємозв'язки між об'єктами. У


нашому прикладі присутні два види взаємозв'язків:
1:M (Учбова група - Студент)
M:1 (Студент - Кімната в гуртожитку).
Мережеві структури, які мають такі зв'язки між початковими і породженими вузлами,
породженими і початковими вузлами, відносять до простих мережевих
структур. Складною мережевою структурою називають таку структуру, в якій
присутній хоч би один зв'язок типа N:M.
Прикладом такого зв'язку є відношення Студент - Викладач. Таке розділення мережевих
структур обумовлене технологічними складнощами реалізації взаємозв'язку N:M.

База даних з мережевою структурою складається з декількох областей. Кожна область


складається із записів, які складаються з полів. Об'єднання записів в логічну структуру
можливо не лише по областях, але і за допомогою наборів даних. По суті набір даних - це
пойменоване дворівневе дерево, яке є основою для побудови багаторівневих дерев. Сама
база даних складається з деякої сукупності наборів даних.

Набір даних - це екземпляр пойменованої сукупності записів. Кожним типом набору є


відношення між двома або декількома типами записів. Для кожного набору даних один тип
запису може бути оголошений власником, а один або декілька типів інших записів - членами
набору. Набор даних, наприклад, можна використовувати для об'єднання записів про
студентів однієї групи. Тоді тип набору можна визначити як склад групи з типом запису
власника. Наприклад, Учбова група з типом записів членів Студент: Учбова група (запис-
власник) - Студент (сукупність записів про студентах в даній групі).

Набір даних має наступні властивості:


- Набір даних є пойменована сукупність зв'язаних записів.
- У кожному екземплярі набору даних є тільки один екземпляр запису власника.
- Екземпляр набору може містити 0,1 або декілька записів-членів.
- Набор даних вважається за порожній, якщо жоден екземпляр запису-члена не пов'язаний
з відповідним екземпляром запису власника.
- Екземпляр набору даних пов'язаний із записом власника.
- Тип набору припускає логічний взаємозв'язок 1:M між власником і членом набору.
- Кожному типові набору даних привласнюється ім'я, яке дозволяє одній і тій же парі типів
об'єктів брати участь в декількох взаємозв'язках.

Необхідно розрізняти типа і екземпляр набору. Заздалегідь пояснимо відмінність між


поняттями "тип" і "екземпляр" запису. Наприклад, Студент є типом запису, а рядок, що
містить інформацію про конкретного студента, є екземпляром типа запису Студент.
Аналогічна відмінність існує між типом і екземпляром набору даних. Наприклад, тип набору
Склад групи, а його екземпляр містить один екземпляр типа запису власника Учбова група
і N екземплярів типа запису-члена Студент. Певний екземпляр типа запису-члена не може
одночасно належати більш ніж одному екземпляру типа запису-власника. Унікальність
власника типа набору є обов'язковим елементом мережевої моделі даних. З цієї точки зору
ієрархічна модель є окремим випадком мережевої моделі даних.

Для мережевої моделі не існує загальноприйнятої термінології. Далі використовується група


понять і термінів, які використовуються для опису елементів мережевої моделі, що склала
до теперішнього часу.

Для моделювання представлення даних в мережевій моделі використовуються наступні


елементи даних:
- просте поле (елемент даних, итем) - найменша одиниця структури даних, має унікальне
ім'я, розмір і типа: (табельний номер службовця);
- множинне поле (агрегат даних, періодична група) - пойменована сукупність простих полів
або агрегатів; (простий агрегат: Дата = (день, місяць, рік)), (складений агрегат: Організація
= (найменування, адреса = (почтовый_индекс, місто, вулиця, дома_номер))), (група, що
повторюється: зарплата (12) = (ФІО, оклад));
- запис (група даних) - пойменований агрегат, який не входить до складу ніякого іншого
агрегату і представляє суть ПО БД (тип запису);
- групове відношення (зв'язок, набір) - ієрархічне відношення між різними записами
(графічне представлення групового відношення в мережевій моделі називається діаграмою
Бахмана);
- БД - сукупність записів різного типа, об'єднана системою групових стосунків різної
спрямованості.

На рисунку приведений фрагмент опису схеми БД на прикладі запису з БД "Кадри",


призначеної для автоматизації роботи відділу кадрів організації.

Елементи даних мережевої моделі допускають обробку наступними операціями, множина


яких складає мова маніпулювання даними:

ЗАПАМ'ЯТАТИ - заносить екземпляр запису в БД і включає його в існуюче відношення;


ПРИЄДНАТИ - зв'язує існуючі записи в групове відношення і визначає підпорядкування
записів (батько-нащадок);
ПЕРЕМКНУТИ - пов'язує екземпляр підлеглого запису з іншим екземпляром запису-батька;
МОДИФІКУВАТИ - змінює значення полів в існуючих записах БД, перед виконанням цієї
операції запис має витягувати з БД;
ЗНАЙТИ - знаходить записи з БД згідно критерію пошуку;
ВИДАЛИТИ - видаляє з БД непотрібний запис;
ВІДОКРЕМИТИ - розриває існуючий зв'язок між записами в груповому відношенні;
ОТРИМАТИ - витягує записи з БД.
Дуже часто до недоліків мережевого підходу в БД відносять як складність самої моделі
даних, так і складність освоєння засобів маніпулювання даними в ній. Практично, при
аналізі ПЗ БД і програмування особливо ретельно доводиться відстежувати ланцюжки
зв'язаних груповими стосунками даних при операціях вставки, оновлення і видалення.
Проте дійсне джерело складності мережевої моделі даних полягає в діапазоні конструкцій,
що надаються моделлю, для представлення інформації і набору операції для маніпулювання
цими конструкціями.
XML та JSON

Що таке XML
XML (eXtensible Markup Language) – це розширювана мова розмітки - стандарт побудови мов
розмітки ієрархічно структурованих даних . Є спрощеною підмножиною мови
розмітки SGML. XML документ складається із текстових знаків, і придатний до читання
людиною.

Створений для передачі для зберігання даних.

XML важливо знати і легко вивчити.

Приклад XML документу:

<?xml version="1.0" encoding="UTF-8"


<note>
<to> Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

Тегом (Tag) в XML називається текст, що заключний між в <>. Назви тегів в XML можуть
бути довільними і визначаються автором XML-документу.

Для чого XML:


- спрощує обмін даними між різними пристроями усуваючи необхідність погодження
формату передачі даних
- спрощує передачу даних, оскільки існує готовий набір бібліотек
- робить дані більш доступними, оскільки вони зберігаються у human-readable форматі
- використаний для створення новий інтернет-мов (XHTML, WSDL, WAP, RSS, etc)

Структура документу
XML документ має структуру дерева, починається з корені (root) та має гілки(branch) і
листки (leaf).

1. <?xml version="1.0" encoding="UTF-8"


2. <note>
3. <to> Tove</to>
4. <from>Jani</from>
5. <heading>Reminder</heading>
6. <body>Don't forget me this weekend!</body>
7. </note>

Стрічка 1 – вказує, що це xml документу, версії 1.0, кодування UTF-8. Ця стрічка


називається prolog
Стрічка 2 – містить кореневий елемент <note>
Стрічка 3 – 6 містять дочірні елементи
Стрічка 7 – вказує на завершення (закриття) кореневого елементу.

Правила синтаксису
Всі xml теги мають мати закриваючий тег
<tag></tag>
<tag/>

Назви тегів є чутливими до регістру.


<Message>This is incorrect</message>

Вкладені теги повинні дотримуватися структури дерева


<b><i>This text is bold and italic</i></b>

Кореневий елемент є обов’язковим


<root>
<child>
<subchild>.....</subchild>
</child>
</root>

Атрибути елементів потрібно завжди брати в лапки і вони мають бути унікальними для
одного елементу
<note date="12/11/2007">

Документ який відповідає усім вимогами називається “Well Formed”

Атрибути
Тег може мітити додаткову інформацію у вигляді атрибутів.

<note date="12/11/2007">
Особливих правил, що має бути тегом, а що атрибутом немає. Наступні три приклади є
еквівалентними

<note date="10/01/2008">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

<note>
<date>10/01/2008</date>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

<note>
<date>
<day>10</day>
<month>01</month>
<year>2008</year>
</date>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

При використанні атрибутів варто враховувати, що:


- атрибути не можуть мати декілька значень
- атрибути не можуть містити деревовидної структури
- атрибути буде важко розширювати (в майбутньому)

Використання префіксів
Приклад різних сутностей, які будучи в одному xml-документів призведуть до конфлікту
імен.

<table> <table>
<tr> <name>African Coffee Table</name>
<td>Apples</td> <width>80</width>
<td>Bananas</td> <length>120</length>
</tr> </table>
</table>

Для розв’язання можливих конфліктів імен при формуванні великих xml-документів,


допускається використання префіксів (prefix).
<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>

<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>

При використання префіксів, потрібно задати для них namespace. Задається при
допомозі xmlns атрибуту в першому елементі.

xmlns:prefix="URI".

URI використовується не як джерело інформації, а як унікальний ідентифікатор.

<root>

<h:table xmlns:h="http://www.w3.org/TR/html4/">
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>

<f:table xmlns:f="http://www.w3schools.com/furniture">
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>

</root>

Або задати на початку документу

<root xmlns:h=http://www.w3.org/TR/html4/
xmlns:f="http://www.w3schools.com/furniture">

<h:table>
<h:tr>
<h:td>Apples</h:td>
<h:td>Bananas</h:td>
</h:tr>
</h:table>

<f:table>
<f:name>African Coffee Table</f:name>
<f:width>80</f:width>
<f:length>120</f:length>
</f:table>

</root>

Валідація xml документів


Документ вражається валідним, якщо
- структура документу коректно сформована (well formed)
- зміст документу відповідає його типу.

Для перевірки відповідності змісту документу його типу використовується


- DTD (Document type difinition)
- XML Schema
XML DTD
Для вказання того, що документ має відповідати DTD правилам, на його початку ставиться
тег
<!DOCTYPE note SYSTEM "Note.dtd">

Зміст файлу note.dtd

<!DOCTYPE note
[
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>

!DOCTYPE note – корінь документу


!ELEMENT note - оголошує що note документ містить чотири елементи "to, from, heading,
body"
!ELEMENT to – оголошує, що елемент to містить тип "#PCDATA"
!ELEMENT from – оголошує, що елемент from "#PCDATA"

XML Schema
Аналогом DTD є XML schema, яка в свою чергу теж є xml документом.

<xs:element name="note">
<xs:complexType>
<xs:sequence>
<xs:element name="to" type="xs:string"/>
<xs:element name="from" type="xs:string"/>
<xs:element name="heading" type="xs:string"/>
<xs:element name="body" type="xs:string"/>
</xs:sequence>
</xs:complexType>

</xs:element>

<xs:element name="note"> оголошує елемент "note"


<xs:complexType> елемент "note" є складеним
<xs:sequence> складений елемент є послідовність елементів
<xs:element name="to" type="xs:string"> елемент "to" містить стрічковий тип (text)
<xs:element name="from" type="xs:string"> елемент "from" містить стрічковий тип

JSON

JSON (JavaScript Object Notation) відкритий легковісний текстовий стандарт представлення


даних у читабельній для людей формі.

Викоритсання json:
- написанні javascirpt-застосунків
- серіалізації та пересилання структурованої інформації
- один з основних способів передчі даних від сервера до клієнта у web-застосунках
- Веб-сервіси та API використовують json для представлення даних
- підтримується сучасними мовами програмування та базами даних

Приклад:
{
"book": [
{
"id":"01",
"language": "Java",
"edition": "third",
"author": "Herbert Schildt"
},
{
"id":"07",
"language": "C++",
"edition": "second"
"author": "E.Balagurusamy"
}]
}

Дані представляються у вигляді пар name-value.


Фігурні дужки містять об’єкти, і за кожним іменем слідує двокрапка “:”. Пари ім’я/значення
розділяються комами.
Квадратні дужки містять списки об’єктів, які роділяються комами.

JSON підтримує декілька типів даних


Number double- precision floating-point format in JavaScript
String double-quoted Unicode with backslash escaping
Boolean true or false
Array an ordered sequence of values
Value it can be a string, a number, true or false, null etc
Object an unordered collection of key:value pairs
Whitespace can be used between any pair of tokens
null empty

JSON Schema
Для перевірки коректності json-документу можна використовувати валідацію цього
документу на відповідність заданій структурі:
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"id": {
"description": "The unique identifier for a product",
"type": "integer"
},
"name": {
"description": "Name of the product",
"type": "string"
},
"price": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
}
},
"required": ["id", "name", "price"]
}
Реляційна модель даних

На цій лекції ми введемо на порівняно неформальному рівні основні поняття реляційних


баз даних, а також визначимо істота реляційної моделі даних. Основною метою лекції є
демонстрація простоти і можливості інтуїтивної інтерпретації цих понять. У подальших
лекціях будуть приводитися більш формальні визначення, на яких грунтується математична
теорія реляційних баз даних.

Базові поняття реляційних баз даних


Основними поняттями реляційних баз даних є тип даних, домен, атрибут, кортеж,
первинний ключ і відношення.
Для початку покажемо зміст цих понять на прикладі відношення СПІВРОБІТНИКИ, що
містить інформацію про співробітників деякої організації:

Поняття тип даних в реляційної моделі даних повністю відповідає поняттю типу даних в
мовах програмування. Зазвичай в сучасних реляційних БД допускається зберігання
символьних, числових даних, бітових рядків, спеціалізованих числових даних (таких як
"гроші" ), а також спеціальних " темпоральних " даних ( дата, час, часовий інтервал ). Досить
активно розвивається підхід до розширення можливостей реляційних систем абстрактними
типами даних ( відповідними можливостями володіють, наприклад, системи сімейства Ingres
/ Postgres ). У нашому прикладі ми маємо справу з даними трьох типів: рядки символів, цілі
числа і " гроші".

Поняття домену більш специфічно для баз даних, хоча і має деякі аналогії з підтипами в
деяких мовах програмування. У найзагальнішому вигляді домен визначається заданням
деякого базового типу даних, до якого відносяться елементи домену, і довільного логічного
виразу, який застосовується до елемента типу даних. Якщо обчислення цього логічного виразу
дає результат "істина", то елемент даних є елементом домену.
Найбільш правильною інтуїтивною трактуванням поняття домену є розуміння домену як
допустимої множини значень даного типу. Наприклад, домен " Імена" у нашому прикладі
визначений на базовому типі рядків символів, але в число його значень можуть входити лише
ті рядки, які можуть зображати ім'я (зокрема, такі рядки не можуть починатися з м'якого
знака).
Слід відзначити також семантичне навантаження поняття домену: дані можна порівнювати
тільки в тому випадку, коли вони відносяться до одного домену. У нашому прикладі значення
доменів " Номери пропусків " і " Номери груп " відносяться до типу цілих чисел, але не є
порівнюваними. Зауважимо, що в більшості реляційних СУБД поняття домену не
використовується.

Схема відношення - це іменована множина пар { ім'я атрибута, ім'я домену (або типу, якщо
поняття домену не підтримується) }.
Ступінь або " арність " схеми відношення - потужність цієї множини (кардинальне
число множини). Для скінченної множини A кардинальним числом |A| є натуральне число,
яким позначається кількість елементів цієї множини. Ступінь відношення СПІВРОБІТНИКИ
дорівнює чотирьом, тобто воно є 4- арним. Якщо всі атрибути одного відношення визначені
на різних доменах, осмислено використовувати для іменування атрибутів імена відповідних
доменів.

Схема БД ( в структурному сенсі) - це набір іменованих схем відносин.

Кортеж, що відповідає даній схемі відносини, - це множина пар { ім'я атрибута, значення
}, яка містить одне входження кожного імені атрибута, що належить схемі відносини. "
Значення " є допустимим значенням домену даного атрибуту. Тим самим, ступінь або " арність
" кортежу, тобто число елементів у ньому, збігається з " арністю " відповідної схеми
відношення. Попросту кажучи, кортеж - це набір іменованих значень заданого типу.

Віднощення - це множина кортежів, які відповідають одній схемі відношення. Іноді, щоб не
плутатися, говорять "відношення - схема" і "відношення - екземпляр", іноді схему відношення
називають заголовком відношення, а відношення як набір кортежів - тілом відношення.
Насправді, поняття схеми відносини найближче до поняття структурного типу даних в мовах
програмування. Було б цілком логічно дозволяти окремо визначати схему відношення, а потім
одне або декілька відношень за даною схемою.

Однак у реляційних базах даних це не прийнято. Ім'я схеми відношення в таких базах даних
завжди збігається з ім'ям відповідного віднощення - екземпляра. У класичних реляційних
базах даних після визначення схеми бази даних змінюються тільки відношення - екземпляри.
У них можуть з'являтися нові і відалятися або модифікуватися існуючі кортежі. Однак у
багатьох реалізаціях допускається і зміна схеми бази даних: визначення нових та зміна
існуючих схем відношень. Це прийнято називати еволюцією схеми бази даних.
Звичним представленням відношення є таблиця, заголовком якої є схема відношення, а
рядками - кортежі відношення - екземпляра ; в цьому випадку імена атрибутів іменують
стовпці цієї таблиці. Тому іноді кажуть " стовпець таблиці ", маючи на увазі " атрибут
відношення". Цією термінології дотримуються в більшості комерційних реляційних СУБД.

Реляційна база даних - це набір відношень, імена яких збігаються з іменами схем відношень
в схемі БД.

Фундаментальні властивості відносин


Зупинимося тепер на деяких важливих властивостях відношень, які випливають з
наведених раніше визначень:

Відсутність кортежів - дублікатів


Ця властивість, що відношнння не містять кортежів - дублікатів, випливає з визначення
відношення як множини кортежів. У класичній теорії множин за визначенням кожна
множина складається з різних елементів.
З цієї властивості випливає наявність у кожного відношення так званого первинного ключа -
набору атрибутів, значення яких однозначно визначають кортеж відношення.
Для кожного відношення принаймні повний набір його атрибутів володіє цією властивістю.
Однак при формальному визначенні первинного ключа потрібне забезпечення його
"мінімальності", тобто в набір атрибутів первинного ключа не повинні входити такі атрибути,
які можна відкинути без шкоди для основної властивості - однозначно визначати кортеж.
Поняття первинного ключа є виключно важливим у зв'язку з поняттям цілісності баз даних.
Варто зауважити, що в багатьох практичних реалізаціях РСУБД допускається порушення
властивості унікальності кортежів для проміжних відносин, породжуваних неявно при
виконанні запитів. Такі відносини є не множинами, а мультимножинами, що в ряді випадків
дозволяє домогтися певних переваг, але іноді призводить до серйозних проблем.

Відсутність впорядкованості кортежів


Властивість відсутності впорядкованості кортежів відношення також є наслідком
визначення відношення-екземпляра як множини кортежів.
Відсутність вимоги до підтримання порядку на множині кортежів відношення дає
додаткову гнучкість СУБД при зберіганні баз даних у зовнішній пам'яті і при виконанні
запитів до бази даних. Це не суперечить тому, що при формулюванні запиту до БД, наприклад,
на мові SQL можна зажадати сортування результуючої таблиці у відповідності зі значеннями
деяких стовпців. Такий результат, взагалі кажучи, не відношення, а деякий упорядкований
список кортежів.

Відсутність впорядкованості атрибутів


Атрибути відношення не впорядковані, оскільки за визначенням схема відношення є
множиною пар { ім'я атрибута, ім'я домену }.
Для посилання на значення атрибута в кортежі відношення завжди використовується ім'я
атрибута.
Ця властивість теоретично дозволяє, наприклад, модифікувати схеми існуючих відносин не
тільки шляхом додавання нових атрибутів, а й шляхом видалення існуючих атрибутів. Однак
у більшості існуючих систем така можливість не допускається, і хоча впорядкованість набору
атрибутів відносини явно не потрібно, часто як неявного порядку атрибутів використовується
їх порядок у лінійній формі визначення схеми відношення.

Атомарність значень атрибутів


Значення всіх атрибутів є атомарними. Це випливає з визначення домену як множини
значень деякого простого типу даних, тобто серед значень домену не можуть міститися
мнодини значень (відношення).
Прийнято говорити, що в реляційних базах даних допускаються тільки нормалізовані
відношення або відношення, представлені в першій нормальній формі. Прикладом
ненормалізованного відносини є наступне:
Можна сказати, що тут ми маємо бінарне відношення, значеннями атрибута ВІДДІЛИ якого
є відношеннями. Зауважимо, що вихідне відношення СПІВРОБІТНИКИ є нормалізованом
варіантом відносини ВІДДІЛИ:

СОТР_НОМЕР СОТР_ИМЯ СОТР_ЗАРП СОТР_ОТД_НОМЕР


2934 Иванов 112,000 310
2935 Петров 144,000 310
2936 Сидоров 92,000 313
2937 Федоров 110,000 310
2938 Иванова 112,000 315

Нормалізовані відношення становлять основу класичного реляційного підходу до


організації баз даних. Вони володіють деякими обмеженнями (Не будь-яку інформацію зручно
представляти у вигляді плоских таблиць), але істотно спрощують маніпулювання даними.
Розглянемо, наприклад, два ідентичних оператора занесення кортежу:

Зарахувати співробітника Кузнєцова


( пропуск номер 3000, зарплата 115,000 ) у відділ номер 320

Зарахувати співробітника Кузнєцова


( пропуск номер 3000, зарплата 115,000 ) у відділ номер 310

Якщо інформація про співробітників представлена у вигляді відношення


СПІВРОБІТНИКИ, обидва оператори будуть виконуватися однаково ( вставити кортеж в
відношення СПІВРОБІТНИКИ ). Якщо ж працювати з ненормалізованного відношенням
ВІДДІЛИ, то перший оператор виразиться в занесення кортежу, а другий - в додавання
інформації про Кузнецова в множину значення атрибуту ВІДДІЛ кортежу з первинним
ключем 310.

Реляційна модель даних


Коли ми говорили про основні поняття реляційних баз даних, ми не спиралися на яку-
небудь конкретну реалізацію. Ці міркування в рівній мірі відносяться до будь-якої системи,
при побудові якої використовувався реляційний підхід. Тобто, ми використовували поняття
так званої реляційної моделі даних.
Модель даних описує деякий набір родових понять і ознак, якими повинні володіти всі
конкретні СУБД і керовані ними бази даних, якщо вони грунтуються на цій моделі. Наявність
моделі даних дозволяє порівнювати конкретні реалізації, використовуючи одну спільну мову.

Найбільш поширена трактування реляційної моделі даних, належить Дейта - реляційна


модель складається з трьох частин, що описують різні аспекти реляційного підходу:
структурної частини, маніпуляційної частини і цілісної частини.
У структурній частині моделі фіксується, що єдиною структурою даних, що
використовується в реляційних БД, є нормалізоване n - арне відношення.

У маніпуляційної частини моделі затверджуються два фундаментальні механізми


маніпулювання реляційними БД - реляційна алгебра і реляційне числення.
Перший механізм базується в основному на класичній теорії множин (з деякими
уточненнями ), а другий - на класичному логічному апараті обчислення предикатів першого
порядку.
Основною функцією маніпуляційної частини реляційної моделі є забезпечення заходів
реляційності конкретної мови реляційних БД: мова називається реляційних, якщо вона має не
меншу виразністю і потужністю, ніж реляційна алгебра або реляційне числення.

В цілісній частині реляційної моделі даних фіксуються дві базові вимоги цілісності, які
повинні підтримуватися в будь-якої реляційної СУБД.

Перша вимога називається вимогою цілісності сутностей (entity integrity). Об'єкту або
сутності реального світу в реляційних БД відповідають кортежі відношень. Вимога полягає в
тому, що будь-який кортеж будь-якого відношення відрізнити від будь-якого іншого кортежу
цього відношення, тобто іншими словами, будь-яке відношення має володіти первинним
ключем. Ця вимога автоматично задовольняється, якщо в системі не порушуються базові
властивості відношень.
Теоретично будь-який кортеж, що заноситься у відношення, повинен містити всі
характеристики модельованої ним сутності реального світу. Проте на практиці не всі ці
характеристики можуть бути відомі до того моменту, коли ми фіксуємо сутність в базі даних.
Простим прикладом може бути процедура прийняття на роботу людини, розмір заробітної
плати якого ще не визначений. В цьому випадку службовець відділу кадрів, який заносить у
відношення СЛУЖБОВЦІ кортеж, що описує нового службовця, просто не може забезпечити
значення атрибуту Слу_зарп.
Едгар Кодд запропонував використовувати в таких випадках невизначені значення.
Невизначене значення не належить ніякому типу даних і може бути присутнім серед значень
будь-якого атрибуту, визначеного на будь-якому типові даних (якщо це явно не заборонено
при визначенні атрибуту). Якщо а - це значення деякого типа даних або NULL, op - будь-яка
бінарна арифметична операція цього типа даних (наприклад +), а lop - операція порівняння
значень цього типа (наприклад =), то за визначенням:
а op NULL = NULL
NULL op а = NULL
а lop NULL = unknown
NULL lop а = unknown

Тут unknown - це третє значення логічного, або булевого, типа, що володіє наступними
властивостями:
NOT unknown = unknown
true AND unknown = unknown
true OR unknown = true
false AND unknown = false
false OR unknown = unknown

Друга вимога називається вимогою цілісності по посиланнях (referential integrity).


Очевидно, що при дотриманні нормалізованності відношень складні сутності реального світу
представляються в реляційній БД у вигляді декількох кортежів декількох відношень.
Наприклад, уявімо, що нам потрібно представити в реляційної базі даних сутність ВІДДІЛ
з атрибутами ОТД_НОМЕР (номер відділу ), ОТД_КОЛ (кількість співробітників) і
ОТД_СОТР ( набір співробітників відділу ). Для кожного співробітника потрібно зберігати
СПІВР_НОМЕР (номер співробітника ), СОТР_ІМЯ (ім'я співробітника ) і СОТР_ЗАРП
(заробітна плата працівника). При правильному проектуванні відповідної БД в ній з'являться
два відношення: ВІДДІЛИ ( ОТД_НОМЕР, ОТД_КОЛ ) (первинний ключ - ОТД_НОМЕР ) і
СПІВРОБІТНИКИ ( СПІВР_НОМЕР, СОТР_ІМЯ, СОТР_ЗАРП, СОТР_ОТД_НОМ )
(первинний ключ - СПІВР_НОМЕР ).
Атрибут СОТР_ОТД_НОМ з'являється відносно СПІВРОБІТНИКИ не тому, що номер
відділу є власною властивістю співробітника, а лише для того, щоб мати можливість відновити
при необхідності повну сутність ВІДДІЛ. Значення атрибута СОТР_ОТД_НОМ в будь-якому
кортежі відносини СПІВРОБІТНИКИ повинно відповідати значенню атрибута ОТД_НОМ в
деякому кортежі відносини ВІДДІЛИ.

Атрибут такого роду називається зовнішнім ключем (foreign key), оскільки його значення
однозначно характеризують суті, представлені кортежами деякого іншого відношення ( тобто
задають значення їх первинного ключа).
Кажуть, що відношення, в якому визначено зовнішній ключ, посилається на відповідне
відношення, в якому такий же атрибут є первинним ключем.

Вимога цілісності по посиланнях, або вимога зовнішнього ключа полягає в тому, що для
кожного значення зовнішнього ключа, що міститься у одному відношенні, повинен знайтися
кортеж з таким же значенням первинного ключа у відношенні, на яку веде посилання, або
значення зовнішнього ключа повинно бути невизначеним (тобто ні на що не вказувати ). Для
нашого прикладу це означає, що якщо для співробітника вказано номер відділу, то цей відділ
повинен існувати.

Обмеження цілісності суті і за посиланнями повинні підтримуватися СУБД. Для


дотримання цілісності суті досить гарантувати відсутність в будь-якому відношенні кортежів
з одним і тим же значенням первинного ключа. З цілісністю по посиланнях трохи складніше.
Зрозуміло, що при оновленні посилається відносини ( вставці нових кортежів або
модифікації значення зовнішнього ключа в існуючих кортежах ) досить стежити за тим, щоб
не з'являлися некоректні значення зовнішнього ключа. Але як бути при видаленні кортежу з
відношення, на яку веде посилання ?
Тут існують три підходи, кожен з яких підтримує цілісність по посиланнях.
Перший підхід полягає в тому, що забороняється проводити видалення кортежу, на який
існують посилання ( тобто спочатку потрібно або видалити посилання кортежі, або
відповідним чином змінити значення їх зовнішнього ключа).
При другому підході при видаленні кортежу, на який є посилання, у всіх кортежах що
посилаються на нього значення зовнішнього ключа автоматично стає невизначеним.
Третій підхід полягає в тому, що при видаленні кортежу з відношення, на яке веде
посилання, автоматично видаляються всі кортежі, що мають посилання на цей кортеж (
каскадне видалення ).
У розвинених реляційних СУБД зазвичай можна вибрати спосіб підтримки цілісності по
посиланнях для кожної окремої ситуації визначення зовнішнього ключа. Звичайно, для
прийняття такого рішення необхідно аналізувати вимоги конкретної прикладної області.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:30. Версія: 1. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

Тема: Загальні поняття реляційного підходу до організації БД

Засоби маніпулювання реляційними даними


В маніпуляційна складова визначають два базових механізми маніпулювання реляційними даними -
заснована на теорії множин реляційна алгебра і засноване на математичній логіці (точніше, на численні
предикатів першого порядку) реляційне числення. У свою чергу, зазвичай розглядаються два види
реляційного числення - числення доменів і числення предикатів.

Ці механізми володіють однією важливою властивістю: вони замкнені відносно поняття відношення.
Це означає, що вирази реляційної алгебри і формули реляційного числення визначаються над
відношеннями реляційних БД і результатом обчислення також є відношення. В результаті будь-який
вираз або формула можуть інтерпретуватися як відношення, що дозволяє використовувати їх в інших
виразах або формулах.

Алгебра та числення володіють великою виразною потужністю: дуже складні запити до бази даних
можуть бути виражені за допомогою одного виразу реляційної алгебри або однієї формули реляційного
числення. Саме з цієї причини ці механізми включені в реляційну модель даних.
Конкретна мова маніпулювання реляційними БД називається реляційно повною, якщо будь-який
запит, що виражається за допомогою одного виразу реляційної алгебри або однієї формули реляційного
числення, може бути виражена за допомогою одного оператора цієї мови.

Відомо, що механізми реляційної алгебри і реляційного числення еквівалентні, тобто для будь-якого
допустимого вираження реляційної алгебри можна побудувати еквівалентну формулу реляційного
числення і навпаки. Чому ж в реляційній моделі даних присутні обидва ці механізму ?
Справа в тому, що вони розрізняються рівнем процедурності. Вирази реляційної алгебри будуються
на основі алгебраїчних операцій (високого рівня), і подібно до того, як інтерпретуються арифметичні і
логічні вирази, вираз реляційної алгебри також має процедурну інтерпретацію. Іншими словами, запит,
представлений на мові реляційної алгебри, може бути обчислений на основі елементарних
алгебраїчних операцій з урахуванням їх старшинства і наявності дужок. Для формули реляційного
числення однозначна інтерпретація, взагалі кажучи, відсутня. Формула тільки встановлює умови, яким
повинні задовольняти кортежі результуючого відношення. Тому мови реляційного числення є більш
непроцедурними або декларативними.
Оскільки механізми реляційної алгебри і реляційного числення еквівалентні, то в конкретній ситуації
для перевірки ступеня реляційності деякої мови БД можна користуватися будь-яким з цих механізмів.
Зауважимо, що вкрай рідко алгебра або числення приймаються в якості повної основи для мови БД.
Зазвичай (як, наприклад, у випадку мови SQL ) мова грунтується на деякій суміші алгебраїчних і логічних
конструкцій. Проте, знання алгебраїчних і логічних основ мов баз даних часто буває корисно на практиці.
У викладі нижче будемо слідувати підходу Дейта.

Реляційна алгебра
Основна ідея реляційної алгебри полягає в тому, що оскільки відношення є множинами, то засоби
маніпулювання відношенями можуть базуватися на традиційних теоретико -множинних операціях,
доповнених деякими спеціальними операціями, специфічними для баз даних.

Існує багато підходів до визначення реляційної алгебри, які розрізняються набором операцій і
способами їх інтерпретації, але в принципі, більш-менш рівносильні.
Розглянемо розширений початковий варіант алгебри, який був запропонований Коддом (реляційна
алгебра Кодда). У цьому варіанті набір основних алгебраїчних операцій складається з восьми операцій,
які діляться на два класи - теоретико - множинні операції та спеціальні реляційні операції.
До складу теоретико -множинних операцій алгебри Кодда входять операції:
- об'єднання відношень;
- перетину відношень;
- взяття різниці відношень;
- декартовий добуток відношень.
Спеціальні реляційні операції включають:
- обмеження відношень;
- проекцію відношень;
- з’єднання відношень;
- ділення відношень.
Крім того, до складу алгебри включається операція присвоювання, що дозволяє зберегти в базі
даних результати обчислення алгебраїчних виразів, і операція перейменування атрибутів, що дає
можливість коректно сформувати заголовок (схему) результуючого відношення.

Загальна інтерпретація реляційних операцій алгебри


Якщо не вдаватися в деякі тонкощі, то майже всі операції запропонованого вище набору володіють
очевидною і простою інтерпретацією.
При виконанні операції об'єднання двох відношень отримується відношення, що включає всі кортежі,
що входять хоча б в одне з відношень - операндів.
Операція перетину двох відношень виробляє відношення, що включає всі кортежі, що входять в
обидва відношення - операнда.
Відношення, що є різницею двох відношень включає всі кортежі, що входять у відношення - перший
операнд, такі, що жоден з них не входить до відношення, яке є другим операндом.
При виконанні декартового добутку двох відношень отримується відношення, кортежі якого є
конкатенацією ( зчепленням ) кортежів першого і другого операндів.
Результатом обмеження (вибірки) відношення по деякій умові є відношення, що включає кортежі
відношення - операнда, яке задовольняє цій умові.
При виконанні проекції відношення на заданий набір його атрибутів виробляється відношення,
кортежі якого виробляються шляхом знаходження відповідних значень з кортежів відношеня - операнда.
При об’єднання двох відношень по деякій умові утворюється результуюче відношення, кортежі якого
є конкатенацію кортежів першого і другого відношення і задовольняють цій умові.
У операції реляційного ділення два операнди - бінарне і унарне відношення. Результуюче
відношення складається з одноатрібутних кортежів, що включають значення першого атрибуту кортежів
першого операнда таких, що множина значень другого атрибута ( при фіксованому значенні першого
атрибута) збігається з множиною значень другого операнда.
Операція перейменування виробляє відношення, тіло якого збігається з тілом операнда, але імена
атрибутів змінені.
Операція присвоювання дозволяє зберегти результат обчислення реляційного виразу в існуючому
відношенні БД.
Оскільки результатом будь-якої реляційної операції (крім операції присвоювання ) є деяке
відношення, то можна утворювати реляційні вирази, в яких замість відношення - операнда деякої
реляційної операції знаходитиметься вкладений реляційний вираз.

Теоретико-множинні операції реляційної алгебри


Хоча в основі теоретико-множинної частки реляційної алгебри Кодда лежить класична теорія
множин, відповідні операції реляційної алгебри володіють деякими особливостями.
В теорії множин:
* результатом об'єднання (UNION) двох множин A{a} і B{b} є така множина C{c}, що для кожного с
або існує такий елемент а, що належить множині A, що c=a, або існує такий елемент b, що належить
множині B, що c=b;
* перетином (INTERSECT) множина A і B є така множина C{c}, що для будь-якого з існують такі
елементи а, що належить множина A, і b, що належить множина B, що c=a=b;
* різницею (MINUS) множина A і B є така множина C{c}, що для будь-якого з існує такий елемент а,
що належить множина A, що c=a, і не існує такий елемент b, належний B, що c=b.

Але якщо в теорії множин операція об'єднання осмислена для будь-яких двох множин-операндів, то
у випадку разі реляційної алгебри результатом операції об'єднання має бути відношення. Якщо в
реляційній алгебрі допустити можливість теоретико-множинного об'єднання двох довільних відношень
(з різними заголовками), то, звичайно, результатом операції буде множина, але множина різнотипних
кортежів, тобто не відношень. Якщо виходити з вимоги замкнутості реляційної алгебри щодо поняття
відношення, то така операція об'єднання є безглуздою.
Такі міркування підводять до поняття сумісності відношень по об'єднанню: два відношення сумісні
по об'єднанню в тому і лише у тому випадку, коли володіють однаковими заголовками. У розгорненій
формі це означає, що в заголовках обох відношень міститься один і той же набір імен атрибутів, і
однойменні атрибути визначені на одному і тому ж домені.
Якщо два відношення сумісні по об'єднанню, то при звичайному виконанні над ними операцій
об'єднання, перетину і узяття різниці результатом операції є відношення з коректним заголовком,
співпадаючим із заголовком кожного із відношень-операндів.
Якщо два відношення «майже» сумісні по об'єднанню, тобто сумісні у всьому, окрім імен атрибутів,
то до виконання операції об'єднання ці відношення можна зробити повністю сумісними по об'єднанню
шляхом застосування операції перейменування.
Наприклад операція об'єднання, перетину і узяття різниці припустимо в базі даних є два відношення
Службовці_в_проекті_1 і Службовці_в_проекті_2 з однаковими схемами { Слу_номер, Слу_імя,
Слу_зарп, Слу_отд_номер}. Кожне із відношень містить дані про службовців, що беруть участь у
відповідному проекті.

Тоді виконання операції Службовці_в_проекті_1 UNION Службовці_в_проекті_2 дозволить


отримати інформацію про всіх службовців, що беруть участь в обох проектах.
Виконання операції Службовці_в_проекті_1 INTERSECT Службовці_в_проекті_2 дозволить
отримати дані про службовців, які одночасно беруть участь в двох проектах.
Виконання операції Службовці_в_проекті_1 MINUS Службовці_в_проекті_2 виробить
відношення, що містить кортежі службовців, які беруть участь тільки в першому проекті.

Результати виконання операцій UNION, INTERSECT і MINUS

Відмітимо, що включення до складу операцій реляційної алгебри одразу трьох операцій об'єднання,
перетину і узяття різниці є, очевидно, надлишковим, оскільки, наприклад, операція перетину
виражається через операцію узяття різниці. Проте Кодд свого часу вирішив включити всі три операції,
виходячи з інтуїтивних потреб далекого від математики потенційного користувача системи реляційних
БД.

У теорії множин декартовий добуток (TIMES) може бути отриманий для будь-яких двох множин, і
елементами результуючої множини є пари, складені з елементів першої і другої множин. Якщо говорити
точніше, декартовим добуток множин A{a} і B{b} є така множина пар C{<c1, c2>}, що для кожного
елементу <c1, c2> множини C існує такий елемент а множина A, що c1=a, і такий елемент b множинаі
B, що c2=b.
Оскільки відношення є множинами, для будь-яких двох відношень можливе отримання прямого
добуток. Але результат не буде відношенням. Елементами результату будуть не кортежі, а пари
кортежів.
Тому в реляційній алгебрі використовується спеціалізована форма операції узяття декартового
добуток - розширений декартовий добуток відношень. При узятті розширеного декартового добуток
двох відношень елементом результуючого відношення є кортеж, який є об'єднанням одного кортежу
першого відношення і одного кортежу другого відношення.
Нехай є два відношення R1{a1, a2, …, an} і R2{b1, b2, …, bm}. Тоді результатом операції R1 TIMES R2 є
відношення R{a1, a2, …, an, b1, b2, …, bm}, тіло якого є множина кортежів вигляду {ra1, ra2, …, ran, rb1, rb2, …,
rbm} таких, що {ra1, ra2, …, ran} входить в тіло R1, а {rb1, rb2, …, rbm} входить в тіло R2.
Але тепер виникає друга проблема - як отримати коректно сформований заголовок відношення-
результату? Оскільки схема результуючого відношення є об'єднанням схем відношень-операндів, то
очевидною проблемою може бути іменування атрибутів результуючого відношення, якщо відношення-
операнди володіють однойменними атрибутами.
Ці міркування приводять до введення поняття сумісності по узяттю розширеного декартового
добутоку. Два відношення сумісні по узяттю розширеного декартового добутку в тому і лише в тому
випадку, якщо перетин множин імен атрибутів, узятих з їх схем відношень, порожній. Будь-які два
відношення завжди можуть стати сумісними по узяттю декартового добутку, якщо застосувати операцію
перейменування до одного з цих відношень.
Для ілюстрації використання декартового добутку припустимо, що на додаток до введених раніше
відношень Службовці_в_проекті_1 і Службовці_в_проекті_2 в базі даних міститься ще і відношення
ПРОЕКТИ з схемою { Проєкт_назв, Проєкт_рук} (імена доменів знову опущені). Тоді результат операції
Службовці_в_проекті_1 TIMES ПРОЕКТИ буде:

Слід зауважити, що операція узяття декартового добутку не є дуже осмисленою на практиці. По-
перше, потужність тіла її результату дуже велика навіть при допустимих потужностях операндів, а, по-
друге, результат операції не більш інформативний, ніж узяті в сукупності операнди. Як буде показано
далі, основний сенс включення операції розширеного декартового добутку до складу реляційної
алгебри Кодда полягає в тому, що на її основі визначається дійсно корисна операція з'єднання.

З приводу теоретико-множинних операцій реляційної алгебри слід ще відмітити, що всі чотири


операції є асоціативними. Т. е. якщо позначити через OP будь-яку з чотирьох операцій, то (A OP B) OP
C = A OP (B OP C), і, отже, без внесення двозначності можна писати A OP B OP C (A, B і C - відношення,
що володіють властивостями, необхідними для коректного виконання відповідної операції). Всі операції,
окрім узяття різниці, є комутативними, тобто A OP B = B OP A.

Спеціальні реляційні операції

Операція обмеження (WHERE)


Операція обмеження вимагає наявності двох операндів: обмежуване відношення і простої умова
обмеження.
Умова обмеження може мати видгляд ( a comp-op b ), де а і b - імена атрибутів обмежуваного
відношення, для яких осмислена операція порівняння comp-op, або видгляд (a comp-op const ), де a -
ім'я атрибута обмежуваного відношення, а const - літерально задана константа.
В результаті виконання операції обмеження виробляється відноешння, заголовок якого співпадає з
заголовком відношення - операнда, а в тіло входять ті кортежі відношення - операнда, для яких
значенням умови обмеження є true.
Нехай UNION позначає операцію об'єднання, INTERSECT - операцію перетину, а MINUS - операцію
взяття різниці. Для позначення операції обмеження будемо використовувати конструкцію A WHERE
comp, де A - обмежувати відносини, а comp - проста умова порівняння.
Нехай comp1 і comp2 - два простих умови обмеження. Тоді за визначенням:

A WHERE comp1 AND comp2 те ж саме, що (A WHERE comp1) INTERSECT (A WHERE comp2)

A WHERE comp1 OR comp2 те ж саме, що (A WHERE comp1) UNION (A WHERE comp2)

A WHERE NOT comp1 те ж саме, що A MINUS (A WHERE comp1)

З використанням цих визначень можна використовувати операції обмеження, в яких умовою


обмеження є довільний булевий вираз, складений з простих умов з використанням логічних зв'язок AND,
OR, NOT і дужок.

Результат виконання операції Службовці_в_проекті_1 WHERE (Слу_зарп > 20000.00 AND


(Слу_отд_ном = 310 OR Слу_отд_ном = 315))
На інтуїтивному рівні операцію обмеження найкраще представляти як взяття деякої "горизонтальної
" вирізки з відношення - операнда.

Операція взяття проекції (PROJECT)


Операція взяття проекції також вимагає наявності двох операндів - проектованого відношення A і
списку імен атрибутів, що входять у заголовок відношення A.
Результатом проекції відношення A зі списком атрибутів a1, a2,..., an є відношення, із заголовком,
визначеним множиною атрибутів a1, a2,..., an, і з тілом, що складається з кортежів виду < a1: v1, a2:
v2,..., an: vn > таких, що відносно A є кортежем, атрибут a1 якого має значення v1, атрибут a2 має
значення v2,..., атрибут an має значення vn.

Результат операції PROJECT Службовці_в_проекті_1 { Слу_отд_ном} (у яких відділах працюють


службовці, дані про яких містяться відносно Службовці_в_проекті_1?).

При виконанні операції проекції виділяється "вертикальна" вирізка відношення - операнда з


природним знищенням потенційно виникаючих кортежів - дублікатів.

Операція з’єднання відношень (JOIN)


Загальна операція з’єднання (що також називається з'єднанням за умовою) вимагає наявності двох
операндів - з'єднуваних відношень і третього операнда - простої умови.
Нехай з’єднуються відношення A і B. Як і у випадку операції обмеження, умова з’єднання comp має
вигляд або ( a comp-op b ), або ( a comp-op const ), де a і b - імена атрибутів відношення A і B, const -
літерально задана константа, а comp - op - допустима в даному контексті операція порівняння.
Тоді за визначенням результатом операції порівняння є відношення, що отримується шляхом
виконання операції обмеження за умовою comp декартового добутку відношень A і B.
Є окремий випадок з’єднання – еквіз’єднання (EQUIJOIN) і просте, але важливе розширення
операції еквіз’єднання - природне з’єднання (NATURAL JOIN).
Операція об’єднання називається операцією еквіз’єднання, якщо умова з’єднання має вигляд ( a = b
), де a і b - атрибути різних операндів з’єднання. Цей випадок важливий тому, що ( a ) він часто
зустрічається на практиці, і ( b ) для нього існують ефективні алгоритми реалізації.
Операція природного з’єднання застосовується до пари відношень A і B, що володіють загальним
атрибутом c (тобто атрибутом з одним і тим же ім'ям і визначеним на одному і тому ж домені).
Нехай ab позначає об'єднання заголовків відносин A і B. Тоді природне з’єднання A і B - це
спроектований на ab результат еквіз’єднання A і B по A / С і BBC.
Основний зміст операції природного з’єднання - можливість відновлення складної сутності, що
підлягла декомпозиції з причин вимоги першої нормальної форми. Операція природного з’єднання не
включається прямо до складу набору операцій реляційної алгебри, але вона має дуже важливе
практичне значення.
Для предметної області

результати операцій СЛУЖБОВЦІ JOIN (ПРОЕКТИ RENAME (Про_ном, Про_ном1)) WHERE


(Слу_зарп = Про_зарп) (эквізєднання відношень СЛУЖБОВЦІ і ПРОЕКТИ: знайти всіх службовців,
одержуючих зарплату, рівну середній заробітній платі в якому-небудь проекті) і СЛУЖБОВЦІ NATURAL
JOIN ПРОЕКТИ (природне з'єднання - видати повну інформацію про службовців і проекти, в яких вони
беруть участь).

Операція ділення відношень (DIVIDE BY)


Ця операція найменш очевидна з усіх операцій реляційної алгебри і тому потребує більш докладного
пояснення.
Нехай задані два відношення - A з заголовком { a1, a2,..., an, b1, b2,..., bm } і B з заголовком { b1,
b2,..., bm }. Будемо вважати, що атрибут bi відношення A і атрибут bi відношення B не тільки володіють
одним і тим же ім'ям, але й визначені на одному і тому ж домені. Назвемо множину атрибутів { aj }
складовим атрибутом a, а множину атрибутів { bj } - складовим атрибутом b. Після цього будемо
говорити про реляційне ділення бінарного відношення A ( a, b ) на унарне відношення B ( b ).
Результатом розподілу A на B є унарне відношення C ( a ), що складається з кортежів v таких, що у
відношення A є кортежі <v, w> такі, що множина значень { w } включає множину значень атрибуту b
відносно B.
Припустимо, що в базі даних співробітників підтримуються два відношення: СПІВРОБІТНИКИ ( ІМ'Я,
ОТД_НОМЕР ) і ІМЕНА ( ІМ'Я ), причому унарне відношення ІМЕНА містить усі прізвища, якими
володіють співробітники організації. Тоді після виконання операції реляційного ділення відношення
СПІВРОБІТНИКИ на відношення ІМЕНА буде отримано унарне відношення, що містить номери відділів,
співробітники яких володіють всіма можливими в цій організації іменами.

Для ілюстрації цієї операції припустимо, що в базі даних службовців підтримуються наступні
відношення: СЛУЖБОВЦІ, як воно було визначене раніше, і унарне відношення Номери_проектів {
Про_ном}.
Тоді запит СЛУЖБОВЦІ DIVIDE BY Номери_проектів видасть дані про всіх службовців, що беруть
участь у всіх проектах.
Реляційне числення
Припустимо, що ми працюємо з базою даних, що володіє схемою СПІВРОБІТНИКИ ( СОТР_НОМ,
СОТР_ІМЯ, СОТР_ЗАРП, ОТД_НОМ ) і ВІДДІЛИ ( ОТД_НОМ, ОТД_КОЛ, ОТД_НАЧ ), і хочемо дізнатися
імена та номери співробітників, які є начальниками відділів з кількістю співробітників більше 50.
Якби для формулювання такого запиту використовувалася реляційна алгебра, то ми отримали б
алгебраїчний вираз, який читалося б, наприклад, таким чином:
- виконати зєднання відношень СПІВРОБІТНИКИ і ВІДДІЛИ за умовою СОТР_НОМ = ОТД_НАЧ ;
- обмежити отримане відношення за умовою ОТД_КОЛ > 50 ;
- спроектувати результат попередньої операції на атрибут СОТР_ІМЯ, СОТР_НОМ.

Ми чітко сформулювали послідовність кроків виконання запиту, кожен з яких відповідає одній
реляційної операції. Якщо ж сформулювати той самий запит з використанням реляційного числення, то
ми отримали б формулу, яку можна було б прочитати, наприклад, таким чином:
Повернути СОТР_ІМЯ і СОТР_НОМ для співробітників таких, що існує відділ з таким же значенням
ОТД_НАЧ і значенням ОТД_КОЛ великим 50.

У другому формулюванні ми вказали лише характеристики результуючого відношення, але нічого не


сказали про спосіб його формування. У цьому випадку система повинна сама вирішити, які операції і в
якому порядку потрібно виконати над відношеннями СПІВРОБІТНИКИ і ВІДДІЛИ.
Зазвичай кажуть, що алгебраїчне формулювання є процедурним, тобто задає правила виконання
запиту, а логічне - описовим (або декларативною ), оскільки воно всього лише описує властивості
бажаного результату.
Насправді ці два механізми еквівалентні і існують не дуже складні правила перетворення одного
формалізму в іншій.

Кортежних змінні і правильно побудовані формули


Реляційне числення є прикладною гілкою формального механізму обчислення предикатів першого
порядку. Базисними поняттями обчислення є поняття змінної з певною для неї областю допустимих
значень і поняття правильно побудованої формули, що спирається на змінні, предикати і квантори.
Залежно від того, що є областю визначення змінної, розрізняються числення кортежів та числення
доменів.
У численні кортежів областями визначення змінних є відношення бази даних, тобто допустимим
значенням кожної змінної є кортеж деякого відношення.
У численні доменів областями визначення змінних є домени, на яких визначені атрибути відношень
бази даних, тобто допустимим значенням кожної змінної є значення деякого домену.

На відміну від реляційної алгебри, при використанні числення необхідно доби римуватися деякого
конкретного синтаксису. Використовуваний синтаксис близький, але не повністю збігається з
синтаксисом мови баз даних QUEL, який довгий час був основною мовою СУБД Ingres.

Для визначення кортежної змінної використовується оператор RANGE. Наприклад, для того, щоб
визначити змінну СПІВРОБІТНИК, областю визначення якої є ставлення СПІВРОБІТНИКИ, потрібно
вжити конструкцію
RANGE СПІВРОБІТНИК IS СПІВРОБІТНИКИ

Як ми вже говорили, з цього визначення випливає, що в будь-який момент часу змінна


СПІВРОБІТНИК представляє деякий кортеж відношення СПІВРОБІТНИКИ. При використанні кортежних
змінних у формулах можна посилатися на значення атрибута змінної (це аналогічно тому, як,
наприклад, при програмуванні на мові Сі можна послатися на значення поля структурної змінної ).
Наприклад, для того, щоб послатися на значення атрибута СПІВ_ІМЯ змінної СПІВРОБІТНИК, потрібно
вжити конструкцію СОТРУДНІК.СПІВ_ІМЯ.

Правильно побудовані формули ( WFF - Well- Formed Formula ) служать для вираження умов, що
накладаються на кортежних змінні. Основою WFF є прості порівняння ( comparison ), що представляють
собою операції порівняння скалярних значень ( значень атрибутів змінних або літерально заданих
констант ).
Наприклад, конструкція " СОТРУДНІК.СОТР_НОМ = 140 " є простим порівнянням. За визначенням,
просте порівняння є WFF, а WFF, вкладене в круглі дужки, є простим порівнянням.
Більш складні варіанти WFF будуються за допомогою логічних зв'язок NOT, AND, OR і IF... THEN.
Так, якщо form - WFF, а comp - просте порівняння, то NOT form, comp AND form, comp OR form і IF comp
THEN form є WFF.

Нарешті, допускається побудова WFF за допомогою кванторів. Якщо form - це WFF, в якій бере
участь змінна var, то конструкції EXISTS var ( form ) і FORALL var ( form ) представляють wff.

Змінні, що входять до WFF, можуть бути вільними або зв'язаними. Всі змінні, що входять в WFF, при
побудові якої не використовувалися квантори, є вільними. Фактично, це означає, що якщо для якогось
набору значень вільних кортежних змінних при обчисленні WFF отримано значення true, то ці значення
кортежних змінних можуть входити в результуюче відношення. Якщо ж ім'я змінної використано відразу
після квантора при побудові WFF виду EXISTS var ( form ) або FORALL var ( form ), то в цій WFF і у всіх
WFF, побудованих з її участю, var - зв'язана змінна. Це означає, що така змінну не видно за межами
мінімальної WFF, що зв'язала цю змінну. При обчисленні значення такої WFF використовується не одне
значення пов'язаної змінної, а вся її область визначення.

Нехай СОТР1 і СОТР2 - дві кортежних змінні, визначені на відношення СПІВРОБІТНИКИ. Тоді, WFF
EXISTS СОТР2 ( СОТР1.СОТР_ЗАРП > СОТР2.СОТР_ЗАРП ) для поточного кортежу змінної СОТР1
приймає значення true в тому і тільки в тому випадку, якщо в усьому відношенні СПІВРОБІТНИКИ
знайдеться кортеж (пов'язаний із змінною СОТР2 ) такий, що значення його атрибуту СОТР_ЗАРП
задовольняє внутрішньій умові порівняння. WFF FORALL СОТР2 ( СОТР1.СОТР_ЗАРП >
СОТР2.СОТР_ЗАРП ) для поточного кортежу змінної СОТР1 приймає значення true в тому і тільки в
тому випадку, якщо для всіх кортежів відносшення СПІВРОБІТНИКИ ( пов'язаних із змінною СОТР2 )
значення атрибута СОТР_ЗАРП задовольняють умові порівняння.
Легко бачити, що якщо змінна var є пов'язаної в WFF form, то у всіх WFF, що включають дану, може
використовуватися ім'я змінної var, яка може бути вільною або пов'язаної, але в будь-якому випадку не
має ніякого відношення до входження змінної var в WFF form. Ось приклад:

EXISTS СОТР2 ( СОТР1.СОТР_ОТД_НОМ = СОТР2.СОТР_ОТД_НОМ )

FORALL СОТР2 ( СОТР1.СОТР_ЗАРП > СОТР2.СОТР_ЗАРП )

Тут ми маємо два пов'язаних входження змінної СОТР2 з абсолютно різним змістом.
Цільові списки і вирази реляційного числення
Отже, WFF забезпечують засоби формулювання умови вибірки з відношення БД. Щоб можна було
використовувати числення для реальної роботи з БД, потрібно ще один компонент, який визначає набір
і імена стовпців результуючого відносини. Цей компонент називається цільовим списком ( target_list ).
Цільовий список будується з цільових елементів, кожен з яких може мати наступний вигляд:
var.attr, де var - ім'я вільної змінної відповідної WFF, а attr - ім'я атрибута відношення, на якому
визначена змінна var ;
var, що еквівалентно наявності підсписку var.attr1, var.attr2,..., var.attrn, де attr1, attr2,..., attrn включає
імена всіх атрибутів початкового відношення;
new_name = var.attr ; new_name - нове ім'я відповідного атрибута результуючого відношення.
Останній варіант потрібен в тих випадках, коли в WFF використовуються кілька вільних змінних з
однаковою областю визначення.
Результатом реляційного числення кортежів називається конструкція вигляду target_list WHERE wff.
Значенням виразу є відношення, тіло якого визначається WFF, а набір атрибутів і їх імена - цільовим
списком.

Реляційне числення доменів


У численні доменів областю визначення змінних є не відношення, а домени.
Стосовно бази даних СПІВРОБІТНИКИ- ВІДДІЛИ можна говорити, наприклад, про доменні змінні ІМ'Я
( значення - допустимі імена ) або НОСОТР ( значення - допустимі номери співробітників ).

Основною формальною відмінністю числення доменів від числення кортежів є наявність додаткового
набору предикатів, що дозволяють формувати так звані умови членства. Якщо R - це n - арне
відношення з атрибутами a1, a2,..., an, то умова членства має вигляд

R (ai1:vi1, ai2:vi2,..., aim:vim) (m <= n),

де vij - це або літерально задана константа, або ім'я кортежної змінної. Умова членства приймає
значення true в тому і тільки в тому випадку, якщо стосовно R існує кортеж, що містить вказані значення
зазначених атрибутів. Якщо vij - константа, то на атрибут aij задається жорстка умова, що не залежить
від поточних значень доменних змінних; якщо ж vij - ім'я доменної змінної, то умова членства може
приймати різні значення при різних значеннях цієї змінної.
У всіх інших відношеннях формули і вирази обчислення доменів виглядають схожими на формули і
вирази обчислення кортежів. Зокрема, розрізняються вільні і пов'язані входження доменних змінних.
Для прикладу сформулюємо з використанням обчислення доменів запит "Видати номери і імена
співробітників, які не отримують мінімальну заробітну плату" (вважатимемо для простоти, що ми
визначили доменні змінні, імена яких збігаються з іменами атрибутів відношення СПІВРОБІТНИКИ, а в
разі, коли потрібно кілька доменних змінних, визначених на одному домені, ми будемо додавати в кінці
імені цифри ):

СОТР_НОМ, СОТР_ИМЯ WHERE EXISTS СОТР_ЗАРП1

(СОТРУДНИКИ (СОТР_ЗАРП1) AND

СОТРУДНИКИ (СОТР_НОМ, СОТР_ИМЯ, СОТР_ЗАРП) AND


СОТР_ЗАРП > СОТР_ЗАРП1)

Реляційне числення доменів є основою більшості мов запитів, заснованих на використанні форм.
Зокрема, на цьому обчисленні базувалася мова Query-by-Example, яка була першою мовою в сімействі
мов, заснованих на табличних формах.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:30. Версія: 5. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

Функціональні залежності

Найбільш важливий з практичної точки зору нормальні форми відношень грунтуються на


фундаментальному в теорії реляційних баз даних понятті функціональної залежності. Для
подальшого викладу нам буде потрібно декілька визначень і тверджень.

Загальні визначення
Нехай задана змінна відношення r, а X і Y є довільними підмножинами заголовка r
("складеними" атрибутами).

У значенні змінної відношення r атрибут Y функціонально залежить від атрибуту X в


тому і лише в тому випадку, якщо кожному значенню X відповідає в точності одне значення
Y. В цьому випадку говорять також, що атрибут X функціонально визначає атрибут Y (X є
детермінантом (визначником) для Y, а Y є залежним від X). Позначатимемо це як r.X r.Y.

Для прикладу використовуватимемо відношення Служащие_проєкти { Слу_ном, Слу_імя,


Слу_зарп, Про_ном, Проєкт_рук}. Очевидно, що якщо Слу_ном є первинним ключем
відношення СЛУЖБОВЦІ, то для цього відношення справедлива функціональна залежність
(Functional Dependency - FD) Слу_ном слу_імя.

Насправді, для тіла відношення Служащие_проєкти в тому вигляді, в якому воно показане
на мал. 6.1, виконуються ще і наступні FD (1):

СЛУ_НОМ СЛУ_ИМЯ
СЛУ_НОМ СЛУ_ЗАРП
СЛУ_НОМ ПРО_НОМ
СЛУ_НОМ ПРОЕКТ_РУК
{СЛУ_НОМ, СЛУ_ИМЯ} СЛУ_ЗАРП
{СЛУ_НОМ, СЛУ_ИМЯ} ПРО_НОМ
{СЛУ_НОМ, СЛУ_ИМЯ} {СЛУ_ЗАРП, ПРО_НОМ}

ПРО_НОМ ПРОЕКТ_РУК и т.д.

Оскільки імена всіх службовців різні, то виконуються і такі FD (2):

СЛУ_ИМЯ СЛУ_НОМ
СЛУ_ИМЯ СЛУ_ЗАРП
СЛУ_ИМЯ ПРО_НОМ и т.д.

Більш того, для прикладу на мал. 6.1 виконується і FD (3):

СЛУ_ЗАРП ПРО_НОМ

Проте відмітимо, що природа FD групи (1) відрізняється від природи FD груп (2) і (3).
Логічно припустити, що ідентифікаційні номери службовців мають бути завжди різні, а у
кожного проекту є тільки один керівник. Тому FD групи (1) мають бути вірні для будь-якого
допустимого значення змінної відношення Служащие_проєкти і можуть розглядуватися
як інваріанти, або обмеження цілісності для цією змінною відношення.

FD групи (2) базуються на менш природному припущенні про те, що імена всіх службовців
різні. Це відповідає дійсності для прикладу з мал. 6.1, але можливо, що з часом FD групи
(2) не виконуватимуться для якого-небудь значення змінної відношення
Служащие_проєкти.

Нарешті, FD групи (3) заснована на зовсім неприродному припущенні, що ніякі двоє


службовців, що беруть участь в різних проектах, не отримують однакову зарплату. Знову ж
таки, дане припущення вірне для прикладу з мал. 6.1, але, швидше за все, це випадковий
збіг.

Надалі нас цікавитимуть тільки ті функціональні залежності, які повинні виконуватися для
всіх можливих значень змінних відношень.

Відмітимо, що якщо атрибут A відношення r є можливим ключем, то для будь-якого атрибуту


B цього відношення завжди виконується FD A B (у групі (1) до цих FD відносяться всі FD,
детермінантом яких є Слу_ном). Звернете увагу, що наявність відносно
Служащие_проєкти FD Про_ном проєкт_рук приводить до деякої надлишковості цього
відношення. Ім'я керівника проекту є характеристикою проекту, а не службовця, але в
нашому випадку міститься в тілі відношення стільки разів, скільки службовців працює над
проектом.

Отже, ми матимемо справу з FD, які виконуються для всіх можливих станів тіла відповідного
відношення і можуть розглядуватися як обмеження цілісності. Як показує (неповний) список
(1), таких залежностей може бути дуже багато. Оскільки вони трактуються як обмеження
цілісності, за їх дотриманням повинна стежити СУБД. Тому важливо уміти скоротити
набір FD до мінімуму, підтримка якого гарантує виконання всіх залежностей. Ми займемося
цим далі.

FD A B називається тривіальною, якщо A B (тобто множина атрибутів A включає


множину B або збігається з множиною B).

Очевидно, що будь-яка тривіальна FD завжди виконується. Наприклад, відносно


Служащие_проєкти завжди виконується FD { Слу_зарп, Про_ном} Слу_зарп. Окремим
випадком тривіальної FD є A A.
Оскільки тривіальні FD виконуються завжди, їх не можна трактувати як обмеження
цілісності, і тому вони не представляють інтересу з практичної точки зору. Проте в
теоретичних міркуваннях їх наявність необхідно враховувати.

Замикання множини функціональних залежностей.


Замиканням множини FD S є множина FD S+, що включає все FD, що логічно виводяться
з FD множини S.

Спершу наведемо два приклади FD, з яких виходять (або виводяться) інші FD. Знову
користуватимемося відношенням Служащие_проєкти. Для цього відношення виконується,
наприклад, FD Слу_ном { Слу_зарп, Про_ном}. З цієї FD виводяться FD Слу_ном
слу_зарп і Слу_ном про_ном.

Відносно Служащие_проєкти є також пара FD Слу_ном про_ном і Про_ном проєкт_рук. З


них виводиться FD Слу_ном проєкт_рук. Відмітимо, що FD виду Слу_ном проєкт_рук
називаються транзитивними, оскільки Проєкт_рук залежить від Слу_ном "транзитивно",
через Про_ном.

FD A C називається транзитивною, якщо існує такий атрибут B, що є функціональні


залежності A BіB C і відсутня функціональна залежність C A.

Підхід до вирішення проблеми пошуку замикання S+ множини FD S вперше запропонував


Вільям Армстронг. Ним був запропонований набір правил виведення нових FD з тих, що
існують (ці правила зазвичай називають аксіомами Армстронга, хоча справедливість правил
доводиться на основі визначення FD). Зазвичай прийнято формулювати ці правила виводу
в наступній формі. Хай A, B і C є (у загальному випадку, складеними) атрибутами
відношення r. Множина A, B і C можуть мати непорожній перетин. Скорочено позначатимемо
через AB A UNION B. Тоді:

1. якщо B A, то A B (рефлексивність);
2. якщо A B, то AC BC (поповнення);
3. якщо A BіB C, то A C (транзитивність).

Істинність першої аксіоми Армстронга виходить з того, що при B A FD A B є тривіальною.

Справедливість другої аксіоми доведемо від протилежного. Припустимо, що FD AC BC не


дотримується. Це означає, що в деякому допустимому тілі відношення знайдуться два
кортежі t1 і t2, такі, що t1 {AC} = t2 {AC} (a), але t1 {BC} t2 {BC} (b) (тут t {A} позначає
проекцію кортежу t на множина атрибутів A). По аксіомі рефлексивності з рівності (a)
виходить, що t1 {A} = t2 {A}. Оскільки є FD A B, повинна дотримуватися рівність t1 {B}
= t2 {B}. Тоді з нерівності (b) виходить, що t1 {C} t2 {C}, що противоречит наявності
тривіальної FD AC C. Отже, припущення про відсутність FD AC BC не є вірним, і
справедливість другої аксіоми доведена.

Аналогічно доведемо істинність третьої аксіоми Армстронга. Припустимо, що FD A C не


дотримується. Це означає, що в деякому допустимому тілі відношення знайдуться два
кортежі t1 і t2, такі, що t1 {A} = t2 {A}, але t1 {C} t2 {C}. Але з наявності FD A
B виходить, що t1 {B} = t2 {B}, а тому з наявності FD B C виходить, що t1 {C} = t2 {C}.
Отже, припущення про відсутність FD A C не є вірним, і справедливість третьої аксіоми
доведена.

Можна довести, що система правил виведення Армстронга повна і досконала


(sound and complete) в тому сенсі, що для даної множини FD S будь-яка FD, що потенційно
виводиться з S, може бути виведена на основі аксіом Армстронга, і застосування цих аксіом
не може привести до виведення зайвої FD. Проте Дейт по практичних міркуваннях
запропонував розширити базовий набір правил виводу ще п'ятьма правилами:

4. A A (самодетерминированность) - прямо виходить з правила (1);


5. якщо A BC, то A BіA C (декомпозиція) - з правила (1) виходить, що BC B; за
правилом (3) A B; аналогічно, з BC С і правил (3) виходить A C;
6. якщо A BіA C, то A BC (об'єднання) - з правила (2) виходить, що A AB і AB BC;
з правила (3) виходить, що A BC;
7. якщо A BіC D, то AC BD (композиція) - з правила (2) виходить, що AС BС і BC
BD; з правила (3) виходить, що AC BD;
8. якщо A BC і B D, то A BCD (накопичення) - з правила (2) виходить, що BС BCD; з
правила (3) виходить, що A BCD.

Хай задано відношення r, множина Z атрибутів цього відношення (підмножина заголовка r,


або складений атрибут r) і деяка множина FD S, що виконуються для r. Тоді замиканням Z
над S називається найбільша множина Z+ таких атрибутів Y відношення r, що FD Z
Y входить в S+.

Алгоритм обчислення Z+ дуже простий. Один з його варіантів показаний на мал. 6.2.

Алгоритм побудови замикання атрибутів над заданим множиною FD

Доведемо коректність алгоритму по індукції. На нульовому кроці Z[0]= Z, FD Z Z[I],


очевидно, належить S+ (тривіальна FD "виводиться" з будь-якої множини FD). Хай для
деякого K виконується FD ZZ[K], і хай ми знайшли в S таку FD A B, що A Z[K]. Тоді можна
представити Z[K] у вигляді AC, і, отже, виконується FD Z AC. Але за правилом (8) ми
маємо FD Z ACB, тобто FD Z (Z[K] UNION B) входить в множина S+, що перекладає нас
на наступний крок індукції.

Хай для прикладу є відношення із заголовком {A, B, C, D, E, F} і заданим множиначю FD S


= {A D, AB E, BF E, CD F, Є С}. Хай потрібно знайти {AE}+ над S. На першому
проході тіла циклу DO Z[1] рівне AE. У тілі циклу FOR EACH будуть знайдені FD A D і Є С,
і в кінці циклу Z[1] стане рівним ACDE. На другому проході тіла циклу DO при Z[2],
рівному ACDE, в тілі циклу FOR EACH буде знайдена FD CD F, і в кінці циклу Z[2] стане
рівним ACDEF. Наступний прохід тіла циклу DO не змінить Z[3], і Z+ ({AE}+) буде
рівне ACDEF.

Алгоритм побудови замикання множини атрибутів Z над заданим множиначю FD S


допомагає легко встановити, чи входить задана FD Z B в замикання S+. Очевидно, що
необхідною і достатньою умовою для цього є B Z+, тобто входження складеного атрибуту
B в замикання Z2).

Суперключем відношення r називається будь-яка підмножина K заголовка r, що


включає, щонайменше, хоч би один можливий ключ r.

Одне із следствий цього визначення полягає в тому, що підмножина K заголовка відношення


r є суперключем тоді і тільки тоді, коли для будь-якого атрибуту A (можливо, складеного)
заголовка відношення r виконується FD K A. В термінах замикання множини атрибутів K є
суперключем тоді і тільки тоді, коли K+ збігається із заголовком r.

Мінімальне покриття множини функціональних залежностей


Множина FD S2 називається покриттям множини FD S1, якщо будь-яка FD, що виводиться
з S1, виводиться також з S2.

Легко відмітити, що S2 є покриттям S1 тоді і тільки тоді, коли S1+ S2+. Дві множина FD S1
і S2 називаються еквівалентними, якщо кожна з них є покриттям іншого, тобто S1+ = S2+.

Множина FD S називається мінімальною в тому і лише у тому випадку, коли задовольняє


наступним властивостям:

1. права частина будь-якої FD з S є множиною з одного атрибуту (простим атрибутом);


2. детермінант кожної FD з S володіє властивістю мінімальності; це означає, що видалення
будь-якого атрибуту з детермінанта приводить до зміни замикання S+, тобто породженню
множини FD, не еквівалентного S;
3. видалення будь-якої FD з S приводить до зміни S+, тобто породженню множини FD, не
еквівалентного S.

Щоб продемонструвати мінімальну і немінімальну множина FD, повернемося наприклад


відношення Служащие_проєкти { Слу_ном, Слу_імя, Слу_зарп, Про_ном, Проєкт_рук} з
мал. 6.1. Якщо вважати, що єдиним можливим ключем цього відношення є атрибут Слу_ном,
то множина FD { Слу_ном слу_імя, Слу_ном слу_зарп, Слу_ном про_ном, Про_ном
проєкт_рук} буде мінімальною. Дійсно, в правих частках FD цієї множини знаходяться
множини, що складаються рівно з одного атрибуту; кожен з детермінантів теж є множиною
з одного атрибуту, видалення якого, очевидно, неприпустимо; видалення кожної FD явно
приводить до зміни замикання множини FD, оскільки інформація, що втрачається, не
виводиться за допомогою аксіом Армстронга.

З іншого боку, множина FD


1. { Слу_ном { Слу_імя, Слу_зарп}, Слу_ном про_ном, Слу_ном проєкт_рук, Про_ном
проєкт_рук},
2. { Слу_ном слу_імя { Слу_ном, Слу_імя}Слу_зарп, Слу_ном про_ном, Слу_ном
проєкт_рук, Про_номпроєкт_рук} і
3. { Слу_ном слу_ном, Слу_ном слу_імя, Слу_ном слу_зарп, Слу_ном про_ном,
Слу_ном проєкт_рук, Про_ном проєкт_рук}

не є мінімальними. Для множини (1) в правій частині першої FD присутня множина з двох
елементів. Для множини (2) видалення атрибуту Слу_імя з детермінанта другої FD не міняє
замикання множини FD. Для множини (3) видалення першої FD не приводить до зміни
замикання. Ці приклади показують, що для визначення мінімальності множини FD не завжди
потрібна явна побудова замикання даної множини.

Цікавим і важливим є той факт, що для будь-якої множини FD S існує (і навіть може бути
побудовано) еквівалентне йому мінімальна множина S-.

Приведемо загальну схему побудови S- по заданій множини FD S. По-перше,


використовуючи правило (5) (декомпозиції), ми можемо привести множину S до
еквівалентної множини FD S1, праві частки FD якого містять тільки одноелементні множини
(прості атрибути). Далі, для кожної FD з S1, детермінант D {D1, D2 ., Dn} якою містить
більш за один атрибут, намагатимемося видаляти атрибути Di, отримуючи множину FD S2.
Якщо після видалення атрибуту Di S2 еквівалентно S1, то цей атрибут віддаляється, і
пробується наступний атрибут. Назвемо S3 множина FD, отримана шляхом допустимого
видалення атрибутів зі всіх детермінантів FD множини S1. Нарешті, для кожної FD f з
множини S3 перевірятимемо еквівалентність множини S3 і S3 MINUS {f}. Якщо ці множини
еквівалентні, видалимо f з множини S3, і на закінчення отримаємо множина S4, яка
мінімальна і еквівалентно початковій множини FD S.
Хай, наприклад, є відношення r {A, B, C, D} і задана множина FD S = {A B, A BC, AB
C, AC D, B C}. За правилом декомпозиції S еквівалентно множини S1 {A B, A C, AB
C, AC D, B C}. У детерминанте FD AC D можна видалити атрибут C, оскільки за
правилом доповнення з FD A C слідує А АС; за правилом транзитивності виводиться FD A
D, тому атрибут C в детерминанте FD AC Dє надлишковим. FD AB C може бути
видалена, оскільки може бути виведена з FD A C (за правилом поповнення з
цієї FD виводиться AB BC, а за правилом декомпозиції далі виводиться AB C).
Нарешті, FD A C теж виводиться за правилом транзитивності з FD A BіB C. Таким
чином, ми отримуємо множина залежностей {A B, A D, B C}, яка є мінімальною і
еквівалентно S по побудові.

Мінімальним покриттям множини FD S називається будь-яка мінімальна множина FD S1,


еквівалентне S.

Оскільки для кожної множини FD існує еквівалентна мінімальна множина FD, у кожної
множини FD є хоч би одне мінімальне покриття, причому для його знаходження не
обов'язково знаходити замикання початкової множини.

Декомпозиція
Як вже наголошувалося, в наступній лекції ми обговорюватимемо підхід до проектування
реляційних баз даних на основі нормалізації, тобто декомпозиції (розбиття шляхом
проектування) відношення, що знаходиться в попередній нормальній формі, на два або
більш за відношення, що задовольняють вимогам наступної нормальної форми.

Вважаються за правильні такі декомпозиції відношення, які обратимы, тобто є можливість


зібрати початкове відношення з декомпозированных відношень без втрати інформації. Такі
декомпозиції називаються декомпозиціями без втрат.
Коректні і некоректні декомпозиції відношень. Теорема Хіта

На мал. 6.3 приведено дві можливі декомпозиції відношення Служащие_проєкти (для


економії місця ми скоротили і злегка змінили тіло відношення з мал. 6.1).
Аналіз мал. 6.3 показує, що в разі декомпозиції (1) ми не втратили інформацію про
службовців - про кожного з них можна дізнатися ім'я, розмір зарплати, номер виконуваного
проекту і ім'я керівника проекту. Друга декомпозиція не дає можливості отримати дані про
проект службовця, оскільки Іванов і Іваненко отримують однакову зарплату, отже, ця
декомпозиція приводить до втрати інформації. Що ж привело до того, що одна декомпозиція
є декомпозицією без втрат, а друга - ні?

Відмітимо, що при проведенні декомпозиції ми використовували операцію узяття проекції.


Кожен із відношень СЛУЖ, Слу_про і Зарп_про є проекцією початкового відношення
Служащие_проєкти. В разі декомпозиції (1) відсутність втрати інформації означає, що в
результаті природного з'єднання відношень СЛУЖ і Слу_про ми гарантовано отримаємо
відношення, заголовок і тіло якого збігаються із заголовком і тілом відношення
Служащие_проєкти. Слід зазначити, що це станеться для будь-яких допустимих (і
узгоджених) значень змінних відношень Служащие_проєкти, СЛУЖ і Слу_про, оскільки у
всіх цих змінних атрибут Слу_ном є можливим ключем. Проте якщо виконати природне
з'єднання відношень СЛУЖ і Зарп_про, то буде отримано відношення, показане на мал. 6.4.

Схема цього відношення, природно (оскільки з'єднання - природне), збігається з схемою


відношення Служащие_проєкти, але в тілі з'явилися зайві кортежі, наявність яких і
приводить до втрати початкової інформації. Інтуїтивно зрозуміло, що це відбувається тому,
що відносно Зарп_про відсутні функціональні залежності Слу_зарппро_ном і
Слу_зарппроєкт_рук, але точніше причину втрати інформації в даному випадку ми пояснимо
декілька пізніше.

Коректність же декомпозиції 1 виходить з теореми Хіта:

Теорема Хіта.

Хай задано відношення r {A, B, C} (A, B і C, в загальному випадку, є складеними атрибутами)


і виконується FD A B.

Мал. 6.4. Результат природного з'єднання відношень СЛУЖ і Зарп_про

Тоді r = (r PROJECT {A, B}) NATURAL JOIN (r PROJECT {A, C}).

Доказ. Перш за все, доведемо, що в тілі результату природного з'єднання (позначимо цей
результат через r1) містяться всі кортежі тіла відношення r. Дійсно, хай кортеж {а, b, с} r.
Тоді за визначенням операції узяття проекції {а, b} (r PROJECT {A, B}) і {а,
с} (r PROJECT {A, С}). Отже, {а, b, с} r1. Тепер доведемо, що в тілі результату
природного з'єднання немає зайвих кортежів, тобто що якщо кортеж {а, b, с} r1, то {а, b,
с} r. Якщо {а, b, с} r1, то існують {а, b} (r PROJECT {A, B}) і {а, с} (r PROJECT {A, С}).
Остання умова може виконуватися в тому і лише у тому випадку, коли існує кортеж {а, b*,
с} r. Але оскільки виконується FD A B, то b = b* і, отже {а, b, с} = {а, b*, с}. Кінець
доказу.

Для ілюстрації загального випадку застосування теореми Хіта розгледимо відношення


Служащие_отдели_проєкти { Слу_ном, Слу_отд, Про_ном} (мал. 6.5). Атрибут Слу_отд
містить номери відділів, в яких працюють службовці, а Про_ном - номери проектів, в яких
службовці беруть участь. Кожен службовець працює тільки в одному відділі, тобто
є FD Слу_ном слу_отд, але один службовець може брати участь в декількох проектах.
Відносно Служащие_отдели_проєкти атрибут Слу_ном не є можливим ключем, але, як
показано на мал. 6.5, наявності FD Слу_номслу_отд виявляється достатньо для декомпозиції
цього відношення без втрат.

Для подальшого викладу нам потрібно буде ввести ще одне визначення і зробити пару
зауважень.

Атрибут B мінімально залежить від атрибуту A, якщо виконується мінімальна зліва FD AB.

Наприклад, відносно Служащие_проєкти виконуються FD Слу_ном слу_зарп і { Слу_ном,


Слу_імя} Слу_зарп. Перша FD є мінімальною зліва, а друга - ні. Тому Слу_зарп мінімально
залежить від Слу_ном, а для { Слу_ном, Слу_імя} властивість мінімальної залежності не
виконується.
Діаграми функціональних залежностей

Далі, для ілюстрацій в наступній лекції нам стануть в нагоді діаграми FD, за допомогою яких
можна наочно представляти мінімальну множина FD. Наприклад, на мал. 6.6 приведена
діаграма мінімальної множини FD відношення Служащие_проєкти.

У лівій частці діаграми всі стрілки починаються з атрибуту Слу_ном, який є єдиним
можливим (і, отже, первинним) ключем відношення Служащие_проєкти. Звернете увагу на
відсутність стрілки від Слу_ном до Проєкт_рук. Звичайно, оскільки Слу_ном є можливим
ключем, повинна виконуватися і FD Слу_ном проєкт_рук. Але ця FD є транзитивною
(через Про_ном) і тому не входить в мінімальну множина FD. Відмітимо, що в процесі
нормалізації, до розгляду якого ми приступимо в наступній лекції, з діаграм
множини FD віддаляються стрілки, що починаються не від можливих ключів.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:30. Версія: 0. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.
Проектування реляційних баз даних
При проектуванні бази даних вирішуються дві основні проблеми:
-Яким чином відобразити об'єкти предметної області в абстрактні об'єкти моделі даних,
щоб це відображення не суперечило семантиці предметної області і було по можливості
кращим ( ефективним, зручним і т.д.)? Часто цю проблему називають проблемою логічного
проектування баз даних.
-Як забезпечити ефективність виконання запитів до бази даних, тобто яким чином, беручи
до уваги особливості конкретної СУБД, розташувати дані у зовнішній пам'яті, які додаткові
структури створити і т.д.? Цю проблему називають проблемою фізичного проектування баз
даних.
Для початку питання проектування реляційної бази даних обмежемо прийняттям рішень
про те з яких відносин повинна складатися БД і які атрибути мають бути у цих відносин.

Логічне проектування реляційних баз даних


Розглянуто класичний підхід, при якому весь процес проектування проводиться в термінах
реляційної моделі даних методом послідовних наближень до задовільного набору схем
відносин.
В процесі експлуатації реляційної бази даних відбувається модифікація даних: у
відношеннях додаються або віддаляються кортежі, в результаті певних подій змінюються
значення деяких атрибутів кортежів і тому подібне Після маніпулювання даними значення
деяких атрибутів можуть дублюватися, породжує надмірність даних, значення деяких
атрибутів можуть віддалятися, зникаючи з бази даних, хоча потреба в цих значеннях
залишається, деякі значення атрибутів не можуть бути додані, оскільки їх значення невідомі,
тобто дані в базі даних з часом стають неузгодженими і суперечливими. Потенційна
суперечність (або аномалії) при виконанні операцій маніпулювання даними в базі даних
залежить як від типа ФЗ між атрибутами, так і від угрупування цих атрибутів по відношеннях.
Розгледимо типові приклади аномалій, що виникають при виконанні операцій включення,
видалення і модифікації даних.
Приклад. Аномалії операцій над базою даних

ПОСТАЧАННЯ (Постачальник, Адреса, Товар, Кількість, Вартість)

Оновлення. Якщо Постачальник поставляє декілька видів товару, то значення атрибуту


Адреса повторюється для кожного кортежу і, отже, при зміні адреси постачальника
необхідно змінити значення цього атрибуту у всіх цих кортежах. Інакше буде порушена
цілісність даних бази даних.

Видалення. Якщо Постачальник припиняє постачання товарів на деякий час, то кортежі


зі всіма його постачаннями віддаляються. При цьому відбувається втрата реквізитів
постачальника - Адреси і Найменування.

Вставка. Якщо договір на постачання вже поміщений, а постачання ще не проведене,


то неможливо включити в дане відношення значення атрибутів Постачальник і Адреса,
оскільки немає відомостей про постачання (проблема інтерпретації нуль-значений).

Подібні аномалії в даних лише частково дають відповідь на питання, чому логічна
структура реляційної БД може бути незадовільною. Деякі проблеми надмірності даних можна
вирішити, замінивши, наприклад, початкове відношення ПОСТАЧАННЯ на два нові
відношення - відношення ПОСТАЧАЛЬНИК (Постачальник, Адреса) і відношення
ПОСТАЧАННЯ (Постачальник, Товар, Кількість, Вартість). Проте в цілому залишається ряд
питань, на які теорія реляційних баз даних не дає задовільних відповідей: quot;Как знайти
хорошу заміну для поганої схеми відношень? Як визначити, чи є вибрана заміна вигідної? Як
створити схему, що забезпечує якнайкращу продуктивність?quot;
Наприклад, для того, щоб виконати запит, що використовує дані з двох таблиць, необхідно
побудувати з'єднання цих таблиць, яке є дорогою операцією з фізичною базою даних з погляду
числа виконуваних операцій введення/виводу.
Теорія функціональних залежностей дозволяє встановити певні вимоги до схем відношень
в реляційній базі даних. Ці вимоги формулюються в термінах властивостей відношень і
називаються нормальними формами схем відношень. Кожна нормальна форма відношень
пов'язана з певним класом ФЗ, які представлені в відношеннях. Зрозуміло, що одним з
очевидних способів усунення потенційної суперечності даних в відношеннях логічної моделі
реляційної бази даних є їх розбиття на два або більш за відношення, в кожному з яких
присутній тільки одна ФЗ.
Це можливо, оскільки теорія ФЗ стверджує, що існує мінімальне покриття множинаі ФЗ
бази даних, тобто мінімальний набір ФЗ, з яких можна вивести всі останні. Кожній ФЗ з
мінімального покриття можна відвести по самостійному відношенню. Проте, по-перше, для
заданої множинаі ФЗ може існувати декілька мінімальних покриттів (вибір серед можливих
альтернатив), і, по-друге, для практики поважно мати наочний спосіб побудови мінімального
покриття.
Процес усунення потенційної суперечності і надмірності даних в відношеннях реляційної
бази даних називається нормалізацією початкових схем відношень. Нормалізація відношень
полягає у виконанні декомпозиції або синтезу відношень, призначенні ключів відношень
відповідно до певних правил, що гарантують цілісність відношень бази даних. Вимога
мінімальності числа відношень, тобто побудови мінімального покриття ФЗ зазвичай є
опциональным. На мінімальному покритті, як правило, не може бути досягнута висока
продуктивність обробки запитів.
Чому нормалізація схем відношень важлива для проектування реляційних баз даних?
Численні випробування показали, що нормалізація схем відношень дає якнайкращий
результат при моделюванні наочної області з використанням реляційної моделі даних; при
цьому не вводиться великого числа обмежень, не спотворюються дані. Таким чином,
нормалізація відношень є методом видалення з відношення ФЗ, які приводять до аномалій
модифікації даних. Іншими словами, нормалізація відношень допомагає проектувати
реляційну базу даних, яка не містить надлишкових даних і гарантує їх цілісність.
Мову нормальних форм констатує наявність або відсутність певних ФЗ в відношеннях
реляційної бази даних і указує на рівень надмірності і надійності даних в нормалізованих
відношеннях. Методи нормалізації відношень грунтуються на застосуванні поняття ФЗ і
способів маніпулювання ними. При виконанні реляційних операцій над стосунками в базі
даних кожен тип ФЗ може породжувати певного типа аномалій, який порушуватиме цілісність
даних в базі даних. Нормальна форма (НФ) є обмеженням на схему бази даних, що вводиться
з метою усунення певних небажаних властивостей при виконанні реляційних операцій.

Нормальні форми
Вихідною точкою є представлення предметної області у вигляді одного або декількох
відношень, і на кожному кроці проектування проводиться деякий набір схем відношень, що
володіють кращими властивостями.
Процес проектування являє собою процес нормалізації схем відносин, причому кожна
наступна нормальна форма володіє кращим набором властивостей, ніж попередня.

Кожній нормальній формі відповідає певний набір обмежень, і відношення знаходиться в


деякій нормальній формі, якщо задовольняють цьому набору обмежень.
У теорії реляційних баз даних звичайно виділяється наступна послідовність нормальних
форм:
-перша нормальна форма ( 1NF ) ;
-другий нормальна форма ( 2NF ) ;
-третя нормальна форма ( 3NF ) ;
-нормальна форма Бойса-Кодда ( BCNF ) ;
-четверта нормальна форма ( 4NF ) ;
-п'ята нормальна форма, або нормальна форма проекції-з'єднання ( 5NF або PJ / NF ).

Основні властивості нормальних форм:


-кожна наступна нормальна форма в деякому розумінні краще попередньої ;
-при переході до наступної нормальній формі властивості попередніх нормальних
властивостей зберігаються.

В основі процесу проектування лежить метод нормалізації, декомпозиція відношень, що


знаходиться в попередній нормальній формі, в два або більше відношення, що задовольняють
вимогам наступної нормальної форми.
Прикладом набору обмежень є обмеження першої нормальної форми-значення всіх
атрибутів відносини атомарний. Оскільки вимога першої нормальної форми є базовою
вимогою класичної реляційної моделі даних, ми будемо вважати, що вихідний набір відносин
вже відповідає цій вимозі.

Найбільш важливі на практиці нормальні форми відношень грунтуються на


фундаментальному в теорії реляційних баз даних понятті функціональної залежності.

Визначення 1. функціональна залежність


У відношенні R атрибут Y функціонально залежить від атрибуту X ( X і Y можуть бути
складеними ) в тому і тільки в тому випадку, якщо кожному значенню X відповідає в точності
одне значення Y: R.X ( r ) R.Y

Визначення 2. Повна функціональна залежність


Функціональна залежність R.X ( r ) R.Y називається повною, якщо атрибут Y не залежить
функціонально від будь-якої точної підмножини X.

Визначення 3. Транзитивная функціональна залежність


Функціональна залежність R.X-> R.Y називається транзитивною, якщо існує такий атрибут
Z, що є функціональна залежність R.X-> R.Z і R.Z-> R.Y і відсутня функціональна залежність
R.Z-> R.X ( При відсутності останньої вимоги ми мали б " тривіальні " транзитивні залежності
в будь-якому відношенні, що володіють декількома ключами. )

Визначення 4. неключових атрибут


Неключовим атрибутом називається будь-який атрибут відношення, що не входить до
складу первинного ключа.

Визначення 5. Взаємно незалежні атрибути


Два або більше атрибута взаємно незалежні, якщо жоден з цих атрибутів не є
функціонально залежним від інших.

Перша нормальна форма


Відношення знаходиться в першій нормальній формі (1НФ), якщо всі атрибути відношення
є простими (вимога атомарності атрибутів в реляційній моделі), тобто не мають компонентів.
Іншими словами, домен атрибуту повинен складатися з неподільних значень і не може
включати множини значень з більш елементарних доменів. Так, наприклад, дата не може
вважатися за простий атрибут. В більшості випадків виконати цю вимогу досить просто.
Кожен простий атрибут повинен мати свою колонку в таблиці. Проте це часто приводить до
дублювання даних у відношенні.

Типовим прикладом неатомарності атрибуту є так звані групи, що повторюються,


представляють масив значень атрибуту.
Таким чином, процедура приведення відношення до 1НФ полягає у винесенні неатомарних
атрибутів в окреме підлегле відношення, тобто у виконанні двох проекцій.
Друга нормальна форма
Розглянемо наступний приклад схеми відношення:

СПІВРОБІТНИКИ-ВІДДІЛИ-ПРОЕКТИ
( СПІВР_НОМЕР, СОТР_ЗАРП, ОТД_НОМЕР, ПРО_НОМЕР, СПІВР_ЗАВДАН )
Первинний ключ: СПІВР_НОМЕР, ПРО_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР-> СОТР_ЗАРП
СПІВР_НОМЕР-> ОТД_НОМЕР
ОТД_НОМЕР-> СОТР_ЗАРП
СПІВР_НОМЕР, ПРО_НОМЕР-> СПІВР_ЗАВДАН

Як видно, хоча первинним ключем є складовою атрибут СПІВР_НОМЕР, ПРО_НОМЕР,


атрибути СОТР_ЗАРП і ОТД_НОМЕР функціонально залежать від частини первинного
ключа, атрибута СПІВР_НОМЕР. У результаті ми не зможемо вставити у відношення
СПІВРОБІТНИКИ-ВІДДІЛИ-ПРОЕКТИ кортеж, що описує співробітника, який ще не
виконує ніякого проекту (первинний ключ не може містити невизначене значення ). При
видаленні кортежу ми не тільки руйнуємо зв'язок даного співробітника з даним проектом, але
втрачаємо інформацію про те, що він працює в деякому відділі. При перекладі співробітника
в інший відділ ми будемо змушені модифікувати всі кортежі, що описують цього
співробітника, або отримаємо неузгоджений результат. Такі неприємні явища називаються
аномаліями схеми відношення. Вони усуваються шляхом нормалізації.

Друга нормальна форма: Відношення R знаходиться в другій нормальній формі ( 2NF ) в


тому і тільки в тому випадку, коли перебуває в 1NF, і кожен неключових атрибут повністю
залежить від первинного ключа.

Можна провести наступну декомпозицію відношення СПІВРОБІТНИКИ-ВІДДІЛИ-


ПРОЕКТИ в два відношення СПІВРОБІТНИКИ-ВІДДІЛИ і СПІВРОБІТНИКИ-ПРОЕКТИ:

СПІВРОБІТНИКИ-ВІДДІЛИ ( СПІВР_НОМЕР, СОТР_ЗАРП, ОТД_НОМЕР )


Первинний ключ: СПІВР_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР-> СОТР_ЗАРП
СПІВР_НОМЕР-> ОТД_НОМЕР
ОТД_НОМЕР-> СОТР_ЗАРП

СПІВРОБІТНИКИ-ПРОЕКТИ ( СПІВР_НОМЕР, ПРО_НОМЕР, СПІВР_ЗАВДАН )


Первинний ключ: СПІВР_НОМЕР, ПРО_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР, ПРО_НОМЕР-> CОТР_ЗАДАН

Кожне з цих двох відношень знаходиться в 2NF, і в них усунені зазначені вище аномалії
(легко перевірити, що всі зазначені операції виконуються без проблем).

Якщо допустити наявність декількох ключів, то визначення можна записати як


Відношення R знаходиться в другій нормальній формі ( 2NF ) в тому і тільки в тому
випадку, коли воно знаходиться в 1NF, і кожен неключових атрибут повністю залежить від
кожного ключа R.
Тут і далі ми не будемо наводити приклади для відношень з декількома ключами. Вони
занадто громіздкі і відносяться до ситуацій, що рідко зустрічається на практиці.
Таким чином, процедура приведення відношення до 2НФ полягає у виконанні двох
проекцій: проекції без атрибутів часткової ФЗ і проекції на частку складеного ключа і ті
атрибути, які від нього залежать.

Третя нормальна форма


Розглянемо ще раз відношення СПІВРОБІТНИКИ-ВІДДІЛИ, що знаходиться в 2NF.
Зауважимо, що функціональна залежність СПІВР_НОМЕР-> СОТР_ЗАРП є транзитивною ;
вона є наслідком функціональних залежностей СПІВР_НОМЕР-> ОТД_НОМЕР і
ОТД_НОМЕР-> СОТР_ЗАРП. Іншими словами, заробітна плата співробітника насправді є
характеристикою не співробітник, а відділу, в якому він працює (це не дуже природне
припущення, але достатня для прикладу).

У результаті ми не зможемо занести в базу даних інформацію, що характеризує заробітну


плату відділу, до тих пір, поки в цьому відділі не з'явиться хоча б один співробітник
(первинний ключ не може містити невизначене значення ).
При видаленні кортежу, що описує останнього співробітника даного відділу, ми втратимо
інформації про заробітну плату відділу.
Щоб узгодженим чином змінити заробітну плату відділу, ми будемо змушені попередньо
знайти всі кортежі, що описують співробітників цього відділу.
Тобто у відношеннях СПІВРОБІТНИКИ-ВІДДІЛИ існують аномалії. Їх можна усунути
шляхом подальшої нормалізації.

Третя нормальна форма. Відношення R знаходиться в третій нормальній формі ( 3NF ) в


тому і тільки в тому випадку, якщо перебуває в 2NF і кожен неключовий атрибут
нетранзитивно залежить від первинного ключа.

Можна зробити декомпозицію відношення СПІВРОБІТНИКИ-ВІДДІЛИ в два відношення


СПІВРОБІТНИКИ і ВІДДІЛИ:

СПІВРОБІТНИКИ ( СПІВР_НОМЕР, ОТД_НОМЕР )


Первинний ключ:
СПІВР_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР-> ОТД_НОМЕР

ВІДДІЛИ ( ОТД_НОМЕР, СОТР_ЗАРП )


Первинний ключ:ОТД_НОМЕР
Функціональні залежності:
ОТД_НОМЕР-> СОТР_ЗАРП

Кожне з цих двох відношень знаходиться в 3NF і немає зазначених аномалій.

Якщо відмовитися від того обмеження, що відношення володіє єдиним ключем, то


визначення 3NF прийме таку форму:
Відношення R знаходиться в третій нормальній формі ( 3NF ) в тому і тільки в тому випадку,
якщо перебуває в 2NF, і кожен неключовий атрибут не є транзитивно залежним від будь-якого
ключа R.
Таким чином, процедура приведення відношення до 3НФ полягає у виконанні двох
проекцій: проекції по правій частці транзитивної ФЗ і проекції по лівій частці транзитивної
ФЗ.

На практиці третя нормальна форма схем відносин достатня в більшості випадків, і


приведенням до третьої нормальної форми процес проектування реляційної бази даних
зазвичай закінчується. Однак іноді корисно продовжити процес нормалізації.

Нормальна форма Бойса-Кодда


Розглянемо наступний приклад схеми відношення:
СПІВРОБІТНИКИ-ПРОЕКТИ
( СПІВР_НОМЕР, СОТР_ІМЯ, ПРО_НОМЕР, СПІВР_ЗАВДАН )
Можливі ключі:
СПІВР_НОМЕР, ПРО_НОМЕР
СОТР_ІМЯ, ПРО_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР-> CОТР_ІМЯ
СПІВР_НОМЕР-> ПРО_НОМЕР
СОТР_ІМЯ-> CОТР_НОМЕР
СОТР_ІМЯ-> ПРО_НОМЕР
СПІВР_НОМЕР, ПРО_НОМЕР-> CОТР_ЗАДАН
СОТР_ІМЯ, ПРО_НОМЕР-> CОТР_ЗАДАН

У цьому прикладі ми припускаємо, що особистість співробітника повністю визначається як


його номером, так і ім'ям ( це знову не надто життєве припущення, але достатня для прикладу).

Відповідно відношення СПІВРОБІТНИКИ-ПРОЕКТИ знаходиться в 3NF. Однак той факт,


що є функціональні залежності атрибутів відношення від атрибута, що є частиною первинного
ключа, призводить до аномалій.
Наприклад, для того, щоб змінити ім'я співробітника з даним номером узгодженим чином,
нам буде потрібно модифікувати всі кортежі, що включають його номер.

Детермінант-будь-який атрибут, від якого повністю функціонально залежить деякий


інший атрибут.

Нормальна форма Бойса – Кодда. Відношення R знаходиться в нормальній формі Бойса-


Кодда ( BCNF ) в тому і тільки в тому випадку, якщо кожен детермінант є можливим ключем.

Очевидно, що ця вимога не виконана для відношення СПІВРОБІТНИКИ-ПРОЕКТИ.


Можна провести його декомпозицію до відношення СПІВРОБІТНИКИ і СПІВРОБІТНИКИ-
ПРОЕКТИ:

СПІВРОБІТНИКИ ( СПІВР_НОМЕР, СОТР_ІМЯ )


Можливі ключі:
СПІВР_НОМЕР
СОТР_ІМЯ
Функціональні залежності:
СПІВР_НОМЕР-> CОТР_ІМЯ
СОТР_ІМЯ-> СПІВР_НОМЕР

СПІВРОБІТНИКИ-ПРОЕКТИ ( СПІВР_НОМЕР, ПРО_НОМЕР, СПІВР_ЗАВДАН )


Можливий ключ:
СПІВР_НОМЕР, ПРО_НОМЕР
Функціональні залежності:
СПІВР_НОМЕР, ПРО_НОМЕР-> CОТР_ЗАДАН

Можлива альтернативна декомпозиція, якщо вибрати за основу СОТР_ІМЯ. В обох


випадках одержані відношення СПІВРОБІТНИКИ і СПІВРОБІТНИКИ-ПРОЕКТИ
знаходяться в BCNF, і їм не властиві відмічені аномалії.

Четверта нормальна форма


Розглянемо приклад такої схеми відносини:
ПРОЕКТИ ( ПРО_НОМЕР, ПРО_СОТР, ПРО_ЗАДАН )

Відношення ПРОЕКТИ містить номери проектів, для кожного проекту список


співробітників, які можуть виконувати проект, і список завдань, що передбачаються проектом.
Співробітники можуть брати участь у кількох проектах, і різні проекти можуть включати
однакові завдання.
Кожен кортеж відношення пов'язує деякий проект із співробітником, бере участі у цьому
проекті, і завданням, яке співробітник виконує в рамках даного проекту (ми припускаємо, що
будь-який співробітник, що бере участь у проекті, виконує всі завдання, передбачені цим
проектом ).
Унаслідок сформульованих вище умов єдиним можливим ключем відношення є складовий
атрибут ПРО_НОМЕР, ПРО_СОТР, ПРО_ЗАДАН, і немає ніяких інших детермінантів. Отже,
відношення ПРОЕКТИ знаходиться в BCNF.
Але при цьому воно володіє недоліками: якщо, наприклад, деякий співробітник
приєднується до даного проекту, необхідно вставити у відношення ПРОЕКТИ стільки
кортежів, скільки завдань у ньому передбачено.

Багатозначні залежності. У відношенні R (A, B, C) існує багатозначна залежність RA->->


RB в тому і тільки в тому випадку, якщо множина значень B, що відповідає парі значень A і
C, залежить тільки від A і не залежить від С.

Відносно ПРОЕКТИ існують наступні дві багатозначні залежності:


ПРО_НОМЕР->-> ПРО_СОТР
ПРО_НОМЕР->-> ПРО_ЗАДАН

Легко показати, що в загальному випадку у відношенні R (A, B, C) існує багатозначна


залежність RA->-> RB в тому і тільки в тому випадку, коли існує багатозначна залежність RA-
>-> RC

Подальша нормалізація відношень, подібних ПРОЕКТИ, грунтується на наступній теоремі:

теорема Фейджин. Відношення R (A, B, C) можна спроектувати без втрат у відношення R1


( A, B ) і R2 ( A, C) в тому і тільки в тому випадку, коли існує MVD A->-> B | C.

Під проектуванням без втрат розуміється такий спосіб декомпозиції відношення, при якому
початкове відношення повністю і без надмірності відновлюється шляхом природного
з'єднання отриманих відношень.

Четверта нормальна форма. Відношення R знаходиться в четвертій нормальній формі (


4NF ) в тому і тільки в тому випадку, якщо у випадку існування багатозначної залежності A-
>-> B всі інші атрибути R функціонально залежать від A.

У нашому прикладі можна зробити декомпозицію відношення ПРОЕКТИ на два


відношення ПРОЕКТИ-СПІВРОБІТНИКИ і ПРОЕКТИ-ЗАВДАННЯ:
ПРОЕКТИ-СПІВРОБІТНИКИ ( ПРО_НОМЕР, ПРО_СОТР )
ПРОЕКТИ-ЗАВДАННЯ ( ПРО_НОМЕР, ПРО_ЗАДАН )

Обидва ці відношення знаходяться в 4NF і вільні від зазначених аномалій.

П'ята нормальна форма


До цього моменту при нормалізації проводилася декомпозиція одного відношення в два.
Іноді це зробити не вдається, але можлива декомпозиція в більше число відношень, кожне з
яких володіє кращими властивостями.

Розглянемо, наприклад, відношення

СПІВРОБІТНИКИ-ВІДДІЛИ-ПРОЕКТИ (СПІВР_НОМЕР, ОТД_НОМЕР, ПРО_НОМЕР)

Припустимо, що один і той же працівник може працювати в декількох відділах і працювати


в кожному відділі над кількома проектами.
Первинним ключем цього відношення є повна сукупність його атрибутів, відсутні
функціональні та багатозначні залежності.
Тому відношення знаходиться в 4NF. Однак у ньому можуть існувати аномалії, які можна
усунути шляхом декомпозиції в три відношення.

залежність з'єднання. Відношення R ( X, Y,..., Z ) задовольняє залежності з'єднання * ( X,


Y,..., Z) в тому і тільки в тому випадку, коли R відновлюється без втрат шляхом з'єднання своїх
проекцій на X, Y,..., Z.

П'ята нормальна форма. Відношення R знаходиться в п'ятій нормальній формі ( нормальній


формі проекції-з'єднання-PJ / NF ) в тому і тільки в тому випадку, коли будь-яка залежність
з'єднання в R випливає з існування деякого можливого ключа в R.

Введемо наступні імена складових атрибутів:


СО = { СПІВР_НОМЕР, ОТД_НОМЕР }
СП = { СПІВР_НОМЕР, ПРО_НОМЕР }
ОП = { ОТД_НОМЕР, ПРО_НОМЕР }

Припустимо, що відносно СПІВРОБІТНИКИ-ВІДДІЛИ-ПРОЕКТИ існує залежність


з'єднання:
* (СО, СП, ОП )

Наприклад наступне відношення та його проекції:


X Y Z X Y X Z Y Z
1 1 2 1 1 1 2 1 2
1 2 1 1 2 1 1 2 1
2 1 1 2 1 2 1 1 1
1 1 1 R1=R[X,Y] R2=R[X,Z] R3=R[Y,Z]

Як легко відмітити, відношення не відновлюється ні по одному з попарних з'єднань, або .


Дійсно, з'єднання має вигляд:
X Y Z R1 JOIN R2
1 1 2
1 1 1
1 2 2
1 2 1
2 1 1

Cірим кольором виділений зайвий кортеж, відсутній у відношенні . Аналогічно (через


міркування симетрії) і інші попарні з'єднання не відновлюють відношення .
Таким чином, процедура приведення відношення, що містить багатозначні ФЗ, до 5НФ
полягає в побудові зв'язуючого відношення, що дозволяє виключити появу в з'єднаннях
помилкових кортежів.

Отож легко показати, що при вставках і видаленнях кортежів можуть виникнути проблеми.
Їх можна усунути шляхом декомпозиції початкового відношення в три нових відносини:
СПІВРОБІТНИКИ-ВІДДІЛИ ( СПІВР_НОМЕР, ОТД_НОМЕР )

СПІВРОБІТНИКИ-ПРОЕКТИ ( СПІВР_НОМЕР, ПРО_НОМЕР )

ВІДДІЛИ-ПРОЕКТИ ( ОТД_НОМЕР, ПРО_НОМЕР )

П'ята нормальна форма-це остання нормальна форма, яку можна отримати шляхом
декомпозиції. Її умови досить нетривіальні, і на практиці 5NF не використовується.
Зауважимо, що залежність з'єднання є узагальненням як багатозначної залежності, так і
функціональної залежності.

Отже, кожна нормальна форма обмежує певного типа ФЗ і усуває аномалії обробки даних.
Нормальні форми характеризуються наступними властивостями:
1НФ - всі атрибути відношення прості;
2НФ - відношення знаходиться в 1НФ і не містить часткових ФЗ;
3НФ - відношення знаходиться в 2НФ і не містить транзитивних ФЗ від ключа;
НФБК - відношення знаходиться в 3НФ і не містить ФЗ ключів від неключових атрибутів;
4НФ, застосовується за наявності більш ніж одній багатозначною ФЗ - відношення
знаходиться в НФБК або 3НФ і не містить незалежних багатозначних ФЗ;
5НФ - відношення знаходиться в 4НФ і не містить ФЗ по з'єднанню.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:30. Версія: 2. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

Семантичне моделювання даних. ER-діаграми


Широке поширення реляційних СУБД та їх використання в найрізноманітніших
застосунках показує , що реляційна модель даних достатня для моделювання предметних
областей. Однак проектування реляційної бази даних в термінах відношень на основі
механізму нормалізації часто представляє собою дуже складний і незручний для
проектувальника процес .

При цьому виявляються обмеженість реляційної моделі даних в таких аспектах:


- Модель не надає достатніх засобів для представлення змісту даних. Семантика реальної
предметної області повинна незалежним від моделі способом представлятися в голові
проектувальника . Зокрема , це відноситься до згадуваної нами проблеми представлення
обмежень цілісності .
- Для багатьох застосунків важко моделювати предметну область на основі плоских
таблиць . У ряді випадків на початковій стадії дуже складно описати предметну область у
вигляді однієї (навіть ненормалізованої) таблиці .
- Хоча весь процес проектування відбувається на основі врахування залежностей ,
реляційна модель не має засобів для представлення цих залежностей .
- Незважаючи на те , що процес проектування починається з виділення деяких істотних для
програми об'єктів предметної області ( " сутностей " ) і виявлення зв'язків між цими
сутностями , реляційна модель даних не пропонує ніякого апарату для розділення сутностей і
зв'язків.

Семантичні моделі даних


Потреби проектувальників баз даних в більш зручних і потужних засобах моделювання
предметної області призвели до виникнення семантичних моделей даних.
При тому , що будь-яка розвинена семантична модель даних , як і реляційна модель ,
включає структурну , маніпуляційну і цілісну частини , головним призначенням семантичних
моделей є забезпечення можливості вираження семантики даних.

Перш, ніж ми коротко розглянемо особливості однієї з поширених семантичних моделей ,


зупинимося на їх можливих застосуваннях .
Найбільш часто на практиці семантичне моделювання використовується на першій стадії
проектування бази даних. При цьому в термінах семантичної моделі проводиться
концептуальна схема бази даних , яка потім перетвориться в реляційну схему. Цей процес
виконується під управлінням методик , в яких досить чітко обумовлені всі етапи такого
перетворення.
Менш часто реалізується автоматизована компіляція концептуальної схеми в реляційну .
При цьому відомі два підходи : на основі явного представлення концептуальної схеми як
вихідної інформації для компілятора і побудови інтегрованих систем проектування з
автоматизованим створенням концептуальної схеми на основі інтерв'ю з експертами
предметної області.
І в тому , і в іншому випадку в результаті виробляється реляційна схема бази даних в третій
нормальній формі.
Третя можливість - це робота з базою даних у семантичній моделі, тобто СУБД , що
базується на семантичних моделях даних. При цьому, знову розглядаються два варіанти :
забезпечення інтерфейсу користувача на основі семантичної моделі даних з автоматичним
відображенням конструкцій в реляційну модель даних (це завдання приблизно такого ж рівня
складності , як автоматична компіляція концептуальної схеми бази даних в реляційну схему)
і пряма реалізація СУБД , що базується на деякій семантичній моделі даних. Найбільш близько
до другого підходу знаходяться сучасні об'єктно-орієнтовані СУБД , моделі даних яких за
багатьма параметрами близькі до семантичних моделей.

Основні поняття моделі Entity - Relationship


Розглянемо одну з найбільш популярних семантичних моделей даних - модель " Сутність-
Зв'язок" (часто її називають коротко ER- моделлю) .

На використанні різновидів ER-моделі засновано більшість сучасних підходів до


проектування баз даних . Модель була запропонована Ченом ( Chen) в 1976 р. Моделювання
предметної області базується на використанні графічних діаграм, що включають невелике
число різнорідних компонентів. У зв'язку з наочністю подання концептуальних схем баз даних
ER- моделі одержали широке поширення в CASE системах, що підтримують автоматизоване
проектування реляційних баз даних. Серед різновидів ER -моделей одна з найбільш
розвинених застосовується в системі CASE фірми ORACLE . Її ми і розглянемо. Більш точно
, ми зосередимося на структурній частині цієї моделі.

Основними поняттями ER- моделі є сутність , зв'язок і атрибут.


Сутність - це реальний або уявний об'єкт , інформація про який повинна зберігатися і бути
доступна. У діаграмах ER- моделі сутність представляється у вигляді прямокутника, що
містить ім'я сутності. При цьому ім'я сутності - це ім'я типу , а не деякого конкретного
екземпляра цього типу. Для більшої виразності і кращого розуміння ім'я суті може
супроводжуватися прикладами конкретних об'єктів цього типу.

Нижче зображена сутність АЕРОПОРТ з зразковими об'єктами Шереметьєво і Хітроу :

Кожен екземпляр сутності повинен відрізнити від будь-якого іншого екземпляра тієї ж
сутності (це вимога в деякому роді аналогічно вимозі відсутності кортежів - дублікатів в
реляційних таблицях ) .

Зв'язок - це графічно зображена асоціація, що встановлюється між двома сутностями. Ця


асоціація завжди є бінарною і може існувати між двома різними сутностями або між тією
самою сутністю ( рекурсивна зв'язок ) .
У будь-якому зв'язку виділяються два кінці , на кожному з яких вказується ім'я кінця зв'язку
, ступінь кінця зв'язку (скільки екземплярів даної суті пов'язується ) , обов'язковість зв'язку
(тобто чи обов’язково екземпляр даної суті повинен брати участь у зв'язку).
Зв'язок представляється у вигляді лінії, що зв'язує дві сутності або веде від суті до неї ж
самої. При цьому в місці " стикування" зв'язку з сутністю використовуються триточковий вхід
в прямокутник сутності , якщо для цієї сутності в зв'язку можуть використовуватися багато (
many ) екземплярів сутності, і одноточковий вхід , якщо у зв'язку може брати участь тільки
один екземпляр сутності (one).
Обов'язковий кінець зв'язку зображається суцільною лінією , а необов'язковий -
переривчастою лінією.

Як і сутність , зв'язок - це типове поняття , всі примірники обох пар пов'язують сутностей
підкоряються правилам зв'язування .

У зображеному нижче прикладі зв'язок між сутностями КВИТОК і ПАСАЖИР пов'язує


квитки і пасажирів. При тому кінець сутності з ім'ям " для " дозволяє пов'язувати з одним
пасажиром більше одного квитка , причому кожен квиток повинен бути пов'язаний з яким-
небудь пасажиром. Кінець сутності з ім'ям "має" означає , що кожен квиток може належати
тільки одному пасажиру , причому пасажир не зобов'язаний мати хоча б один квиток.

Усне трактуванням зображеної діаграми є наступна:


- Кожен КВИТОК призначений для одного і тільки одного ПАСАЖИРА;
- Кожен ПАСАЖИР може мати один або більше КВИТКІВ.

На наступному прикладі зображена рекурсивна зв'язок, зв'язує сутність ЛЮДИНА з нею ж


самою. Кінець зв'язку з ім'ям "син" визначає той факт, що в одного батька може бути більше
ніж один син. Кінець зв'язку з ім'ям "батько" означає, що не у кожної людини можуть бути
сини.

Усне трактуванням зображеної діаграми є наступна:


- Кожен ЧОЛОВІК є сином одного і тільки одного ЧОЛОВІКА;
- Кожен ЧОЛОВІК може бути батьком для одного або більше ЛЮДЕЙ ( " ЧОЛОВІКІВ" )
.
Атрибутом сутності є будь деталь , яка служить для уточнення , ідентифікації ,
класифікації , числової характеристики або вираження стану сутності. Імена атрибутів
заносяться в прямокутник , що зображує сутність , під ім'ям сутності і зображуються малими
літерами.
Унікальним ідентифікатором сутності є атрибут , комбінація атрибутів , комбінація
зв'язків або комбінація зв'язків і атрибутів , унікально відрізняє будь-який екземпляр сутності
від інших екземплярів сутності того ж типу.

Ступінь(degree) типу відношення стосується кількості екземплярів у межах кожного типу


сутності, які можуть бути пов'язані з даним типом відношення. Кожен з кінців відношення має
мінімальний і максимальний ступінь.
Максимальний ступінь називається потужністю (cardinality), а мінімальна ступінь
опціональністю (optionality).

Використовуються три символи, що показують ступінь.


- коло означає нуль,
- лінія означає одне
- “вороняча лапка” означає багато.

Потужність визначає тип зв’язку між сутностями. Так на рисунку схеми є прикладами
зв’язків:
(b) один-до-багатьох 1:N (one-to-many),
(с) один-до-одного 1:1 (one-to-one),
(d) M:N (many-to-many)

Опціональність визначає обов’язковість (mandatory) зв’язку між сутностями.


(b) – кожна сутність А повинна бути пов’язана хоча б одним B;
кожна сутність B необов’язково повинна бути пов’язана з A

Приклад: покупець і рахунок.


Нормальні форми ER- схем
Як і в реляційних схемах баз даних , в ER- схемах вводиться поняття нормальних форм ,
причому їх зміст дуже близько відповідає змісту реляційних нормальних форм .
Формулювання нормальних форм ER- схем роблять більш зрозумілим сенс нормалізації
реляційних схем .
У першій нормальній формі ER- схеми усуваються повторювані атрибути або групи
атрибутів , тобто виконується виявлення неявних сутностей , " замаскований " під атрибути .
У другій нормальній формі усуваються атрибути, які залежать тільки від частини
унікального ідентифікатора. Ця частина унікального ідентифікатора визначає окрему сутність.
У третій нормальній формі усуваються атрибути , які залежать від атрибутів , що не
входять в унікальний ідентифікатор. Ці атрибути є основою окремої сутності.

Розширені можливості ER- моделі


Ми зупинилися тільки на самих основних і найбільш очевидних поняттях ER- моделі даних
. До числа більш складних елементів моделі відносяться наступні:

- Підтипи і супертіпи сутностей. Як у мовах програмування з розвиненими типовими


системами (наприклад , в мовах об'єктно -орієнтованого програмування ) , запроваджується
можливість наслідування типу сутності , виходячи з одного або декількох супертіпів . Цікаві
нюанси пов'язані з необхідністю графічного зображення цього механізму.
- Зв'язки " many - to - many " . Іноді буває необхідно зв'язувати сутності таким чином , що з
обох кінців зв'язку можуть бути присутні кілька екземплярів сутності (наприклад , всі члени
кооперативу спільно володіють майном кооперативу) . Для цього вводиться різновид зв'язку
"багато- до- багатьох " .
- Уточнюємо ступеня зв'язку . Іноді буває корисно визначити можливу кількість
примірників сутності, беруть участь у даній зв'язку (наприклад , службовцю дозволяється
брати участь не більше , ніж у трьох проектах одночасно). Для вираження цього семантичного
обмеження дозволяється вказувати на кінці зв'язку її максимальну або обов'язкову ступінь .
- Каскадні видалення екземплярів сутностей. Деякі зв'язки бувають настільки сильними
(як правило зв'язки " один-до-багатьох") , що при видаленні опорного екземпляра сутності
(відповідного кінця зв'язку "один") потрібно видалити і всі екземпляри сутності , відповідні
кінці зв'язку "багато" . Таку вимогу " каскадного видалення " можна сформулювати при
визначенні сутності.
- Домени . Як і у випадку реляційної моделі даних буває корисна можливість визначення
потенційно допустимої множини значень атрибута сутності ( домену ) .

Ці та інші більш складні елементи моделі даних " Сутність-Зв'язок " роблять її істотно
потужнішою , але одночасно дещо ускладнюють її використання . Зазвичай , при реальному
використанні ER -діаграм для проектування баз даних необхідно ознайомитися з усіма
можливостями.

Елементів - підтип сутності


Сутність може бути розщеплена на два або більше взаємовиключаючі підтипу , кожен з
яких включає загальні атрибути та / або зв'язки . Ці загальні атрибути та / або зв'язки явно
визначаються один раз на більш високому рівні. У підтипах можуть визначатися власні
атрибути та / або зв'язку . В принципі підтипізація може тривати на більш низьких рівнях , але
практика показує , що в більшості випадків виявляється достатньо двох -трьох рівнів .

Сутність , на основі якої визначаються підтипи , називається супертип .


Підтипи повинні утворювати повну множину , тобто будь-який екземпляр супертипу
повинен ставитися до деякого підтипу . Іноді для повноти доводиться визначати додатковий
підтип ІНШІ .

Приклад: супертипа ЛІТАЛЬНИЙ АПАРАТ

Як це читати ?
Від супертипа : літальний апарат , який може бути АЕРОПЛАН , ВЕРТОЛІТ , ЦЕПЕЛІН
або ІНШИЙ .
Від підтипу: ВЕРТОЛІТ , який відноситься до типу літальних апаратів.
Від підтипу , який є одночасно супертип : АЕРОПЛАН , який відноситься до
типу ЛІТАЛЬНИХ АПАРАТІВ і повинен бути ПЛАНЕР або МОТОРНИЙ ЛІТАК.

Отримання реляційної схеми з ER- схеми

Крок 1 .
Кожна проста сутність перетворюється в таблицю .
Проста сутність - сутність , яка не є підтипом і не має підтипів .
Ім'я суті стає ім'ям таблиці.

Крок 2 .
Кожен атрибут стає можливим стовпцем з тим же ім'ям, може вибиратися більш точний
формат .
Стовпці , що відповідають необов'язковим атрибутам , можуть містити невизначені
значення; стовпці, що відповідають обов'язковим атрибутами , - не можуть.

Крок 3 .
Компоненти унікального ідентифікатора сутності перетворюються на первинний ключ
таблиці.
Якщо є кілька можливих унікальних ідентифікаторів , вибирається найбільш
використовуваний .
Якщо до складу унікального ідентифікатора входять зв'язку , до числа стовпців первинного
ключа додається копія унікального ідентифікатора сутності , що знаходиться на другому кінці
зв'язку (цей процес може тривати рекурсивно ) . Для іменування цих стовпців
використовуються імена решти зв'язків та / або імена сутностей.

Крок 4 .
Зв'язки багато-до-одного (і один- до-одного ) стають зовнішніми ключами. Тобто робиться
копія унікального ідентифікатора з кінця зв'язку "один" , і відповідні стовпці складають
зовнішній ключ.
Необов'язкові зв'язки відповідають стовпцях, що допускають невизначені значення ;
обов'язкові зв'язку - стовпцях, що не допускає невизначені значення.

Крок 5 .
Індекси створюються для первинного ключа (унікальний індекс) , зовнішніх ключів і тих
атрибутів , на яких передбачається в основному базувати запити.

Крок 6 .
Якщо в концептуальній схемі були присутні підтипи , то можливі два способи :
- всі підтипи в одній таблиці ( а )
- для кожного підтипу - окрема таблиця (б)
При застосуванні способу ( а ) таблиця створюється для найбільш загального супертипу , а
для підтипів можуть створюватися представлення. У таблицю додається принаймні один
стовпець, що містить код ТИПУ, він стає частиною первинного ключа.
При використанні методу (б) для кожного підтипу першого рівня ( для більш нижніх -
представлень) супертип відтворюється за допомогою представлення UNION ( з усіх таблиць
підтипів вибираються загальні стовпці - стовпці супертипу ) .
Все в одній таблиці Таблиця - на підтип
Переваги
Всі зберігається разом Більш ясні правила підтипів
Легкий доступ до супертипа і підтипів Програми працюють тільки з
Потрібно менше таблиць потрібними таблицями
Недоліки
Занадто загальне рішення
Занадто багато таблиць
Потрібна додаткова логіка роботи з різними
Стовпці в представленням UNION
наборами стовпців і різними обмеженнями
Потенційна втрата продуктивності при
Потенційне вузьке місце (у зв'язку з блокуваннями)
роботі через UNION
Стовпці підтипів повинні бути необов'язковими
Над супертипом неможливі
У деяких СУБД для зберігання невизначених значень
модифікації
потрібна додаткова пам'ять

Крок 7 .
Є два способи роботи за наявності виключачих зв'язків:
- загальний домен ( а )
- явні зовнішні ключі (б)
Якщо зовнішні ключі всі в одному домені , тобто мають загальний формат (спосіб ( а )) , то
створюються два стовпці : ідентифікатор зв'язку та ідентифікатор сутності. Стовпець
ідентифікатора зв'язку використовується для розрізнення зв'язків , що покриваються дугою
виключення . Стовпець ідентифікатора суті використовується для зберігання значень
унікального ідентифікатора суті на далекому кінці відповідної зв'язку .
Якщо результуючі зовнішні ключі не відносяться до одного домену , то для кожного зв'язку,
що покривається дугою виключення , створюються явні стовпці зовнішніх ключів; всі ці
стовпці можуть містити невизначені значення .

Варіант 1 (поганий)

Варіант 2 (краще, якщо підтипи дійсно існують)

Варіант 3 (підходить, якщо існує осмислений супертип D).

Востаннє редаговано: Четвер, 11 лютого 2016, 13:31. Версія: 1. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

ER-діаграми
Широке розповсюдження реляційних СУБД і їх використання в найрізноманітніших
застосуваннях показує, що реляційна модель даних достатня для моделювання
різноманітних наочних областей. Проте проектування реляційної бази даних в термінах
стосунків на основі того, що короткий розглянуті нами в двох попередніх лекціях механізму
нормалізації часто є дуже складним і незручним для проектувальника процесом.

Семантична модель Entity-Relationship (Суть-Зв'язок)


У цій лекції ми коротко розглянемо деякі риси однієї з найбільш популярних семантичних
моделей даних - модель «Суть-Зв'язок» (часто її називають коротко ER-моделью від Entity-
Relationship).

Тут слід зробити два зауваження, що стосуються, головним чином, термінології. Обидва
терміни relation і relationship можуть бути перекладені на російську мову як відношення.
Тому в російськомовній літературі ER-модель інколи називають моделлю суть-відношення,
а інколи і реляційною семантичною моделлю. Напевно, в цьому немає нічого страшного,
якщо говорити про ER-модели у відриві від тематики проектування реляційних баз даних.

Але якщо потрібно одночасно використовувати терміни ER-модели і реляційної моделі


даних, то, безумовно, потрібно застосовувати для термінів relation і relationship різні
російські еквіваленти. За цими термінами коштують вельми різні поняття. У реляційній
моделі відношення (relation) - це єдина родова структура даних. За допомогою цього ж
механізму представляється «зв'язана» суть (пригадаєте, наприклад, про зовнішні ключі).
Як ми побачимо трохи пізніше, в ER-модели для представлення схеми бази даних
використовуються два рівноправні поняття - суть і зв'язок. Зв'язки в ER-модели грають
роль, відмінну від тієї, яку грають відношення в реляційній моделі даних.

Крім того, в російськомовну термінологію увійшла і чиста транслітерація


терміну relation саме в сенсі відношення. Ми говоримо, наприклад, про реляційну модель
даних, реляційну алгебру і т. д., розуміючи модель даних, засновану на стосунках, алгебру
стосунків і тому подібне Із цього приводу, принаймні, в контексті баз даних, розумно
остаточно зарезервувати терміни relation і відношення для позначення понять реляційної
моделі даних, а для терміну relationship використовувати інший допустимий
російськомовний еквівалент - зв'язок.

На використанні різних варіантів ER-модели заснована більшість сучасних підходів до


проектування баз даних (головним чином, реляційних). Модель була запропонована
Пітером Ченом (Peter Chen) в 1976 р. Моделювання наочної області базується на
використанні графічних діаграм, що включають невелике число різнорідних компонентів.
Простота і наочність представлення концептуальних схем баз даних в ER-модели привели
до її широкого розповсюдження в CASE-системах, що підтримують автоматизоване
проектування реляційних баз даних. Серед безлічі різновидів ER-моделей одна з найбільш
популярних і розвинених застосовувалася в системі CASE компанії Oracle. Ми обговоримо
деякий спрощений варіант цієї моделі. Якщо говорити точніше, зосередимося на її
структурній і цілісній частках.

Основні поняття ER-модели


Основними поняттями ER-модели є суть, зв'язок і атрибут.
Суть - це реальний або такий, що представляється об'єкт, інформація про яке повинна
зберігатися і бути доступной. У діаграмах ER-модели суть представляється у вигляді
прямокутника, що містить ім'я суті. При цьому ім'я суті - це ім'я типа, а не деякого
конкретного екземпляра цього типа. Для більшої виразності і кращого розуміння ім'я суті
може супроводитися прикладами конкретних екземплярів цього типа.

Мал. 9.1. Приклад типа суті


На мал. 9.1 змальована суть АЕРОПОРТ із зразковими екземплярами «Шереметьево» і
«Хитроу». Ця примітивна діаграма проте несе важливу інформацію. По-перше, вона показує,
що в базі даних міститимуться однотипні структури даних (екземпляри суті), що описують
аеропорти. По-друге, оскільки в житті існує декілька точок зору на аеропорти (наприклад,
точка зору пілота, точка зору пасажира, точка зору адміністратора) і цим точкам зору
відповідають різні структури даних, то наведені приклади аеропортів дозволяють декілька
звузити допустимий набір точок зору. У нашому випадку наведені приклади міжнародних
аеропортів, так що, швидше за все, є точка зору пасажира або пілота міжнародних
авіарейсів.
При визначенні типу суті необхідно гарантувати, що кожен екземпляр суті може бути
відмінний від будь-якого іншого екземпляра тієї ж суті. Це вимога в деякому роді аналогічно
вимозі відсутності кортежів-дублікатів в реляційних таблицях.

Зв'язок - це графічно змальовувана асоціація, що встановлюється між двома типами суті.


Як і суть, зв'язок - це типове поняття, всі екземпляри обох зв'язуваних типів суті
підкоряються встановлюваним правилам скріплення. Тому правильніше говорити про тип
зв'язку, що встановлюється між типами суті, і про екземпляри типа зв'язку, що
встановлюються між екземплярами типа сущности. У обговорюваному тут варіанті ER-
модели ця асоціація завжди є бінарною і може існувати між двома різними типами суті або
між типом суті і ним же самим (рекурсивний зв'язок). У будь-якому зв'язку виділяються два
кінці (відповідно до існуючої пари зв'язуваної суті), на кожному з яких указуються ім'я кінця
зв'язку, ступінь кінця зв'язку (скільки екземплярів даного типа суті має бути присутніми в
кожному екземплярі даного типа зв'язку), обов'язковість зв'язку (тобто чи будь-який
екземпляр даного типа суті повинен брати участь в деякому екземплярі даного типа зв'язку)
.7)

Зв'язок представляється у вигляді ненапрямленої лінії, що сполучає дві суті або ведучу від
суті до неї ж самої. При цьому в місці «стиковки» зв'язку з суттю використовуються:
* триточковий вхід в прямокутник суті, якщо для цієї суті в зв'язку можуть (або повинні)
використовуватися багато (many) екземплярів суті;
* одноточечний вхід, якщо в зв'язку може (або повинен) брати участь тільки один
екземпляр суті.

Обов'язковий кінець зв'язку змальовується суцільною лінією, а необов'язковий -


переривистою лінією.

Зв'язок між суттю КВИТОК і ПАСАЖИР, показана на мал. 9.2, зв'язує квитки і пасажирів.
Кінець зв'язку з ім'ям «для» дозволяє пов'язувати з одним пасажиром більш як один квиток,
причому кожен квиток має бути пов'язаний з яким-небудь пасажиром. Кінець зв'язку з ім'ям
«має» показує, що кожен квиток може належати тільки одному пасажирові, причому
пасажир не зобов'язаний мати хоч би одного квитка.

Мал. 9.2. Приклад типа зв'язку

Лаконічне усне трактування змальованої діаграми полягає в наступному:


* кожен КВИТОК призначений для одного і лише одного ПАСАЖИРА;
* кожен ПАСАЖИР може мати один або більш за КВИТКИ.

На наступному прикладі (мал. 9.3) змальований рекурсивний зв'язок, що зв'язує


суть ЧОЛОВІК з нею ж самою. Кінець зв'язку з ім'ям «син» визначає той факт, що декілька
людей можуть бути синами одного отця. Кінець зв'язку з ім'ям «отець» означає, що не у
кожного чоловіка мають бути сини.

Мал. 9.3. Приклад рекурсивного типа зв'язку

Лаконічне усне трактування змальованої діаграми полягає в наступному:


* кожен ЧОЛОВІК є сином одного і лише одного ЧОЛОВІКА;
* кожен ЧОЛОВІК може бути отцем одного або більш за ЧОЛОВІКІВ.

Атрибутом суті є будь-яка деталь, яка служить для уточнення, ідентифікації, класифікації,
числової характеристики або вираження стану суті. Імена атрибутів заносяться в
прямокутник, що змальовує суть, під ім'ям суті і змальовуються малими буквами, можливо,
з прикладами. Приклад типа суті ЧОЛОВІК з вказаними атрибутами показаний на мал. 9.4.
З технічної точки зору атрибути типа суті в ER-модели схожі на атрибути відношення в
реляційній моделі даних. І у тому, і в іншому випадках введення іменованих атрибутів
вводить деяку типову структуру даних, ім'я якої збігається з ім'ям типа суті в разі ER-модели
або з ім'ям змінної відношення в разі реляційної моделі.
Цій типовій структурі повинні слідувати всі екземпляри типа суті або всі кортежі відношення.
Але є і важлива відмінність. Нагадаємо, що в реляційній моделі даних атрибут визначається
як впорядкована пара <имя_атрибута, имя_домена> (або <имя_атрибута,
имя_базового_типа_данных>, якщо поняття домена не підтримується). Заголовок
відношення, визначуваний як безліч таких пар, є повним аналогом структурного типа даних
в мовах програмування.

Мал. 9.4. Приклад типа суті з атрибутами

Крім того, нагадаємо, що при визначенні атрибуту відношення допускається використання


імен атрибутів, співпадаючих з іменами своїх доменів (це два разных простору імен, і
наявність однакових імен у атрибутів і доменів не викликає колізій). Тому при визначенні
атрибутів типів суті можна так підбирати їх імена, що вони надалі підказуватимуть, які
домени у цих атрибутів маються на увазі. Розумінню передбачуваної суті доменів сприяє і
можливість вказівки прикладів значень атрибутів. Наприклад, на мал. 9.4 є атрибут рік
народження, як зразкове значення якого вказане «1976». Це підказує, що в реляційній
схемі при визначенні відповідного атрибуту найбільш природним базовим типом даних буде
темпоральний тип «ДАТА», значення якого задають дату з точністю до року.
Унікальні ідентифікатори типів суті

Але при проектуванні бази даних мало того, щоб проектувальник переконався в
правильному виборі типів суті, що гарантує відмінність екземплярів кожного типа суті.
Необхідно повідомити систему автоматизації проектування БД, яким чином розрізнятимуться
ці екземпляри, тобто повідомити, як конструюються унікальні ідентифікатори екземплярів
кожного типа суті. У ER-модели у екземпляра типа суті не може бути імені, що призначається
користувачем, або зовнішнього унікального ідентифікатора, що призначається системою.
Екземпляр типа суті може ідентифікуватися тільки своїми індивідуальними
характеристиками, а вони представляються значеннями атрибутів і екземплярами типів
зв'язку, що зв'язують даний екземпляр типа суті з екземплярами інших типів суті або цього
ж типа суті. Тому унікальним ідентифікатором суті може бути атрибут, комбінація атрибутів,
зв'язок, комбінація зв'язків або комбінація зв'язків і атрибутів, що унікально відрізняє будь-
який екземпляр суті від інших екземплярів суті того ж типа.

Наведемо декілька прикладів. На мал. 9.5 показаний тип суті КНИГА, придатний для
використання в базі даних книжкового складу. При виданні будь-якої книги в будь-якому
видавництві (окрім піратських, якими ми для простоти нехтуватимемо) їй привласнюється
унікальний номер - ISBN. Зрозуміло, що значення атрибуту isbn унікально
ідентифікуватиме партію книг на складі. Крім того, звичайно, як унікальний ідентифікатор
годиться і комбінація атрибутів <автор, назва, номер видання, видавництво, рік видання>.
Мал. 9.5. Тип суті, екземпляри якого ідентифікуються атрибутами

На мал. 9.6 діаграма включає два зв'язаних типи суті. У кожної дорослої людини є один і
лише один паспорт (ми знову не беремо в розрахунок особливий випадок, коли у однієї
людини є декілька паспортів), і кожен паспорт може належати тільки одній дорослій людині
(деякі вже готові паспорти можуть бути ще нікому не видані). Тоді зв'язок людини з його
паспортом (кінець зв'язку МАЄ) унікально ідентифікує дорослу людину, т. е., грубо кажучи,
паспорт визначає дорослу людину. Оскільки можуть існувати паспорти, ще не видані якій-
небудь людині, цей зв'язок не є унікальним ідентифікатором суті ПАСПОРТ.

Мал. 9.6. Тип суті, екземпляри якого ідентифікуються зв'язком

На мал. 9.7 діаграма включає трьох зв'язаних типів суті. Професори володіють знаннями в
декількох учбових дисциплінах. Викладання кожної дисципліни доступне декільком
професорам. Іншими словами, між суттю ПРОФЕСОР і ДИСЦИПЛІНА визначений зв'язок
«багато до багатьом». Кожен професор може готувати курси по будь-якій доступній йому
дисципліні. Кожній дисципліні може бути присвячене декілька учбових курсів. Але кожен
професор може готувати тільки один курс по будь-якій доступній йому дисципліні, і кожен
курс може бути присвячений тільки одній дисципліні. Тим самим, кожен екземпляр типа
суті КУРС унікально ідентифікується екземпляром суті ПРОФЕСОР і екземпляром
суті ДИСЦИПЛІНА, тобто парою зв'язків з іменами кінців ГОТУЄТЬСЯ і ПРИСВЯЧЕНИЙ на
стороні суті КУРС. Відмітимо, що суть ПРОФЕСОР і ДИСЦИПЛІНА зв'язками не
ідентифікуються.

Мал. 9.7. Тип суті, екземпляри якого ідентифікуються комбінацією зв'язків

Нормальні форми ER-диаграмм


Як і в разі схем реляційних баз даних, для ER-діаграм вводиться поняття нормальних форм,
причому їх сенс дуже близько відповідає сенсу нормальних форм стосунків. Відмітимо, що
визначення нормальних форм ER-диаграмм роблять зрозумілішим сенс нормалізації схем
стосунків. Ми приведемо тільки дуже короткі і неформальні визначення трьох перших
нормальних форм. Звичайно, можна було б ввести подальші нормальні форми ER-диаграмм,
аналогічні нормальній формі Бойса-кодда, 4NF і 5NF, але на практиці до такої нормалізації
зазвичай не удаються.

У першій нормальній формі ER-диаграммы усуваються атрибути, що містять множинні


значення, тобто проводиться виявлення неявної суті, «замаскованої» під атрибути.

На мал. 9.9 (a) показана діаграма, в якій типа суті АЕРОПОРТ не задовольняє вимозі першої
нормальної форми. Тут для нас неістотні атрибути суті АВІАРЕМОНТНЕ ПІДПРИЄМСТВО, але
суть АЕРОДРОМ окрім атрибутів, що відображають власні характеристики аеродромів
(довжина злітно-посадочної смуги, число ангарів і так далі) містить атрибут, множинне
значення якого характеризує літаки, приписані до цього аеродрому. Очевидно, що літаки
потребують ремонту, тобто повинні обслуговуватися деяким авіаремонтним підприємством.
Але оскільки літаки є часткою суті АЕРОДРОМ, єдиним способом фіксації цього факту на
діаграмі є проведення зв'язку «багато до багатьом» між типами суті АЕРОДРОМ і
АВІАРЕМОНТНЕ ПІДПРИЄМСТВО. Таким чином виражається те міркування, що для ремонту
різних літаків, приписаних до одного аеродрому, можуть використовуватися різні
транспортні підприємства, і кожне транспортне підприємство може обслуговувати декілька
аеродромів.

Мал. 9.9. Приклад приведення ER-диаграммы до першої нормальної форми

Чим погана ця ситуація? Перш за все, тим, що ховається той факт, що авіаремонтне
підприємство ремонтує літаки, а не аеродроми. Наш же зв'язок насправді означає, що будь-
який аеродром з групи аеродромів обслуговується будь-яким авіаремонтним підприємством
з групи таких підприємств. Проблема полягає саме в тому, що значенням атрибуту «літаки»
є безліч екземплярів типа суті ЛІТАК, і цей тип суті сам володіє атрибутами і зв'язками.

Ситуацію виправляє ER-диаграмма, показана на мал. 9.9 (b). Тут ми виділили типа
суті ЛІТАК. Зв'язок між суттю АЕРОДРОМ і ЛІТАК показує, що до одного аеродрому
приписується декілька літаків. Зв'язок між суттю ЛІТАК і АВІАРЕМОНТНЕ ПІДПРИЄМСТВО
означає, що кожен літак з групи літаків (групу літаків можуть складати, наприклад, всі
літаки одного типа) обслуговується будь-яким транспортним підприємством з деякої групи
таких підприємств. ER-диаграмма на мал. 9.9 (b) знаходиться в першій нормальній формі і,
як ми бачимо, краще відображує реальну ситуацію.
Друга нормальна форма ER-диаграммы

У другій нормальній формі усуваються атрибути, залежні тільки від частки унікального
ідентифікатора. Ця частка унікального ідентифікатора визначає окрему суть.

На мал. 9.10 (a) показана діаграма, на якій тип суті ЕЛЕМЕНТ РОЗКЛАДУ не задовольняє
вимогам другої нормальної форми. На цій діаграмі у суті ЕЛЕМЕНТ РОЗКЛАДУ є наступні
властивості. Елементи розкладу призначені для збереження даних про рейси літаків, що
вилітають протягом дня. Деякими важливими характеристиками рейса є номер рейса,
аеропорт вильоту, аеропорт призначення, дата і час вильоту, бортовий номер літака, тип
літака. Якщо говорити про російські авіаційні компанії, то (1) у кожного рейса є заздалегідь
приписаний йому номер (унікальний серед всіх інших наявних номерів рейсів), (2) не всі
рейси здійснюються щодня, тому характеристикою конкретного рейса є дата і час його
здійснення, (3) бортовий номер літака визначається парою <номер рейса, дата-час
вильоту>. Є зв'язок «багато до одного» між суттю ЕЛЕМЕНТ РОЗКЛАДУ і МІСТО. Екземпляри
типа суті МІСТО характеризують місто, в яке прибуває даний рейс.
Мал. 9.10. Приклад приведення ER-диаграммы до другої нормальної форми

Унікальним ідентифікатором типа суті ЕЛЕМЕНТ РОЗКЛАДУ є пара атрибутів <номер рейса,
дата-час вильоту>. Якщо повернутися до термінів функціональних залежностей, то між
атрибутами цієї суті є наступні FD:
* { номер рейса, дата-час вильоту}бортовий номер літака;
* номер рейса аеропорт вильоту;
* номер рейса аеропорт призначення;
* бортовий номер літака тип літака.

Крім того, очевидно, що кожен екземпляр зв'язку з суттю МІСТО також визначається
значенням атрибуту номер рейса. У наявності порушення вимоги другої нормальної форми.
Ми отримуємо не лише надлишкове зберігання значень атрибутів аеропорт вильоту і
аеропорт призначення в кожному екземплярі типа суті ЕЛЕМЕНТ РОЗКЛАДУ з одним і тим
же значенням номера рейса. Спотворюється і затьмарюється сенс зв'язку з суттю МІСТО.
Можна подумати, що в різні дні один і той же рейс прибуває в різні міста.

На мал. 9.10 (b) показаний нормалізований варіант діаграми, в якому вся суть знаходиться
в другій нормальній формі. Тепер є три типи суті: РЕЙС з атрибутами номер рейса, аеропорт
вильоту, аеропорт призначення, ЕЛЕМЕНТ РОЗКЛАДУ з атрибутами дата-час вильоту,
бортовий номер літака, тип літака і МІСТО. Унікальним ідентифікатором суті РЕЙС є
атрибут номер рейса, унікальний ідентифікатор ЕЛЕМЕНТ РОЗКЛАДУ складається з
атрибуту дата вильоту і кінця зв'язку КОЛИ, НА ЧОМУ. Ми бачимо, що ні в одному типові
суті більше немає атрибутів, визначуваних часткою унікального ідентифікатора. Властивості
другої нормальної форми задовольняються, і ми маємо якіснішу діаграму.
Третя нормальна форма ER-диаграммы

У третій нормальній формі усуваються атрибути, залежні від атрибутів, що не входять в


унікальний ідентифікатор. Ці атрибути є основою окремої суті.

Поглянемо ще раз на типа суті ЕЛЕМЕНТ РОЗКЛАДУ на мал. 9.10 (b). Звичайно, щодня
кожен рейс виконується тільки одним літаком, тому бортовий номер літака повністю
залежить від унікального ідентифікатора. Але бортовий номер є унікальною
характеристикою кожного літака, і від цієї характеристики залежить решта всіх
характеристик, зокрема тип літака. Іншими словами, між унікальним ідентифікатором і
іншими атрибутами типа суті ЕЛЕМЕНТ РОЗКЛАДУ є наступні функціональні залежності:

{ КОЛИ, НА ЧОМУ, дата-час вильоту}бортовой номер літака


{ КОЛИ, НА ЧОМУ, дата-час вильоту}тип літака
бортовий номер самолетатип літака
Як видно, є транзитивна FD { КОЛИ, НА ЧОМУ, дата вильоту} тип літака, і наявність
цієї FD викликає порушення вимоги третьої нормальної форми. Насправді, тип
суті ЕЛЕМЕНТ РОЗКЛАДУ на мал. 9.10 (b) включає (принаймні, частково) тип суті ЛІТАК.
Це викликає надмірність зберігання і затуманює сенс діаграми. На мал. 9.11 показаний
нормалізований варіант діаграми, в якому вся суть знаходиться в третій нормальній формі.

Складніші елементи ER-модели

До цих пір ми розглядували тільки найосновніші і найбільш очевидні поняття ER-моделі


даних. До деяких складніших елементів моделі відносяться наступні.
* Підтипи і супертипи суті. Подібно до того як це робиться в мовах програмування з
розвиненими типовими системами (наприклад, в мовах об'єктно-орієнтованого
програмування), в ER-модели підтримується можливість визначення нового типа суті
шляхом спадкоємства деякого супертипа суті. Механізм спадкоємства в ER-модели володіє
декількома особливостями: зокрема, цікаві нюанси пов'язані з необхідністю графічного
зображення цього механізму (див. нижчий).
* Уточнювані ступені зв'язку. Інколи буває корисно визначити можливу кількість
екземплярів суті, що беруть участь в даному зв'язку (наприклад, ввести обмеження,
пов'язане з тим, що службовцеві дозволяється брати участь не більше ніж в трьох проектах
одночасно). Для вираження цього семантичного обмеження дозволяється указувати на кінці
зв'язку її максимально допустимий або обов'язковий ступінь.
* Зв'язки, що взаємно виключають. Для заданого типу суті можна визначити такий набір
типів зв'язку з іншими типами суті, що для кожного екземпляра заданого типу суті може
(якщо набір зв'язків є необов'язковим) або повинен (якщо набір зв'язків обов'язковий)
існувати екземпляр тільки одного зв'язку з цього набору.
* Каскадні видалення екземплярів суті. Деякі зв'язки бувають настільки сильними
(звичайно, в разі зв'язку «один до багатьом»), що при видаленні опорного екземпляра суті
(відповідного кінцю зв'язку «один») потрібно видалити і всі екземпляри суть, відповідна
кінцю зв'язку «багато». Відповідну вимогу каскадного видалення можна специфікувати при
визначенні зв'язку.
* Домени. Як і в разі реляційної моделі даних, в деяких випадках корисна можливість
визначення потенційно допустимої безлічі значень атрибуту суті (домена).

Ці і інші ускладнені елементи моделі даних «Суть-Зв'язок» роблять її потужнішою, але


одночасно дещо утрудняють її використання. Звичайно, при реальному застосуванні ER-
диаграмм для проектування баз даних необхідно ознайомитися зі всіма можливостями.
Нижче ми докладніше обговоримо два елементи з числа згаданих вище - супертипи і підтипи
суті, а також наведемо приклад суті із зв'язками, що взаємно виключають.

Спадкоємство типів суті і типів зв'язку


Суть може бути розщеплена на два або більше число підтипів, що взаємно виключають,
кожен з яких включає загальні атрибути і/або зв'язки. Ці загальні атрибути і/або зв'язки
явно визначаються один раз на більш високому рівні. У підтипах можуть визначатися власні
атрибути і/або зв'язки. В принципі, підтипізація може продовжуватися на нижчих рівнях,
але досвід використання ER-модели при проектуванні баз даних показує, що в більшості
випадків виявляється достатньо двох-трьох рівнів.

Якщо у типу суті A є підтипи B1, B2..., Bn, то:


* (a) будь-який екземпляр типа суті B1, B2..., Bn є екземпляром типа суті A
(включення);
* (b) якщо а є екземпляром типа суті A, то а є екземпляром деякого підтипу суті Bi (i =
1, 2 ..., n) (відсутність власних екземплярів у супертипа суті);
* (c) ні для яких підтипів Bi і Bj (i, j = 1, 2 ..., n) не існує екземпляра, типом якого
одночасно є типи суті Bi і Bj (роз'єднаність підтипів).

Тип суті, на основі якого визначаються підтипи, називається супертипом. Як ми бачили


вище, підтипи повинні утворювати повну множину, тобто будь-який екземпляр супертипа
повинен відноситися до деякого підтипу. Інколи для забезпечення такої повноти доводиться
визначати додатковий підтип ІНШІ.

Приклад супертипа ЛІТАЛЬНИЙ АПАРАТ і його підтипів АЕРОПЛАН, ВЕРТОЛІТ, ПТІЦЕЛЕТ та


ІНШІ показаний на мал. 9.12. У підтипу АЕРОПЛАН є два власні підтипи - ПЛАНЕР і
МОТОРНИЙ ЛІТАК. Для супертипа суті ЛІТАЛЬНИЙ АПАРАТ визначений атрибут максимальна
дальність польоту і необов'язковий зв'язок «багато до багатьом» з типом суті ПІЛОТ. Ці
атрибут і зв'язок успадковується всіма підтипами цього супертипа суті. У безпосереднього
підтипу суті АЕРОПЛАН визначається один додатковий атрибут, так що в сукупності у
даного типа суті є два атрибути максимальна дальність польоту і розмах крил і один
успадкований зв'язок з типом суті ПІЛОТ. У підтипу другого рівня МОТОРНИЙ
ЛІТАК супертипа АЕРОПЛАН визначається один додатковий атрибут потужність мотора і
один додатковий (обов'язкова) зв'язок з типом суті АЕРОДРОМ. Тим самим, у типа
суті МОТОРНИЙ ЛІТАК є три атрибути: два успадкованих - максимальна дальність польоту
і розмах крил і один власний - потужність мотора, а також два зв'язки: одна успадкована -
з типом суті ПІЛОТ і одна власна - з типом суті АЕРОДРОМ. І так далі. Зрозуміло, що для
типу суті ІНШІ, швидше за все, безглуздо визначати власні атрибути і зв'язки, так що
властивості цього типа збігатимуться з властивостями його супертипа.

Мал. 9.12. Супертипи і підтипи суті

Як же слід розуміти діаграму, представлену на мал. 9.12? Якщо починати від супертипа, то
діаграма змальовує ЛІТАЛЬНИЙ АПАРАТ, який має бути АЕРОПЛАНОМ, ВЕРТОЛЬОТОМ,
ПТІЦЕЛЕТОМ або ІНШИМ ЛІТАЛЬНИМ АПАРАТОМ. Якщо починати від підтипу (наприклад,
суть ВЕРТОЛІТ), то це ВЕРТОЛІТ, який відноситься до типу ЛІТАЛЬНОГО АПАРАТУ. Якщо
починати від підтипу, який є одночасно супертипом, то це АЕРОПЛАН, який відноситься до
типу ЛІТАЛЬНОГО АПАРАТУ і має бути ПЛАНЕРОМ або МОТОРНИМ ЛІТАКОМ.

У механізмі спадкоємства ER-модели допускається наявність двох або більше за розбиття


суті на підтипи. Наприклад, тип суті ОСОБА може бути розщеплений на підтипи за
професійною ознакою (ПРОГРАМІСТ, ДОЯРКА і т. д.), а може бути розщеплений і за статевою
ознакою (ЧОЛОВІК, ЖІНКА).
Зв'язки, що взаємно виключають
Приклад діаграми з двох суті із зв'язками, що взаємно виключають, показаний на мал.
9.13(a). Літак може знаходитися в робочому стані, і тоді у нього є один і лише один пілот.
Або ж літак може знаходитися на ремонті на одному з декількох можливих авіаремонтних
підприємств (кожне підприємство може проводити ремонт декількох літаків).

Мал. 9.13. Приклад ER-диаграммы із зв'язками, що взаємно виключають

В даному випадку для кожного екземпляра типа суті ЛІТАК повинен існувати екземпляр
одного з вказаних зв'язків. Для екземплярів типу суті ЛІТАК, відповідних справним літакам,
повинен існувати екземпляр зв'язку «один до одного» з екземпляром типу суті ПІЛОТ, а
екземпляри, відповідні несправним літакам, повинні брати участь в екземплярі типу зв'язку
«багато до одного» з екземпляром типу суті АВІАРЕМОНТНЕ ПІДПРИЄМСТВО.

Як показано на мал. 9.13(b), діаграма із зв'язками, що взаємно виключають, з мал. 9.13(a)


може бути перетворена до діаграми без зв'язків, що взаємно виключають, шляхом введення
підтипів. Оскільки будь-який літак може бути або справним, або несправним, можна
коректним чином ввести два підтипи супертипу ЛІТАК - СПРАВНИЙ ЛІТАК і НЕСПРАВНИЙ
ЛІТАК. На рівні супертипа суті зв'язку не визначаються. Для підтипу СПРАВНИЙ ЛІТАК
визначається обов'язковий зв'язок «один до одного» з типом суті ПІЛОТ, а для
підтипу НЕСПРАВНИЙ ЛІТАК визначається обов'язковий зв'язок «багато до одного» з типом
суті АВІАРЕМОНТНЕ ПІДПРИЄМСТВО.

Відмітимо, що для того, щоб описана схема реалізації механізму зв'язків, що взаємно
виключають, на основі механізму спадкоємства дійсно могла працювати, в засобах
маніпулювання даними ER-модели має бути передбачена можливість динамічної зміни типа
суті у екземпляра. Конкретно для нашого випадку потрібна можливість зміни типа
екземпляра суті СПРАВНИЙ ЛІТАК на типа суті НЕСПРАВНИЙ ЛІТАК, і навпаки (справний
літак може ламатися, несправний літак - приводитися в робочий стан). Звичайно, при такій
зміні типа повинен змінюватися і екземпляр зв'язку. Відмітимо, що в даному випадку ми
маємо справу з обмеженою динамічною зміною типа екземпляра, оскільки і справні, і
несправні літаки є екземплярами супертипа ЛІТАК.
Отримання реляційної схеми з ER-диаграммы
Опишемо типову багатокрокову процедуру перетворення ER-диаграммы в реляційну
(точніше, в SQL-ориентированную) схему бази даних.

Базові прийоми
Кожен простий тип суті перетворюється на таблицю. (Простим типом суті називається тип
суті, що не є підтипом і що не має підтипів.) Ім'я суті стає ім'ям таблиці. Екземплярам типу
суті відповідають рядки відповідної таблиці.

Кожен атрибут стає стовпцем таблиці з тим же ім'ям; може вибиратися точніший формат
представлення даних. Стовпці, відповідні необов'язковим атрибутам, можуть містити
невизначені значення; стовпці, відповідні обов'язковим атрибутам, - не можуть.
Компоненти унікального ідентифікатора суті перетворюються на первинний ключ таблиці.
Якщо є декілька можливих унікальних ідентифікаторів, для первинного ключа вибирається
найбільш характерний. Якщо до складу унікального ідентифікатора входять зв'язки, до
стовпців первинного ключа додається копія унікального ідентифікатора суті, що
знаходиться на іншому кінці зв'язку (цей процес може продовжуватися рекурсивно, і в
загальному випадку може привести до зациклення). Для іменування цих стовпців
використовуються імена кінців зв'язків і/або імена парних типів суті.

Зв'язки «багато до одного» (і «один до одного») стає зовнішніми ключами, тобто


утворюється копія унікального ідентифікатора суті на кінці зв'язку «один», і відповідні
стовпці складають зовнішній ключ таблиці, відповідної типові суті на кінці зв'язку «багато».
Необов'язкові зв'язки відповідають стовпцям зовнішнього ключа, що допускають наявність
невизначених значень; обов'язкові зв'язки - стовпцям, що не допускають невизначених
значень.
Якщо між двома типами суті A і B є зв'язок «один до одного», то відповідний зовнішній ключ
за бажанням проектувальника може бути оголошений як в таблиці A, так і в таблиці B. Щоб
відобразити у визначенні таблиці обмеження, яке полягає в тому, що ступінь кінця зв'язку
повинен дорівнювати одиниці, відповідний (можливо, складений) стовпець має бути
додатково специфікований як можливий ключ таблиці (в разі використання мови SQL для
цього служить специфікація UNIQUE).

Для підтримки зв'язку «багато до багатьом» між типами суті A і B створюється додаткова
таблиця AB з двома стовпцями, один з яких містить унікальні ідентифікатори екземплярів
суті A, а інший - унікальні ідентифікатори екземплярів суті B. Позначимо
через AB(с) унікальний ідентифікатор екземпляра з деякого типа суті C. Тоді, якщо в
екземплярі зв'язку «багато до багатьом» беруть участь екземпляри a1, a2 ..., an типа
суті A і екземпляри b1, b2 ..., bm типа суті B, то в таблиці AB мають бути присутніми всі
рядки вигляду < AB (ai), AB(bj)> для i = 1, 2 ..., n, j = 1, 2 ..., m. Зрозуміло, що,
використовуючи таблиці A, B і AB, за допомогою стандартних реляційних операцій можна
знайти всі пари екземплярів типів суті, що беруть участь в даному зв'язку.

Відтворення в реляційній схемі супертипів і підтипів суті


У цьому підрозділі ми припускаємо, що реляційна схема бази даних проектується з
розрахунку на використання звичайної SQL-ориентированной СУБД, що не підтримує
об'єктно-реляційні розширення. До речі, відмітимо, що підтримка таких розширень не дуже
допомагає при переході від концептуальної схеми бази даних в моделі «Суть-Зв'язок» до
об'єктно-реляційної схеми, відповідної останнім стандартам мови SQL.

Якщо в концептуальній схемі (ER-диаграмме) присутні підтипи, то можливі два способи їх


уявлення в реляційній схемі:

* (a) зібрати всі підтипи в одній таблиці;


* (b) для кожного підтипу утворити окрему таблицю.

При застосуванні способу (a) таблиця створюється для максимального супертипа (типа суті,
що не є підтипом), а для підтипів можуть створюватися представлення(проекції). Таблиця
містить стовпці, відповідні кожному атрибуту (і зв'язкам) кожного підтипу. У таблицю
додається, принаймні, один стовпець, що містить код ТИПу; він стає часткою первинного
ключа. Для кожного рядка таблиці значення цього стовпця визначає тип суті, екземпляру
якого відповідає рядок. Стовпці цього рядка, які відповідають атрибутам і зв'язкам, відсутнім
в даному типові суті, повинні містити невизначені значення.

При використанні методу (b) для кожного підтипу першого рівня (для глибших рівнів
застосовується метод (a)) супертип відтворюється за допомогою представлення UNION (зі
всіх таблиць підтипів вибираються загальні стовпці - стовпці супертипа).

У кожного способу є свої переваги та недоліки. До переваг першого способу (одна таблиця
для супертипа і всіх його підтипів) можна віднести наступне:
* відповідність логіці супертипів і підтипів; оскільки будь-який екземпляр будь-якого
підтипу є екземпляром супертипу, логічно зберігати разом всі рядки, відповідні екземплярам
супертипа;
* забезпечення простого доступу до екземплярів супертипа і не дуже складний доступ
до екземплярів підтипів;
* можливість обійтися невеликим числом таблиць.

Недоліки методу (a):


* прикладна програма, що має справу з однією таблицею супертипа, повинна включати
додаткову логіку роботи з різними наборами стовпців (залежно від значення стовпця ТИП) і
різними обмеженнями цілісності (залежно від особливостей зв'язків, визначених для
підтипу);
* загальна для всіх підтипів таблиця потенційно може стати вузьким місцем
при многопользовательском доступі унаслідок можливості блокування таблиці в цілому
* для індивідуальних стовпців підтипів повинна допускатися можливість містити
невизначені значення; таким чином, потенційно в загальній таблиці міститиметься багато
невизначених значень, що при використанні деяких РСУБД може зажадати значного об'єму
зовнішньою памяти10).

Достоїнства методу (b) полягають в наступному:


* діють зрозуміліші правила роботи з підтипами (кожному підтипу відповідає однойменна
таблиця);
* спрощується логіка додатків; кожна програма працює тільки з потрібною таблицею.

Недоліки методу (b):


* у загальному випадку потрібні дуже багато окремих таблиць;
* робота з екземплярами супертипу на основі уявлення, об'єднуючого таблиці супертипів,
може опинитися недостатньо ефективною;
* оскільки безліч екземплярів супертипа є об'єднанням безлічі екземплярів підтипів, не
всі РСУБД можуть забезпечити виконання операцій модифікації екземплярів супертипа.

Відтворення в реляційній схемі зв'язків, що взаємно виключають


Існують два способи формування схеми реляційною БД за наявності зв'язків, що взаємно
виключають (маються на увазі зв'язки «один до багатьом», причому кінець зв'язку «багато»
знаходиться на стороні суті, для якого зв'язку є такими, що взаємно виключають):

* (a) загальне зберігання зовнішніх ключів;


* (b) роздільне зберігання зовнішніх ключів.

Зрозуміло, що якщо є зв'язки згаданої категорії, що взаємно виключаються, то в таблиці,


відповідної суті, для якого зв'язки є такими, що взаємно виключають, необхідно зберігати
зовнішні ключі. Якщо зовнішні ключі всіх потенційно зв'язаних таблиць мають загальний
формат, то можна застосувати спосіб (a), тобто створити два стовпці: ідентифікатор зв'язку
і ідентифікатор суті (можливо, складений). Стовпець ідентифікатора зв'язку
використовується для розрізнення зв'язків, що покриваються дугою виключення. У стовпці
(стовпцях) ідентифікатора суті зберігаються значення унікального ідентифікатора суті на
далекому кінці відповідного зв'язку.

Якщо результуючі зовнішні ключі не відносяться до одного домена, то доводиться удаватися


до використання способу (b), тобто створювати для кожного зв'язку, дугою виключення, що
покривається, явні стовпці зовнішніх ключів; всі ці стовпці можуть містити невизначені
значення.

Перевага підходу (a) полягає в тому, що в таблиці, відповідній суті, з'являється всього два
додаткові стовпці. Очевидним недоліком є ускладнення виконання операції з'єднання: щоб
скористатися для з'єднання одного з альтернативних зв'язків, потрібно спочатку провести
обмеження таблиці відповідно до потрібного значення стовпця, що містить ідентифікатори
зв'язків.

При використанні підходу (b) з'єднання є явними (і природними). Недолік полягає в тому,
що потрібно мати стільки стовпців, скільки є альтернативних зв'язків. Крім того, в кожному
з таких стовпців міститиметься багато невизначених значень, зберігання яких потенційно
може привести до серйозних накладних витрат зовнішньої пам'яті.
Мал. 9.14. Можливі модифікації ER-діаграм, що дозволяють уникнути зв'язків, що взаємно
виключають
Модифікація, показана на мал. 9.14 (b), заснована на тому спостереженні, що якщо зв'язки
є альтернативними, то вони розділяють безліч екземплярів суті A на два або більш
непересічних підмножини, які можуть лежати в основі визначення підтипів A1 і A2. Це
хороший варіант, якщо такі підтипи можуть стати в нагоді ще для чого-небудь. Наприклад,
в разі взаємного зв'язку, що виключає, представленого на мал. 9.12, у справних і
несправних літаків можуть имется неспівпадаюча безліч атрибутів (скажімо, у типа
суті СПРАВНІ ЛІТАКИ може бути атрибут дата завершення гарантійного терміну, а у типа
суті НЕСПРАВНІ ЛІТАКИ - атрибут тип несправності). З іншого боку, як наголошувалося в
попередньому розділі, для використання цього підходу потрібна можливість динамічної
зміни типа існуючого екземпляра.

Модифікація, показана на мал. 9.14 (с), заснована на тому спостереженні, що якщо типи
суті B і C беруть участь в альтернативному зв'язку, то, видно, у цієї суті є щось загальне.
Можливо, їх було б правильніше визначати як підтипи деякого загального типу суті.
Відмітимо, що приклад з мал. 9.12 явно демонструє, що далеко не завжди типи суті, що
беруть участь в альтернативному зв'язку, володіє загальними рисами.
Востаннє редаговано: Четвер, 11 лютого 2016, 13:31. Версія: 0. Опубліковано: Понеділок, 22
жовтня 2012, 18:00.

Робота з таблицями при допомозі SQL

1. Об'єкти реляційної бази даних


2. Опис основних команд SQL
2.1 Створення бази даних
2.2 Створення таблиці
2.3 Видалення таблиці
2.4 Запис даних в таблиці
2.5 Запит даних з таблиці
2.6 Видалення записів з таблиці
2.7 Модифікація записів в таблиці
2.8 Модифікація структури таблиці
Об'єкти реляційної бази даних
Ієрархія об'єктів реляційної бази даних прописана в стандартах по SQL, зокрема, в стандарті
SQL-92, на який ми орієнтуватимемося при викладі матеріалу лекції. Цей стандарт
підтримується практично всіма сучасними СУБД, аж до настільних. Ієрархія об'єктів
реляційної бази даних показана на рисунку нижче.

На самому нижньому рівні знаходяться найменші об'єкти, з якими працює реляційна база
даних, - стовпці (колонки) і рядки. Вони, у свою чергу, групуються в таблиці і
представлення.
Таблиці і представлення, які представляють фізичне віддзеркалення логічної структури бази
даних, збираються в схему. Декілька схем збираються в каталоги, які потім можуть бути
згруповані в кластери. Слід зазначити, що жодна з груп об'єктів стандарту SQL-92 не
пов'язана із структурами фізичного зберігання інформації в пам'яті комп'ютерів.
Окрім вказаних на рисунку об'єктів, в реляційній базі даних можуть бути створені індекси,
тригери, події, команди, процедури і ряд інших. Тепер перейдемо до визначення об'єктів
реляційної бази даних.
Кластери, каталоги і схеми не є обов'язковими елементами стандарту а, отже, і програмного
середовища реляційних баз даних.
Під кластером розуміється група каталогів, до яких можна звертатися через одне з'єднання
з сервером бази даних (програмна компонента СУБД).
На практиці процедура створення каталогу визначається реалізацією СУБД на конкретній
операційній платформі. Під каталогом розуміється група схем. На практиці каталог часто
асоціюється з фізичною базою даних як набором фізичних файлів операційної системи, які
ідентифікуються її ім'ям.
Для проектувальника бази даних схема - це загальне логічне представлення відношень
закінченої бази даних. З погляду SQL, схема - це контейнер для таблиць, представлень і
інших структурних елементів реляційної бази даних. Принцип розміщення елементів бази
даних в кожній схемі повністю визначається проектувальником бази даних.
Для створення таблиць і уявлень наявність схеми не обов'язкова. Якщо у вас планується
інсталяція тільки однієї логічної бази даних, то ясно, що можна обійтися і без схеми. Але
якщо планується, що одна і та ж СУБД використовуватиметься для підтримки декількох баз
даних, то належна організація об'єктів баз даних в схеми може значно полегшити супровід
цих баз даних. На практиці схема часто асоціюється з об'єктами певного користувача
фізичної бази даних.
Далі об'єкти реляційної бази даних вводитимуться в контексті реляційної СУБД Oracle 9i.
Такий підхід прийнятий тому, що проектування фізичної моделі реляційної бази даних
виконується для конкретної середи її реалізації.
У Oracle 9i термін схема (Schema) використовується для опису всіх об'єктів бази даних, які
створені деяким користувачем. Для кожного нового користувача автоматично створюється
нова схема.
До основних об'єктів реляційних баз даних належать таблиця, представлення і користувач.
Таблиця (Table) є базовою структурою реляційної бази даних. Вона є одиницею зберігання
даних - відношенням. Таблиця ідентифікується в базі даних своїм унікальним ім'ям, яке
включає ідентифікацію користувача. Таблиця може бути порожньою або складатися з
набору рядків.
Представлення (View) - це поіменована динамічно підтримувана СУБД вибірка з однієї або
декількох таблиць бази даних. Оператор вибірки обмежує видимі користувачем дані.
Зазвичай СУБД гарантує актуальність уявлення - його формування проводиться кожного
разу, коли уявлення використовується. Інколи уявлення називають віртуальними
таблицями.
Користувач (User) - це об'єкт, що володіє можливістю створювати або використовувати інші
об'єкти бази даних і запрошувати виконання функцій СУБД, таких як організація сеансу
роботи, зміна стан бази даних і так далі
Для спрощення ідентифікації і іменування об'єктів в базі даних підтримується такі об'єкти,
як синонім, послідовність і визначені користувачем типи даних.
Синонім (Synonym) - це альтернативне ім'я об'єкту (псевдонім) реляційної бази даних, яке
дозволяє мати доступ до даного об'єкту. Синонім може бути загальним і приватним.
Загальний синонім дозволяє всім користувачам бази даних звертатися до відповідного
об'єкту по його псевдоніму. Синонім дозволяє приховати від кінцевих користувачів повну
кваліфікацію об'єкту в базі даних.
Індекс (Index) - це об'єкт бази даних, що створюється для підвищення продуктивності
вибірки даних і контролю унікальності первинного ключа (якщо він заданий для таблиці).
Повністю індексні таблиці (index-organized tables) виконують роль таблиці і індексу
одночасно.
Табличний простір або область (Tablespace) - це іменована частка бази даних,
використовувана для розподілу пам'яті для таблиць і індексів. У Oracle 9i - це логічне ім'я
фізичних файлів операційної системи. Всі об'єкти бази даних, в яких зберігаються дані,
відповідають деяким табличним просторам. Більшість об'єктів бази даних, в яких дані не
зберігаються, знаходяться в словнику даних, розташованому в табличному просторі
SYSTEM.
Кластер (Cluster) - це об'єкт, задаючий спосіб сумісного зберігання даних в декількох або
одній таблиці. Одним з критеріїв використання кластера є наявність загальних ключових
полів в декількох таблицях, які використовуються в одній і тій же команді SQL. Зазвичай
кластеризовані стовпці або таблиці зберігаються в базі даних у вигляді таблиць хешування
(тобто спеціальним чином).
Секція (Partition) - це об'єкт бази даних, який дозволяє представити об'єкт з даними у
вигляді сукупності підоб'єктів, віднесених до різних табличних просторів. Таким чином,
секціонування дозволяє розподіляти дуже великі таблиці на декількох жорстких дисках.
Даними об'єктами реляційної бази даних є програми, тобто виконуваний код. Цього код
зазвичай називають серверним кодом (server-side code), оскільки він виконується
комп'ютером, на якому встановлено ядро реляційної СУБД. Планування і розробка такого
коду є одним із завдань проектувальника реляційної бази даних.

Процедура (Stored procedure) - це об'єкт бази даних, що представляє пойменований набір


команд SQL і/або операторів спеціалізованих мов обробки програмування бази даних.
Функція (Function) - це об'єкт бази даних, що представляє пойменований набір команд SQL
і/або операторів спеціалізованих мов обробки програмування бази даних, який при
виконанні повертає значення - результат обчислень.
Команда (Command) - це пойменований оператор SQL, який заздалегідь відкомпілювався і
зберігається в базі даних. Швидкість обробки команди вища, ніж у відповідного йому
оператора SQL, оскільки при цьому не виконуються фази синтаксичного розбору і
компіляції.
Тригер (Trigger) - це об'єкт бази даних, який є спеціальною процедурою. Ця процедура
запускається автоматично, коли відбувається пов'язана з тригером подія (наприклад, до
вставки рядка в таблицю).
Таймер (Timer) відрізняється від тригера тим, що запускаючою подією є подія таймера.
Пакет (Package) - це об'єкт бази даних, який складається з пойменованого структурованого
набору змінних, процедур і функцій.
У розподілених реляційних СУБД є спеціальні об'єкти: знімок і зв'язок бази даних.
Знімок (Snapshop) - локальна копія таблиці віддаленої бази даних, яка використовується
для тиражування (реплікації) таблиці або результату запиту. Знімки можуть модифікуватися
або бути призначеними тільки для читання.
Зв'язок бази даних (Database Link) або зв'язок з видаленою базою даних - це об'єкт бази
даних, який дозволяє звернутися до об'єктів видаленої бази даних. Ім'я зв'язку бази даних,
грубо кажучи, можна представити як посилання на параметри доступу до видаленої бази
даних.
Для ефективного управління розмежуванням доступу до даних в Oracle підтримує об'єкт
роль.
Роль (Role) - об'єкт бази даних, що є пойменованою сукупністю привілеїв, які можуть
призначатися користувачам, категоріям користувачів або іншим ролям.

Опис основних команд SQL


SQL складається з набору команд маніпулювання даними в реляційній базі даних, які
дозволяють створювати об'єкти реляційної бази даних, модифікувати дані в таблицях
(вставляти, видаляти, виправляти), змінювати схеми відношень бази даних, виконувати
обчислення над даними, робити вибірки з бази даних, підтримувати безпеку і цілісність
даних.
Весь набір команд SQL можна розбити на наступні групи:
 команди визначення даних (DDL - Data Defininion Language);
 команди маніпулювання даними (DML - Data Manipulation Language);
 команди вибірки даних (DQL - Data Query Language);
 команди управління транзакціями;
 команди управління даними.
При виконанні кожна команда SQL проходить чотири фази обробки:
- фаза синтаксичного розбору, яка включає перевірку синтаксису команди, перевірку імен
таблиць і колонок в базі даних, а також підготовку початкових даних для оптимізатора;
- фаза оптимізації, яка включає підстановку дійсних імен таблиць і колонок бази даних в
представлення, ідентифікацію можливих варіантів виконання команди, визначення вартості
виконання кожного варіанту, вибір якнайкращого варіанту на основі внутрішньої
статистики;
- фаза генерації виконуваної коди, яка включає побудову виконуваного коду команди;
- фаза виконання команди, яка включає виконання коду команди.
В даний час оптимізатор є складовою частиною будь-якої промислової реалізації SQL. Робота
оптимізатора заснована на зборі статистики про виконувані команди і виконання
еквівалентних перетворень алгебри із відношеннями бази даних. Така статистика
зберігається в системному каталозі бази даних. Системний каталог є словником даних для
кожної бази даних і містить інформацію про таблиці, представлення, індекси, колонки,
користувачів і їх привілеї доступу. Кожна база даних має свій системний каталог, який
представляє сукупність визначених таблиць бази даних.
Створення бази даних
Синтаксис команди CREATE DATABASE має вигляд:

CREATE DATABASE [IF NOT EXISTS] имя_базы_данных


[спецификация_create[,спецификация_create]...]

Команда CREATE DATABASE створює базу даних з вказаним ім'ям. Для використання
команди необхідно мати привілей CREATE для бази даних. Якщо база даних з таким ім'ям
існує, генерується помилка.

спецификация_create:
[DEFAULT] CHARACTER SET имя_набора_символов
[DEFAULT] COLLATE имя_порядка_сопоставления

Опція спецификация_сrеаtе може вказуватися для визначення характеристик бази даних.


Характеристики бази даних зберігаються у файлі db.opt, розташованому в каталозі даних.
Конструкція CHARACTER SET визначає набір символів для бази даних за умовчанням.
Конструкція COLLATION задає порядок зіставлення за умовчанням.

Бази даних в MYSQL реалізовані у вигляді каталогів, які містять файли, відповідні таблицям
бази даних. Оскільки спочатку в базі немає ніяких таблиць, оператор CREATE DATABASE
тільки створює підкаталог в каталозі даних MYSQL.

Бази даних зберігають дані в таблицях. Чим же є ці таблиці? Найпростіше таблиці можна
уявляти собі, як що складаються з рядків і стовпців. Кожен стовпець визначає дані певного
типа. Рядки містять окремі записи.
Розгледимо таблицю 3.1, в якій приведені персональні дані деяких людей:
Таблиця 3.1. Персональні дані
Ім'я Вік Країна e-mail
Михайло Петров 28 Росія misha@yandex.ru
Джон Доусон 32 Австралія j.dow@australia.com
Моріс Дрюон 48 Франція md@france.fr
Снежана 19 Болгарія sneg@bulgaria.com

Всякий раз при роботі з клієнтом mysql необхідно визначати, яка база даних
використовуватиметься.
Визначити поточну базу даних можна декількома способами:
- визначення імені бази даних при запуску
mysql employees (у Windows)
mysql employees -u manish -p (у Linux)

- визначення бази даних за допомогою оператора USE в запрошенні mysql


USE employees;

Щоб отримати поточну активну базу даних


SELECT DATABASE();

Створення таблиці
Команда SQL для створення таблиці має наступний вигляд:

CREATE TABLE employee_data


(
emp_id int unsigned not null auto_increment primary key,
name varchar(20),
age int,
country varchar(20),
email varchar(60)
);

Примітка: у MYSQL команди і імена стовпців не розрізняють регістр символів, проте імена
таблиць і баз даних можуть залежати від регістра у зв'язку з використовуваною платформою
(як в Linux).
За ключовими словами CREATE TABLE слідує ім'я створюваної таблиці employee_data. Кожен
рядок усередині дужок представляє один стовпець. Ці стовпці зберігають для кожного
співробітника ідентифікаційний номер (emp_id), прізвище (name) вік (вік), стаж роботи в
компанії (yos), і адресу електронна пошта (електронна пошта).

За ім'ям кожного стовпця слідує тип стовпця. Типи стовпців визначають типа даних, які
міститиме стовпець. Перший стовпець (emp_id) містить ідентифікаційний номер (id)
співробітника.
- int: визначає типа стовпця як ціле число.
- unsigned: визначає, що число буде без знаку (позитивне ціле).
- not null: визначає, що значення не може бути порожній покажчик (порожнім); тобто
кожен рядок в цьому стовпці повинен мати значення.
- auto_increment: коли MYSQL зустрічається компанія стовпцем з
атрибутом auto_increment, то генерується нове значення, яке на одиницю більш ніж
найбільше значення в стовпці. Тому ми не повинні задавати для цього стовпця
значення, MYSQL генерує їх самостійно. З цього також виходить, що кожне значення в
цьому стовпці буде унікальним.
primary key: допомагає при індексуванні стовпця, що прискорює пошук значень. Кожне
значення має бути унікальне. Ключовий стовпець необхідний для того, щоб унеможливити
збігу даних. Наприклад, два співробітники можуть мати одне і те ж ім'я, і тоді встане
проблема - як розрізняти цих співробітників, якщо не задати їм унікальні ідентифікаційні
номери. Якщо є стовпець з унікальними значеннями, то можна легко розрізнити два записи.
Краще всього доручити привласнення унікальних значень самій системі MYSQL.

Загальний формат інструкції CREATE TABLE такий:

CREATE [TEMPORARY] TABLE [IF NOT EXISTS] ім'я


[(специфікація ...)]
[опція ...]
[ [IGNORE | REPLACE] запит]

Прапор TEMPORARY задає створення тимчасової таблиці, що існує протягом поточного


сеансу. Після закінчення сеансу таблиця віддаляється. Тимчасовим таблицям можна
привласнювати імена інших таблиць, роблячи останні тимчасово недоступними.
Специфікатор IF NOT EXIST запобігає виведенню повідомлень про помилки у випадку, якщо
таблиця з вказаним ім'ям вже існує. Імені таблиці може передувати ім'я бази даних,
відокремлене крапкою. Якщо це не зроблено, таблиця буде створена в базі даних, яка
встановлена за умовчанням.

Щоб задати ім'я таблиці з пропусками, необхідно взяти його в зворотні лапки, наприклад
'Courses list'. Те ж саме потрібно буде робити у всіх посиланнях на таблицю, оскільки
пропуски використовуються для розділення ідентифікаторів.

Дозволяється створювати таблиці без стовпців, проте в більшості випадків специфікація хоч
би одного стовпця все ж присутня. Специфікації стовпців і індексів приводяться в круглих
дужках і розділяються комами. Формат специфікації наступний:

ім'я тип
[NOT NULL | NULL]
[DEFAULT значення]
[AUTO_INCREMENT]
[KEY]
[посилання]

Видалення таблиці
Для того, щоб видалити таблицю, переконаємося спершу що вона існує. Це можна
перевірити за допомогою команди SHOW TABLES

Для видалення таблиці використовується команда DROP TABLE

DROP TABLE [IF EXISTS] таблиця [RESTRICT | CASCADE]


Специфікація IF EXISTS пригнічує виведення повідомлення про помилку, що видається у
випадку, якщо задана таблиця не існує. Можна указувати декілька імен таблиць, розділяючи
їх комами.

Прапори RESTRICT і CASCADE призначені для полегшення переносу програм, на даний


момент в mySQL не використовуються.

Запис даних в таблиці


Оператор INSERT заповнює таблицю даними. Ось загальна форма INSERT.

INSERT into table_name (column1, column2 ...)


values (value1, value2...);

де table_name є ім'ям таблиці, в яку треба внести дані;


column1, column2 і так далі є іменами стовпців,
а value1, value2 і так далі є значеннями для відповідних стовпців.

Наступний оператор вносить перший запис до таблиці employee_data, яку ми розглядували


в лекції 3.

Запит даних з таблиці


Таблиця employee_data містить тепер достатньо даних, щоб можна було почати з нею
працювати. Запит даних виконується за допомогою команди SELECT. Оператор SELECT має
наступний формат:

SELECT имена_столбцов from имя_таблицы [WHERE ...умови];

Частка оператора з умовами є необов'язковою. По суті, потрібно знати імена стовпців і ім'я
таблиці, з якої витягуються дані.

Оператори порівняння = і !=
SELECT name from employee_data where country="Україна";

Оператори більші і менші


SELECT name from employee_data where age > 32;

Оператори <= і >=


SELECT name, country from employee_data where age <= 32;

Пошук текстових даних за шаблоном


Якщо треба вивести дані про співробітників, ім'я яких починається з букви В, то можна
використати оператор LIKE таким чином.
select name from employee_data where name LIKE "В%";

Знак % діє як символ-заступник (аналогічно використанню * у системах DOS і Linux). Він


замінює собою будь-яку послідовність символів.

Слово HAVING
Щоб вивести середній вік працівників для кожної із країн, можна скористатися запитом
GROUP BY, наприклад:

select country, AVG(age) from employee_data


GROUP BY country;

Тепер, якщо нам потрібний перелік тільки тих країн, для яких середній вік працівників
складає більше 30, то можемо записати

select country, AVG(age) from employee_data


GROUP BY country HAVING AVG(age) > 30

Видалення записів з таблиці


Оператор видалення DELETE вимагає завдання імені таблиці і необов'язкових умов.

DELETE from имя_таблицы [WHERE умови];

Примітка: Якщо ніякі умови не будуть задані, то віддаляються всі дані в таблиці.

Модифікація записів в таблиці


Команда UPDATE виконує зміну даних в таблицях. Вона має дуже простий формат.

UPDATE имя_таблицы SET


имя_столбца_1 = значение_1,
имя_столбца_2 = значение_2,
имя_столбца_3 = значение_3, ...
[WHERE условия];

В якості прикладу можна спробувати змінити назву посади "Розробник Web" "програміст
Web".

update employee_data SET


title = 'программист Web'
WHERE title = 'разработчик Web';

Припустимо, директор збільшив свою зарплату на 20000 і надбавки на 5000.

UPDATE employee_data SET


salary = salary + 20000,
perks = perks + 5000
WHERE title='директор';

Модифікація структури таблиці


До вже існуючої таблиці можна додавати, видаляти і модифікувати визначення стовпців, а
також додавати і видаляти індекси, також допускається перейменування таблиці.

ALTER TABLE item


ADD COLUMN Inventory INT (4) NOT NULL DEFAULT 0

Востаннє редаговано: Четвер, 11 лютого 2016, 13:31. Версія: 0. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

Логічні операції
У лекції розглядуються логічні оператори і способи їх застосування в MySql. Також
розглядуються способи впорядковування даних, способи обмеження витягуваних даних і
команди оновлення записів.

1. Оператори AND, OR, NOT


2. Оператори IN і BETWEEN
3. Впорядковування даних та їх обмеження

Оператори AND, OR, NOT


Вибрати дані на основі умов SQL, представлених за допомогою булевих (логічних)
операторів доволі просто

SELECT name, from employee_data


where salary > 70000 AND salary < 90000;

Давайте виведемо список співробітників, прізвища яких починаються з букви До або Л.

SELECT l_name from employee_data where


l_name like 'К%' OR l_name like 'Л%';

Ось складніший приклад ... список імен і віку співробітників, прізвища яких починаються з
До або Л, і які молодше 30 років.

SELECT f_name, l_name , age from employee_data


where (l_name like 'К%' OR l_name like 'Л%') AND age < 30;

Дужки призначені для виділення різних логічних умов і видалення двозначностей.

Оператор NOT допоможе при пошуку всіх співробітників, які не є програмістами.

SELECT f_name, l_name, title from employee_data


where title NOT LIKE "%програміcт%";

Оператори IN і BETWEEN
Щоб знайти співробітників, які є розробниками Web або системними адміністраторами,
можна використовувати оператора SELECT наступного вигляду:

SELECT f_name, l_name, title from


-> employee_data where
-> title = 'разработчик Web' OR
-> title = 'системный адм.';
Або більш простий спосіб

SELECT f_name, l_name, title from


-> employee_data where title
-> IN ('разработчик Web', 'системный адм.');

Використання NOT перед IN дозволяє вивести дані, які не входять в множину, визначувану
умовою IN.
Оператор BETWEEN використовується для визначення цілочисельних меж. Тому замість age
>= 32 AND age <= 40 можна використовувати age BETWEEN 32 AND 40.

select f_name, l_name, age from


-> employee_data where age BETWEEN
-> 32 AND 40;

NOT також можна використовувати разом з BETWEEN.

Що робить запит
SELECT f_name, l_name, title, age
from employee_data where
title NOT IN ('программист', 'старший программист',
'программист мультимедиа')
AND age NOT BETWEEN 28 and 32;

Впорядковування даних та їх обмеження


Витягувані до цих пір дані завжди виводилися в тому порядку, в якому вони були збережені
в таблиці. Насправді SQL дозволяє сортувати дані, що витягують, за допомогою пропозиції
ORDER BY. Цю пропозицію вимагає ім'я стовпця, на основі якого сортуватимуться дані.
Давайте подивимося, як можна вивести імена співробітників з впорядкованими за абеткою
прізвищами співробітників (у зростаючому порядку).

SELECT name from employee_data ORDER BY name;

Щоб вивести список співробітників в спадаючому порядку, можна використовувати


наступного оператора.

SELECT name, age from employee_data ORDER by age DESC;

У міру збільшення таблиць виникає необхідність виводу тільки підмножини даних. Цього
можна добитися за допомогою пропозиції LIMIT.
Наприклад, щоб вивести з таблиці імена тільки перших п'яти співробітників,
використовується оператор LIMIT з аргументом рівним 5.

SELECT f_name, l_name from employee_data LIMIT 5;

Можна з'єднати оператора LIMIT з оператором ORDER BY. Таким чином, наступний оператор
виведе четверо наймолодших співробітників компанії.

SELECT f_name, l_name, age from employee_data ORDER BY age LIMIT 4;

LIMIT можна використовувати також для витягання підмножини даних, використовуючи


додаткові аргументи.

Загальна форма оператора LIMIT має наступний вигляд:

SELECT (що-небудь) from таблиці LIMIT початкова стрічка, к-ть записів;

SELECT f_name, l_name from employee_data LIMIT 6,3;

Витягуватимуть три рядки, починаючи з шостої.

Розгледимо тепер, як вибрати і вивести записи таблиць MYSQL за допомогою ключового


слова DISTINCT (РІЗНИЙ), використання якого виключає поява даних, що повторюються.

Щоб вивести всі посади бази даних компанії, можна виконати наступного оператора:

select DISTINCT title from employee_data;

Унікальні записи можна також відсортувати за допомогою ORDER BY.

select DISTINCT age from employee_data


ORDER BY age;

Робота з датою. Математичні функції


1. Робота з датою
2. Тип стовпця Null
3. Математичні функції

Робота з датою
Дати в MYSQL завжди представлені роком, за яким слідує місяць і потім день місяця. Дати
часто записують у вигляді YYYY-MM-DD, де YYYY -- 4 цифри року, MM -- 2 цифри місяця і DD
-- 2 цифри дня місяця.

Тип стовпця дати дозволяє виконувати декілька операцій, таких як сортування, перевірка
умов за допомогою операторів порівняння і так далі

Використання операторів = і !=

select p_email, phone from employee_per where birth_date = '1969-12-31';

Примітка: MYSQL вимагає, щоб дати були поміщені в лапки.

Використання операторів >= і <=

select e_id, birth_date from employee_per where birth_date >= '1970-01-01';

Визначення діапазонів
select e_id, birth_date from employee_per where
birth_date BETWEEN '1969-01-01' AND '1974-01-01';

Використання Date для сортування даних

select e_id, birth_date from employee_per ORDER BY birth_date;

Вибір даних за допомогою Date


От як можна вибрати співробітників, які народилися в березні.

select e_id, birth_date from employee_per


where MONTH(birth_date) = 3;

Можна також використовувати замість чисел назви місяців.

select e_id, birth_date from employee_per


where MONTHNAME(birth_date) = 'January';

Будьте уважні при використанні назв місяців, оскільки вони розрізняють регістр символів.
Тому January працюватиме, а JANUARY не буде!

Аналогічно можна вибрати співробітників, що народилися в певний рік або в певний день.

select e_id, birth_date from employee_per


where year(birth_date) = 1972;

select e_id, birth_date from employee_per


where DAYOFMONTH(birth_date) = 20;

Поточна дата
Поточну дату, місяць і рік можна вивести за допомогою
аргументу CURRENT_DATE пропозицій DAYOFMONTH(), MONTH() і YEAR(), відповідно. Те ж
саме можна використовувати для вибірки даних з таблиць.

select e_id, birth_date


from employee_per where
MONTH(birth_date) = MONTH(CURRENT_DATE);

Тип стовпця Null


Тип стовпця NULL є спеціальним значенням. Щоб вставити значення NULL, треба просто
видалите відповідний стовпець з оператора INSERT. Стовпці містять NULL за умовчанням,
якщо тільки не визначені як NOT NULL. Значення null може використовуватися для
цілочисельних, а також текстових або двійкових даних.

NULL не можна порівнювати за допомогою арифметичних операторів. Порівняння для NULL


можна робити за допомогою IS NULL або IS NOT NULL.

select e_id, children


from employee_per
where children IS NOT NULL;

Математичні функції
Описані нижче функції виконують різні математичні операції. Як аргументи більшість з них
приймає числа з плаваючою комою і повертає результат аналогічного типа.

ABS(число) - ця функція повертає модуль числа

ASIN(число) - ця функція повертає арксинус числа. Діапазон допустимих значень - від -1


до 1. Поза цим діапазоном значення арксинуса не визначене.

ACOS(число) - ця функція повертає арккосинус числа. Діапазон допустимих значень - від -


1 до 1. Поза цим діапазоном значення арккосинуса не визначене.

ATAN(число) - ця функція повертає арктангенс числа.

ATAN2(число1, число2) - ця функція повертає кут в радіанах крапки із заданими


координатами.

CEILING(число), CEIL(число) - ця функція округлює число до найближчого більшого цілого


числа.

COS(число) - повертає косинус числа

DEGREES(число) - повертає аргумент, перетворений з радіанів в градуси.

ЕХР(число) - ця функція підносить число e (підстава натурального логарифма) до заданого


ступеня.

FLOOR(число) - ця функція округлює число до найближчого меншого цілого числа.

GREATEST(...) - ця функція повертає найбільше значення із списку. Вона може працювати


як з числами, так і з рядками.

LEAST(...) - функція повертає найменше значення із списку.


LN(число), LOG(число) - ця функція повертає натуральний логарифм числа.

LOG(число1, число2) - при виклику з одним параметром функція LOG повертає натуральний
логарифм числа, а при виклику з двома параметрами - повертає логарифм числа2 по
підставі число1.
LOG(число1, число2) еквівалентна LOG(число2)/ LOG(число1).

LOG2(число) - повертає логарифм числа по підставі 2.

LOG10(число) - повертає логарифм числа по підставі 10.

MOD(число1, число2), число1 % число2, число1 MOD число2 - ця функція повертає


залишок від ділення першого числа на друге подібно до оператора %.

PI() - повертає значення числа . За умовчанням відображується п'ять знаків після десяткової
коми, але внутрішньо MYSQL використовує повне представлення дійсного числа подвійної
точності.

POW(число1, число2), POWER(число1, число2) - повертає значення число1, піднесене до


ступеня число2.

RADIANS(число) - Повертає аргумент, перетворений з градусів в радіани.

RAND([число]) - Повертає випадкове число подвійної точності в діапазоні від 0 до 1. Якщо


вказаний цілочисельний аргумент, він служить початковим числом для генератора
випадкових чисел (генеруючи послідовність, що повторюється). Якщо аргумент відсутній,
використовується значення системного годинника.

Функцію можна використовувати для витягання рядків у випадковому порядку.

mysql> SELECT * FROM имя_таблицы ORDER BY RAND();

ORDER BY RAND() у комбінації з LIMIT зручно для вибору випадкового прикладу з набору
рядків:

SELECT * FROM tablel, table2 WHERE a=b AND c<d


ORDER BY RAND() LIMIT 1000;

ROUND(число [, точність]) - ця функція округлює число з плаваючою комою до цілого числа


або, якщо вказаний другий аргумент, до заданої кількості цифр після коми. Якщо точність
негативна, обнуляється ціла частка числа.

SIGN(число) - повертає знак аргументу як -1, 0 або 1, залежно від того, число негативне,
нуль або позитивне.

SIN(число) - Ця функція повертає синус числа в радіанах.

SQRT(число) - ця функція повертає квадратний корінь числа.

TAN(число) - повертає тангенс числа.

TRUNCATE(число1, число2) - повертає число1 з дробовою часткою, усіченою


до число2 десяткових розрядів. Якщо число2 дорівнює 0, результат не має крапки і
дробової частки. Якщо число2 негативне, ціла частка числа завдовжки число2 обнуляється.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:32. Версія: 0. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.
Створення фізичної моделі даних
1. Індекси
1.1 Індекс із структурою B-Tree
1.2 Виключно індексні таблиці
1.3 Вибір колонок для індексування
2. Секціонування
2.1 Секціонування по діапазону
2.2 Хэш-секціонування
2.3 Складене секціонування
3. Кластери

Одне з найважливіших завдань фізичного проектування реляційної бази даних полягає в


тому, щоб дати гарантію, що база даних забезпечує необхідний рівень продуктивності. В
даній лекції ми розглянемо методи боротьби за продуктивність бази даних і сконцентруємо
свою увагу на СУБД-орієнтованих засобах вирішення цього завдання: індексах, секціях,
кластерах.

Індекси
Індексування (indexing) - це спосіб забезпечення швидкого доступу до значень колонки або
комбінації колонок. Фізично нові рядки додаються в кінець таблиці, результатом чого є
неврегульоване розміщення значень в колонках. Без використання яких-небудь методів
впорядкування даних єдиним способом проглядання значення колонки в є послідовний
перегляд кожного рядка від початку таблиці до її кінця, так зване сканування таблиці.
Продуктивність такого сканування пропорційно розміру таблиці, розміру фізичної сторінки
бази даних і довжині рядка.
Одним із способів внесення відношення порядку в значення колонок без порушення
фізичного розташування рядків таблиці є створення - індексу.
Індекс (index) - це об'єкт в реляційній базі даних, який призначений для організації
швидкого доступу до рядків таблиці по значеннях однієї або декількох колонок цього рядка

Про створення індексу ми вже говорили при обговоренні обмежень первинного ключа і
зовнішнього ключа. Тоді індекси призначалися для підтримки цілісності первинного ключа і
підтримки відношень. Зараз піде мова про використання індексу як інструменту підвищення
продуктивності обробки запитів.

Концептуальна дія індексу полягає в наступному - у індексі міститься впорядкований список


значень колонки або комбінації колонок, а також відомості про місцезнаходження на
жорсткому диску відповідних цим значенням рядків таблиці. Значення колонки в індексі
впорядковані. Не дивлячись на те, що порядок рядків в таблиці випадковий, індекс можна
швидко проглянути, щоб знайти конкретне значення.
При вставці нового запису в таблицю перевірка унікальності первинного ключа реалізується
не реальним переглядом індексу, а тим, що вимога унікальності пред'являється до значень
колонки первинного ключа в індексі. Таким чином, індекс - це об'єкт бази даних, який може
істотно скоротити час пошуку потрібних рядків в таблиці

Кожна таблиця бази даних може мати один або декілька індексів. Індекси можуть
створюватися по одній колонці або декільком колонкам таблиці. Колонки, що входять в
індекс, прийнято називати ключовими полями (key fields) або ключами. Індекси можуть бути
унікальними і неунікальними. Неунікальний індекс може мати декілька ключів з однаковими
значеннями.

Індекс із структурою B-Tree


Індекс на основі збалансованої ієрархічної структури, або індекс B-Tree (Balanced Tree
structured object), використовується як індекс за замовчанням в багатьох СУБД (Oracle). Ця
структура нагадує дерево (якщо дивитися від низу до верху), в якому спочатку прочитується
самий верхній блок, - кореневий вузол (root), потім блок на наступному рівні - блок-гілка
(branch) і так до тих пір, поки не витягуватиме блок-листок (leaf) з ідентифікатором рядка.
Значення ключа зберігаються в індексі. Така структура дозволяє скоротити до мінімуму
число операцій введення/виводу. Для отримання ідентифікатора рядка зазвичай потрібно
одне відвідування блок-листка, тобто фізичної сторінки бази даних, відведеної під індекс.

Рис. 11.1 Концептуальна організація B-Tree індексу

Індекс B-Tree - це фізичний об'єкт реляційної бази даних, що організований за принципом


збалансованої ієрархічної структури і володіє набором властивостей. Сформулюємо деякі
властивості індексів із структурою B-Tree.

Індекс B-Tree характеризується кількістю рівнів в індексі (height). Чим менше рівнів, тим
вище продуктивність.
Індекси створюються командою SQL CREATE INDEX.

Виключно індексні таблиці


Індекси можуть створюватися на основі значень однієї або декількох колонок. Якщо вимоги
до даних в запиті задовольняються на основі інформації з пов'язаного з цими даними
індексу, то доступ до базової таблиці не здійснюється. Ця обставина привела до ідеї
створення виключно індексної таблиці (index-organized table). Виключно індексна таблиця
є індексом типа B-Tree бази даних, який одночасно виконує роль таблиці. Всі дані такої
таблиці зберігаються в індексі. Перевагою створення повністю індексованих таблиць
полягає в економії місця зберігання на диску і скорочення об'єму введення/виводу, оскільки
ключові колонки немає необхідності зберігати ще раз в таблиці. Результат виконання запиту
буде отриманий на основі даних, збережених в індексній таблиці. Виключно індексна
таблиця створюється за допомогою команди SQL CREATE TABLE, як показано в прикладі
нижче.

CREATE TABLE Proj_Index


( projno char(8) NOT NULL,
t_person char(32) NOT NULL,
t_frequency integer,
t_problem varchar2(512),
CONSTRAINT pk_ndx PRIMARY KEY( projno, t_person) )
ORGANIZATION INDEX
TABLESPACE ts_ndx1
PCTTHRESHOLD 20
INCLUDING t_frequency
OVERFLOW TABLESPACE ts__of_ndx1;

Команда CREATE TABLE не відрізняється нічим від інших команд створення таблиць до тих
пір, поки не зустрінеться пропозиція ORGANIZATION INDEX, яка указує СУБД на створення
виключно індексної таблиці. Для розміщення індексу на диску указується табличний
простір. Параметр PCTTHRESHOLD указує, що частку рядка, що залишилася, потрібно
зберігати в заданому табличному просторі - сегменті переповнювання, якщо даний рядок
перевищує розмір фізичної сторінки бази даних на вказане число відсотків. Параметр
INCLUDING визначає ім'я колонки, з якою рядок індексної таблиці ділиться на дві частки:
індексну і переповнювання. Ця колонка може бути часткою первинного ключа таблиці або
неключовою колонкою. Всі неключові колонки, які слідують за вказаною колонкою,
розміщуються в сегменті переповнювання, який визначається ключовим словом OVERFLOW.

Вибір колонок для індексування


- колонки первинного ключа. За визначенням, колонки первинного ключа повинні мати
унікальний індекс;
- колонки зовнішнього ключа. Вони дають хороший індекс по двох причинах. По-перше,
вони часто застосовуються для виконання з'єднань з батьківськими таблицями. По-друге,
вони можуть бути використані СУБД за підтримки посилальної цілісності в операціях
видалення рядків батьківської і дочірніх таблиць;
- будь-які колонки, які містять унікальні значення;
- колонки, запити або з'єднання по яких захоплюють від 5 до 10% рядків таблиці;
- колонки, які часто входять як аргументи у функції агрегації;
- колонки, які часто використовуються для перевірки правильності введення даних в
програмах введення/редагування.

Секціонування
У багатьох базах даних в таблицях зберігається величезна кількість даних. Чим більше
розмір таблиці, тим більше часу буде потрібно як для деяких операцій по вибірці рядків
таблиці, так і для виконання деяких функцій адміністратора бази даних (резервного
копіювання і відновлення). Великі за розміром індексовані таблиці мають також великі
індекси, які вимагають багато часу СУБД для роботи з ними.

Секціонування (partitioning) - це спосіб фізичного розподілу таблиць і індексів серед двох


або більше табличних просторів залежно від значень ключових колонок таблиць з метою
підвищення продуктивності операцій введення/виводу. Фрагмент таблиці, розташований в
окремому табличному просторі, називатимемо секцією таблиці.

При здійсненні секціонування одним з важливих понять є колонка таблиці, щодо значень
якої СУБД робитиме те, що фізичне розноситься таблиці по різних табличних просторах на
жорстких дисках. Ці колонка називається ключем секціонування (partition key).

У СУБД Oracle підтримується декілька видів секціонування: секціонування по діапазону,


хэш-секціонування, складене секціонування, а також різні види секціонування індексів.

Секціонування по діапазону
Секціонування по діапазону (range partitioning) означає розподіл рядків таблиці на різні
табличні простори залежно від значення ключа секціонування. Доступ до такої таблиці, як
і до будь-якої іншої, здійснюється по її імені, причому доступ до секцій, розташованої в
кожному табличному просторі, можна отримати окремо.
Наприклад, таблицю, що містить фінансові квартальні звіти організації, можна секціонувати
по даті таким чином, що звіти по кожному кварталу зберігатимуться в окремому табличному
просторі. При такій організації секцій дані тільки по одному кварталу вибиратимуться з
одного табличного простору, що підвищить ефективність роботи бази даних в цілому.

Секціонування по діапазону базується на впорядкуванні рядків таблиці в секціях (табличних


просторах) на основі значення колонок ключа секціонування

CREATE TABLE Sales


(
s_customer_id number(6),
s_amt number(9,2),
s_date date)
PARTITION BY RANGE (s_date)
(PARTITION st_q01 VALUES LESS THAN ('01-apr-2002')
TABLESPACE ts_01,
PARTITION st_q02 VALUES LESS THAN ('01-jul-2002')
TABLESPACE ts_02,
PARTITION st_q03 VALUES LESS THAN ('01-oct-2002')
TABLESPACE ts_03,
PARTITION st_q04 VALUES LESS THAN (MAXVALUE)
TABLESPACE ts_04
);

Щоб дістати доступ до рядків таблиці, розташованих в певній секції, дізнатися про продажі
в третьому кварталі, можна використовувати команду SELECT, як показано нижче:

SELECT s_customer_id, s_amt FROM Sales PARTITION (st_q03);


Як ми можемо побачити, для цього потрібно вказати опцію PARTITION (ім'я секції) після імені
таблиці в пропозиції FROM.

Хэш-секціонування
Хэш-секціонування (hash partitioning) означає рівномірний розподіл рядків таблиці по
табличних просторах залежно від значення ключа секціонування, який в даному випадку
хэшируется. Цей вид секціонування зручно застосовувати для рядків, у яких розподіл
значень ключа секціонування нерівномірно або погано групується. Якщо проектувальник
бази даних ухвалює рішення про створення хэш-секционированной таблиці, то він повинен
достатньо точно представляти розмір цієї таблиці, оскільки вбудовані в СУБД Oracle
алгоритми хешування використовують цей розмір для обчислення позиції рядка на фізичній
сторінці бази даних. Невірне визначення розміру таблиці може привести до великого числа
колізій, тобто до попадання рядків з різними значеннями ключа на одну і ту ж сторінку, що
приводить до підтримки ланцюжків переповнювання і додаткового введення/виводу.

CREATE TABLE Sales


(
s_customer_id number(6),
s_amt number(9,2),
s_date date)
PARTITION BY HASH (s_customer_id)
(PARTITION q01 TABLESPACE ts_01,
PARTITION q02 TABLESPACE ts_02,
PARTITION q03 TABLESPACE ts_03,
PARTITION q04 TABLESPACE ts_04
);

Пропозиція PARTITION BY HASH (s_customer_id) указує СУБД Oracle виконати секціонування


таблиці по ключу секціонування - s_customer_id. Пропозиції вигляду (PARTITION q01
TABLESPACE ts_01 визначають ім'я секції st_q01 і її розміщення у відповідному табличному
просторі ts_01.

Складене секціонування
Складене секціонування (composite partitioning) є комбінацією секціонування по діапазону
і хеш-секціонування. Це означає, що таблиця спочатку розподіляється серед табличних
просторів на основі діапазону значень ключа секціонування, далі кожна з отриманих секцій
діапазонів ділиться на підлеглі секції або підсекції, і потім рядки рівномірно розподіляються
серед підлеглих секцій за значенням хэш-ключа.

CREATE TABLE Sales


(
s_customer_id number(6),
s_amt number(9,2),
s_date date)
PARTITION BY RANGE (s_date)
SUB PARTITION BY HASH (s_customer_id)
SUB PARTITION 4
STORE IN (ts_01, ts_02, ts_03, ts_04)
(PARTITION q01 VALUES LESS THAN ('01-apr-2002'),
PARTITION q02 VALUES LESS THAN ('01-jul-2002'),
PARTITION q03 VALUES LESS THAN ('01-oct-2002'),
PARTITION q04 VALUES LESS THAN (MAXVALUE)
);

Кластери
Найповільнішою операцією, виконуваною СУБД, є операція читання даних з диска або запис
даних на диск. Якщо існує можливість зменшити у декілька разів число таких операцій, то
загальна продуктивність бази даних може помітно збільшитися.

Слід пам'ятати, що СУБД прочитує з диска або записує на диск за один раз одну фізичну
сторінку даних, розмір якої коливається залежно від апаратної платформи від 512 байт до 4
Кб. Таким чином, якщо можна фізично зберігати дані, до яких часто відбувається сумісне
звернення, на одній і тій же сторінці диска або на сторінках, фізично близько розташованих
один до одного, то швидкість доступу до цих даних підвищується.

Кластеризація (Clustering) - це спосіб фізичного розміщення поруч, на одній фізичній


сторінці даних, рядків, доступ до яких здійснюється за допомогою однакового значення
колонки (ключа) з метою збільшення продуктивності. Такий ключ називається кластерним
ключем. Значенням кластерного ключа є значення однакових по сенсу колонок рядків
таблиць, що кластеризуються. Ключ може бути або хэш-ключом, або індексним ключем.
Якщо ключ є хэш-ключом, то фізичне розміщення визначається функцією перетворення
ключа (хешування) і ми маємо справу з вже відомою нам з попередніх розділів таблицею
хешування або хэш-кластером. Якщо це індексний ключ, то для ідентифікації сторінки даних
в кластері використовується індекс із структурою B-Tree, в якому терміни, що мають
однакові значення ключа, розміщуються або в одній сторінці, або в суміжних країн ицах
індексу. Такий кластер називається індексним кластером. Рядки, які зберігаються в
індексному кластері, не обов'язково повинні належати одній таблиці. Таким чином, кластери
є одним з методів зберігання таблиць даних, підтримуваних СУБД. Кластер - це група
таблиць, яка розділяє загальні фізичні сторінки даних при сумісному використанні в запитах
загальних колонок цих таблиць.

До кластеризації, рядки з таблиці зберігаються окремо в своїх фізичних областях на диску.


Після кластеризації по колонці DEPNO, рядки зберігатимуться спільно, розділяючи одні і ті
ж фізичні сторінки бази даних.
Кластеризація може істотно прискорити роботу. Проте, плануючи використання кластерів,
розробник бази даних повинен враховувати наступні чинники:

- кластеризація зачіпає фізичне розміщення даних у файлах бази даних. Тому


рекомендується виконати кластеризацію таблиці тільки по одній колонці або комбінації
колонок;
- кластеризація уповільнює виконання операцій, в яких потрібно просканувати всю
таблицю, оскільки вона може викликати розкид рядків однієї таблиці по безлічі фізичних
сторінок;
- кластеризація може уповільнити введення даних;
- кластеризація може уповільнити модифікацію даних в тих колонках, які поміщені в
кластер.
Через вищеперелічені обставини кластери не рекомендується створювати для таблиць з
інтенсивним оновленням даних. Для того, щоб таблиця була хорошим кандидатом для її
кластеризації, повинні виконуватися принаймні наступні умови:

- значення колонок кластерних ключів розподілені рівномірно і щільно, а їх розмір майже


завжди менше розміру фізичної сторінки (інакше утворюватимуться кластерні ланцюжки).
- в разі індексного кластера на кожен кластерний ключ доводиться більше одного
вибираного рядка, а для хэш-кластера - один рядок. Альтернативне рішення - індексація
таблиці.
- всі дані для заданого кластерного ключа вибираються при кожному доступі по
кластерному ключу. Альтернативне рішення - індексація таблиці.
- Інтенсивність звернень операцій вставки, оновлення і видалення не дуже велика, інакше
загальна продуктивність бази даних може зменшитися. Зворотний негативний ефект.

З фізичної точки зору кластер знаходиться окремо від таблиць. Він створюється з вказівкою
параметрів зберігання, а потім в нім послідовно створюються кластеризовані таблиці. При
описі кластера потрібно вказати колонки або колонку, для яких СУБД сформує кластер, і
таблиці, які будуть включені в його склад. При обробці даних СУБД розміщуватиме рядки,
що містять однакові значення в колонках кластера, фізично максимально близько. В
результаті рядка таблиці можуть бути розподілені серед декількох дискових сторінок, але
первинні і зовнішні ключі зазвичай розташовуються на одній сторінці.

Востаннє редаговано: Четвер, 11 лютого 2016, 13:32. Версія: 0. Опубліковано: Понеділок, 22


жовтня 2012, 18:00.

Транзакції
1. Паралельні запити
2. Транзакції
3. Проблеми паралельного доступу з використанням транзакцій
4. Рівні ізоляції
5. Визначення параметрів транзакції
6. Блокування

Відсутність контролю над паралельним виконанням операцій може привести до спотворення


даних. Якщо два або більш за потоки почнуть здійснювати запис в один і той же файл,
результат буде непередбачуваний. Вирішення проблеми полягає в тому, щоб в той або
інший момент часу тільки один потік міг звертатися до файлу. Приграми, зберігаючі дані в
звичайних файлах, при зверненні до файлу блокують його за допомогою системних
викликів.

У реляційних СУБД блокування реалізовані на абстрактнішому рівні у вигляді транзакцій.


Під транзакцією розуміється послідовність SQL-інструкцій, що виконується повністю або не
виконувана взагалі. Сервер ізолює одночасно-виконувані потоки один від одного,
обмежуючи їх доступ до даних. По мірі надходження транзакцій сервер намагається
виконувати їх так, ніби вони відбуваються послідовно, а не паралельно.

Паралельні запити
СУБД є багатопотоковою програмою, тому вимушена справлятися з множинними запитами
на підключення. Але окрім проблеми планування виникає ще і проблема
одночасного(паралельного) доступу до данних

Програмісти вирішують проблему паралельного доступу за допомогою блокувань. Є


центральний системний сервіс, що відстежує блокування ресурсів і контролюючий роботу
потоків. Якщо якийсь потік захопив ресурс, поставивши на нього блокування, решту всіх
потоків, що звертаються до того ж самому ресурсу, вимушені чекати його звільнення. Це
може призводити до відчутного зниження продуктивності, тому вводяться блокування
різних рівнів, що дозволяють точніше визначати зону дії допустимих і неприпустимих
операцій.
У СУБД блокування реалізуються без прямого втручання з боку користувачів. Одиночні
запити виконуються в атомарному режимі, в якому кожен запит є окремою транзакцією.
Таким чином, деякі проблеми неузгодженості дій можна вирішити, об'єднавши декілька
операцій в одному запиті, наприклад:

UPDATE item SET Inventory = Inventory – 30 WHERE ID 3

Проте, нe всяку послідовність операцій можна виразити у вигляді одного запиту. Скажімо,
для оновлення двох таблиць необхідно два запити. У таких випадках потрібно явно
вказувати початок і кінець кожної трансакції.

Транзакції
Транзакцією називається послідовність дій, яка або повністю фіксується в базі даних, або
повністю відміняється. Інколи під транзакцією також мають на увазі не групу SQL-
операторов, а інтервал часу, протягом якого всі виконувані SQL-оператори можна або
зафіксувати або відмінити.
Так, операція переказу грошей з одного рахунку на іншій повинна складати єдину
транзакцію. Інакше може виникнути ситуація, коли перший SQL-оператор перекладе гроші
на інший рахунок, а другий, виконуючий зняття їх з рахунку, не доведе справу до кінця із-
за непередбаченого збою.

Фіксація транзакції може проводитися примусово по SQL-оператору або неявно після


завершення кожного SQL-оператора. У другому випадку застосовується режим
автокоммита. Як правило, виконання SQL-операторов в інтерактивному режимі завжди
використовує автокоммит. Досить часто в інтегрованому середовищі розробки класи, що
інкапсулюють роботу з базою даних, за умовчанням припускають режим автокоммита .

Транзакції реалізуються шляхом ведення журналу всіх змін, що вносяться до бази даних в
ході кожної транзакції. Коли відбувається відкат, СУБД звіряється з журналом і відміняє всі
зміни. По журналу легко можна відновити узгоджений стан бази даних в разі збою.

Принцип використання транзакцій


Нова транзакція починається з початку кожного сеансу роботи з базою даних. Далі всі
виконувані SQL-операторы входитимуть в одну транзакцію до тих пір, поки не буде
виконаний оператор COMMIT WORK або или ROLLBACK WORK.
Оператор COMMIT завершує поточну транзакцію, виконуючи фіксацію зроблених змін в базі
даних. Інколи говорять, що оператор COMMIT WORK фіксує транзакцію.
Оператора ROLLBACK виконує відкат транзакції, відміняючи дію всіх SQL-операторов,
виконаних в поточній транзакції.
Логічно, що транзакція повинна об'єднувати тільки виконання взаємозв'язаних операцій.
Так, якщо роботи трансакції "дуже великими", такими, що складаються з послідовності не
зв'язаних між собою операторів, то будь-який збій, що автоматично виконує відкат
транзакції, вплине на відміну дій, які могли б бути успішно завершені при "коротших"
транзакціях.

Автоматична фіксація змін


Більшість комерційних СУБД дозволяють встановлювати режим автоматичної фіксації змін -
автокомміт.
Для установки цього режиму використовується (але не всіма СУБД) оператор SET
AUTOCOMMIT ON;, а для відміни режиму - SET AUTOCOMMIT OFF;.

Проблеми паралельного доступу з використанням транзакцій


При паралельному використанні транзакцій можуть виникати наступні проблеми:
· не повторювані читання (non-repeatable read);
· "брудні" читання (dirty read) - читання даних, які були записані транзакцією, яку
згодом відкотили;
· втрачене оновлення (lost update);
· фантомна вставка (phantom insert).

Розгледимо ситуації, в яких можливе виникнення даних проблем.

Неповторюване читання
Припустимо, є дві транзакції, відкриті різними застосуваннями, в яких виконані наступні
SQL-операторы:
Транзакція 1 Транзакція 2
SELECT f2 FROM tbl1 WHERE f1=1; SELECT f2 FROM tbl1 WHERE f1=1;
UPDATE tbl1 SET f2=f2+1 WHERE f1=1;
SELECT f2 FROM tbl1 WHERE f1=1;

У транзакції 2 вибирається значення поля f2, потім в транзакції 1 змінюється значення поля
f2. При повторній спробі вибору значення з поля f2 в транзакції 1 буде отримано інший
результат. Ця ситуація особливо неприйнятна, коли дані прочитуються з метою їх часткової
зміни і зворотного запису в базу даних.

"Брудне" читання
Припустимо, є дві транзакції, відкриті різними застосуваннями, в яких виконані наступні
SQL-операторы:
Транзакція 1 Транзакція 2
SELECT f2 FROM tbl1 WHERE f1=1;
UPDATE tbl1 SET f2=f2+1 WHERE f1=1;
SELECT f2 FROM tbl1 WHERE f1=1;
ROLLBACK WORK;

У транзакції 1 змінюється значення поля f1, а потім в транзакції 2 вибирається значення


поля f2. Після цього відбувається відкат транзакції 1. В результаті значення, отримане
другою транзакцією, відрізнятиметься від значення, що зберігається в базі даних.

Втрачене оновлення
Припустимо, є дві транзакції, відкриті різними застосуваннями, в яких виконані наступні
SQL-операторы:

Транзакція 1 Транзакція 2
SELECT f2 FROM tbl1 WHERE f1=1; SELECT f2 FROM tbl1 WHERE f1=1;
UPDATE tbl1 SET f2=20 WHERE f1=1;
UPDATE tbl1 SET f2=25 WHERE f1=1;

У транзакції 1 змінюється значення поля f1, а потім в транзакції 2 також змінюється значення
цього поля. В результаті зміна, виконана першою транзакцією, буде втрачена.

Фантомна вставка
Припустимо, є дві транзакції, відкриті різними застосуваннями, в яких виконані наступні
SQL-операторы:

Транзакция 1 Транзакция 2
SELECT SUM(f2) FROM tbl1;
INSERT INTO tbl1 (f1,f2) VALUES (15,20);
SELECT SUM(f2) FROM tbl1;

У транзакції 2 виконується SQL-оператор, що використовує всі значення поля f2. Потім


в транзакції 1 виконується вставка нового рядка, що приводить до того, що повторне
виконання SQL-оператора в транзакції 2 видасть інший результат. Така ситуація
називається фантомною вставкою і є приватним випадком непорюваного читання. При
цьому, якщо виконуваний SQL-оператор вибирає не всі значення поля f2, а тільки значення
одного рядка таблиці (використовується предикат WHERE), то виконання
оператора INSERT не приведе до ситуації фантомної вставки.

Рівні ізоляції
Теоретично СУБД повинна забезпечувати повну ізоляцію транзакцій. На практиці ж
вводиться декілька рівнів ізоляції, найвищий з яких відповідає повній ізольованості.
У стандарті мови SQL визначено чотири рівні ізоляції: READ UNCOMMITTED, READ
COMMITTED, REPETABLE READ і SERIALIZABLE. Вони перераховані в порядку від найменшої
до найвищої ізольованості і по черзі вирішують три основне проблеми, що виникають при
використанні транзакцій: поява проміжних даних, поява неузгоджених даних і поява рядків-
примар.
Проміжні дані з'являються, коли незавершена транзакція модифікує рядок таблиці, а інша
транзакція читає цей рядок. Якщо перша транзакція буде скасована (станеться відкат), то
виявиться, що друга транзакція отримала дані, які офіційно ніколи не існували. Така
поведінка виявляється на рівні READ UNCOMMITTED.
У режимі READ COMMITTED транзакціям дозволено читати тільки підтверджені дані. Проте
це не вирішує проблему неузгоджених даних. Припустимо, в ході транзакції вводиться
запит, що визначає число записів в таблиці. Після закінчення цього запиту інша транзакція,
що працює з тією ж самою таблицею, видаляє або додає записи. Якщо тепер перша
транзакція повторно виконає свій запит, вона отримає інші результати.
Проблема неузгоджених даних вирішується на рівні REPEATABLE READ. У цьому режимі
рядки, до яких транзакція звертається для читання або запису, блокуються. Але і тут є
проблема: стрічки-примари. Транзакція може заблокувати всі записи, з якими ведеться
робота, але вона не може перешкодити іншій транзакції додати рядки в ту ж саму таблицю.
Якщо в ході транзакції вводяться два запити на вибірку, а між ними друга транзакція додає
в таблицю новий рядок, цей рядок стане "фантомом", оскільки він раптово з'являється в
ході однієї і тієї ж транзакції.
У режимі SERIALIZABLE транзакції примусово виконуються одна за одною. Саме така
поведінка рекомендується в стандарті SQL. Якщо дві транзакції спробують відновити один і
той же рядок, одна з них буде оголошена такою, що програла в тупиковій ситуації і як
наслідок - скасована.

Визначення параметрів транзакції


Визначення параметрів транзакції виконується оператором SET TRANSACTION, який має в
стандарті SQL-92 наступний формальний опис:
TRANSACTION
{ ISOLATION LEVEL
{ READ UNCOMMITTED
| READ COMMITTED
| REPEATABLE READ
| SERIALIZABLE }
| { READ ONLY | READ WRITE }
| { DIAGNOSTICS SIZE count_message }
} .,. ;
Фраза ISOLATION LEVEL вказує встановлюваний рівень ізоляції.
Фраза READ ONLY встановлює режим, при якому дозволяється тільки читання. Цей режим
встановлюється за умовчанням, якщо рівень ізоляції визначений як READ UNCOMMITTED.
При режимі READ ONLY на дані не встановлюються ніяких блокувань.
Фраза READ WRITE встановлює режим, який дозволяє як читання, так і запис даних. При
цьому режимі рівень ізоляції не може бути встановлений як READ UNCOMMITTED.
Режим READ WRITE встановлюється за умовчанням для будь-якого рівня, відмінного від
READ UNCOMMITTED.
Фраза DIAGNOSTICS SIZE визначає розмір області, використовуваної для запису
діагностичних повідомлень, доступ до яких здійснюється оператором GET DIAGNOSTICS.
Наприклад, для визначення транзакції, що запобігає всім описаним вище конфліктним
ситуаціям, слід виконати SQL-оператор
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;

Блокування
Користувачеві найчастіше не потрібно робити ніяких дій по управленню блокуваннями. Всю
роботу по установці, зняттю і вирішенню конфліктів виконує спеціальний компонент
сервера, званий менеджером блокувань. MS SQL Server підтримує різні рівні блокування
об'єктів (або деталізацію блокувань), починаючи з окремого рядка таблиці і закінчуючи
базою даних в цілому. Менеджер блокувань автоматично оцінює, яку кількість даних
необхідно блокувати, і встановлює відповідного типа блокування. Це дозволяє підтримувати
рівновагу між продуктивністю роботи системи блокування і можливістю користувачів
діставати доступ до даних. Блокування на рівні рядка дозволяє найточніше управляти таким
доступом, оскільки блокуються тільки дійсно змінні рядки. Безліч користувачів можуть
одночасно працювати з даними з мінімальними затримками. Платою за це є збільшення
числа операцій установки і зняття блокувань, а також велика кількість службової інформації,
яку доводиться зберігати для відстежування встановлених блокувань. При блокуванні на
рівні таблиці продуктивність системи блокування різко збільшується, оскільки необхідно
встановити лише одне блокування і зняти її тільки після завершення транзакції. Користувач
при цьому має максимальну швидкість доступу до даних. В той же час вони не доступні
нікому іншому, тому що вся таблиця заблокована. Доводиться чекати, поки поточний
користувач завершить роботу.
Дії, що виконуються користувачами при роботі з даними, зводяться до операцій двох типів:
їх читанню і зміні. У операції по зміні включаються дії з додавання, видалення і власне зміни
даних. Залежно від виконуваних дій сервер накладає певний тип блокування з наступного
переліку:
· Колективні блокування. Вони накладаються при виконанні операцій читання даних
(например,SELECT). Якщо сервер встановив на ресурс колективне блокування, то
користувач може бути упевнений, що вже ніхто не зможе змінити ці дані.
· Блокування оновлення. Якщо на ресурс встановлено колективне блокування і для
цього ресурсу встановлюється блокування оновлення, то ніяка транзакція не зможе
накласти колективне блокування або блокування оновлення.
· Монопольне блокування. Цей тип блокувань використовується, якщо транзакція
змінює дані. Коли сервер встановлює монопольне блокування на ресурс, то ніяка інша
транзакція не може прочитати або змінити заблоковані дані. Монопольне блокування не
сумісне ні з якими іншими блокуваннями, і жодне блокування, включаючи монопольну, не
може бути накладена на ресурс.
· Блокування масивного оновлення. Накладається сервером при виконанні
операцій масивного копіювання в таблицю і забороняє звернення до таблиці будь-яким
іншим процесам. В той же час декілька процесів, що виконують масивне копіювання, можуть
одночасно вставляти рядки в таблицю.
Окрім перерахованих основних типів блокувань SQL Server підтримує ряд спеціальних
блокувань, призначених для підвищення продуктивності і функціональності обробки даних.
Вони називаються блокуваннями намірів і використовуються сервером в тому випадку, якщо
транзакція має намір дістати доступ до даних вниз за ієрархією і для інших транзакцій
необхідно встановити заборону на накладення блокувань, які конфліктуватимуть з
блокуванням, першою транзакцією, що накладається.
Блокування, що раніше розгледіли, відносяться до даних. Окрім перерахованих в середі SQL
Server існує два інших типа блокувань: блокування діапазону ключів і блокування схеми
(метаданих, що описують структуру об'єкту).
Блокування діапазону ключів вирішує проблему виникнення фантомів і забезпечує вимоги
серіалізованості транзакції. Блокування цього типа встановлюються на діапазон рядків,
відповідних певній логічній умові, за допомогою якої здійснюється вибірка даних з таблиці.
Блокування схеми використовується при виконанні команд модифікації структури таблиць
для забезпечення цілісності даних.
Востаннє редаговано: Понеділок, 2 вересня 2019, 10:16. Версія: 0. Опубліковано: Понеділок, 22
жовтня 2012, 18:00.

Проектування структури бази даних

1. Складання схеми бази даних


2. Реалізація моделі
3. Тестування
4. Планування життєвого циклу

Як і при розробці програмного забезпечення, при проектуванні та розробці бази даних


проходять наступні етапи:
- специфікація вимог
- специфікація проекту
- складання схеми БД
- реалізація моделі
- тестування
- планування життєвого циклу
Складання схеми бази даних
Існують два основні типи діаграм: діаграми потоків даних і діаграми взаємозв’язків об'єктів
(entity relationship, ER). На прикладі перших демонструють функціональні перетворення, що
зазнають дані при переході від одного модуля до іншого. Діаграми відношень об'єктів
відображують логічну структуру даних і зв'язку між модулями. Потокові діаграми погано
підходять для описи баз даних. Реляційні бази даних краще всього описуються у вигляді
структур даних.
Діаграми відношень об'єктів відповідають одному з трьох рівнів абстракції: фізичному,
програмному або концептуальному. Діаграма фізичного рівня описує апаратні компоненти.
Це погляд на систему як на сукупність фізичних компонентів. На програмному рівні система
аналізується з точки зору одного або декількох програмних компонентів. Концептуальний
рівень є поглядом на систему з боку користувача.

Специфікація вимог описує систему на концептуальному рівні. Діаграми в даному випадку


відображають бизнес процеси, що відбуваються у системі і взаємодію користувача з нею.
На рис. 8.1 представлено продавець, який вирішує два системні завдання. Перше завдання
полягає в перевірці ціни товару, що продається. Друге завдання - це власне продаж товару.
Тут виникає підзадача: додавання запису про клієнта.

Кожен програмний компонент має власне уявлення про систему. СУБД MYSQL розглядує дані
як інформаційні блоки файлів на диску. Додатки працюють з даними як із записами, які
повертаються в результаті SQL запитів.

На мал. 8.2 приведена діаграма відношень між чотирма таблицями. У цих таблицях
зберігаються відомості про адреси, клієнтів, замовлення і товари. Кожен прямокутник є
таблицею. Лінії, що сполучають таблиці, показують відношення "зовнішній ключ -
первинний ключ". Між таблицями клієнтів і замовлень існує відношення "один до багатьом".
Клієнт може зробити довільне число замовлень (зокрема жодного), але будь-яке замовлення
належить тільки одному клієнтові. Кружок на діаграмі говорить про те, що відношення є
необов'язковим.

У замовлення включається один або декілька товарів. Звернете увагу на відношення "багато
до багатьом". Логічно кожне замовлення пов'язане з групою товарів, а один і той же товар
може входити в декілька замовлень.
Реляційна модель не дозволяє безпосередньо формувати відношення "багато до багатьом".
В ході етапу проектування це відношення перетвориться таким чином, що з'явиться
проміжна таблиця. У таблицю адрес винесені стовпці, загальні для таблиць замовлень і
клієнтів. У таблиці замовлень указується адреса доставки, якщо замовлення робиться через
Web_вузол. У таблиці клієнтів приводяться їх основні адреси, використовувані при
безпосередньому спілкуванні з клієнтами. Наявність таблиці адрес дозволяє гарантувати,
що всі адреси матимуть однакову структуру.
На фізичному рівні описується архітектура системи. Діаграми цього рівня відображають
взаємодію апаратних компонентів. Тут можуть бути представлені мережеві з'єднання, а
також канали запису даних в постійні сховища.

Діаграми відношень об'єктів


Діаграми відношень об'єктів відображують три основні типи інформації: об'єкти (суть),
відношення і характер цих відношень. Об'єкти представляються прямокутниками. Усередині
прямокутника знаходиться ім'я об'єкту. Об'єкт - це загальне поняття, але при моделюванні
реляційних баз даних воно означає таблицю.
Прямі лінії позначають відношення між об'єктами. У реляційних базах даних відношення
реалізуються шляхом об'єднання двох таблиць по групі стовпців, загальних для обох
таблиць. Характер відношення визначається числом рядків, що беруть участь в ньому з
кожного боку. Таблиці, над якою виконується об'єднання, може бути поставлена у
відповідність один рядок або декілька. Перпендикулярна межа означає одиничний зв'язок,
а потрійна лінія - множинну.

Відношення "один до одного" між таблицями клієнтів і адрес. Спеціальні символи, що


виражають характер відношення, ставляться на кінцях лінії. Відношення може "читатися" в
будь-якому напрямі, наприклад "у кожного клієнта є одна адреса" або "кожна адреса
належить до одного клієнта".

Відношення "один до багатьом" між таблицями категорій і товарів. Читається так: "у кожну
категорію входить один або декілька товарів" або "кожен товар належить до однієї і лише
до однієї категорії".

Відношення між об'єктами можуть бути необов'язковими. Щоб показати це, на лінії поряд з
символом відношення ставлять незаштрихований кружок.
Необов'язкове відношення між таблицями замовлень і адрес. Воно читається таким чином:
"у замовленні може бути вказана одна адреса" або "кожна адреса належить до одного
замовлення".

Реалізація моделі
Коли проект бази даних завершений, переходять до її реалізації. Відповідно до діаграм
створюються інструкції CREATE TABLE. Будьте готові повернутися до етапу проектування
для внесення чергових модифікацій: перехід на мову SQL часто відкриває різні упущення.
Всі SQL_инструкции, що створюють базу даних, мають бути зведені в одному або декількох
текстових файлах, а не вводитися в інтерактивному режимі. Це дозволить стирати базу
даних і створювати її "з нуля". Ці ж файли послужать як документація. Перед кожною
інструкцією CREATE TABLE вставляється коментарі, що пояснюють призначення таблиці.
Коментарі ігноруються синтаксичним аналізатором, тому вони не зберігаються в базі даних,
зате дають можливість людині, супроводжуючій базу даних, зрозуміти її структуру. (“//’, “/*
*/”)
Можна також користуватися опцією COMMENT інструкції CREATE TABLE.

При переході від етапу проектування до етапу реалізації необхідно дотримуватися п'яти
ключових принципів:
• первинні ключі слід позначати специфікатором NOT NULL;
• користуйтеся флагом AUTO_INCREMENT для автоматичного створення ідентифікаторів;
• зовнішні ключі повинні посилатися на первинні ключі;
• відношення "багато до багатьом" повинні встановлюватися через проміжну таблицю;
• таблиці, між якими існують стосунки "один до одного", краще об'єднувати.

Як правило, всяка таблиця повинна мати первинний ключ. Стовпці первинних ключів
необхідне об’являти із специфікатором NOT NULL. У більшості таблиць первинним ключем є
окремий стовпець цілочисельних значень, оскільки частенько важко сказати заздалегідь,
чи будуть значення інших полів унікальними.

Зовнішні ключі беруть участь в відношеннях "один до багатьом". Таблиця, з якою існує
"множинний" зв'язок, міститиме зовнішній ключ, вказуючий на первинний ключ протилежної
таблиці. MYSQL не перевіряє правильність значень зовнішніх ключів, тобто пропозиції
FOREIGN KEY інструкції CREATE TABLE є необов'язковими.

Якщо на діаграмі присутні стосунки "багато до багатьом", кожне з них має бути перетворене
в два відношення "один до багатьом" з проміжною таблицею. Первинні стовпці початкових
таблиць перетворяться в зовнішні ключі проміжної таблиці. Це означає, що у неї будуть два
цілочисельні стовпці.

Перевірте доцільність відношень "один до одного". Бувають випадки, корду вони дійсно
необхідні, але, можливо, ви просто пропустили можливість злиття двох таблиць.

Вибір правильних типів стовпців - це творчий процес, частково пов'язаний з аналізом


початкових вимог. Якщо необхідно піклуватися про економію дискового простору, слід
вибирати мінімально можливих типів, що охоплюють заданий діапазон значень. Наприклад,
якщо відомо, що в таблиці буде близько 500 рядків, то тризначного первинного ключа буде
достатньо. Специфікація INT (3) є некоректною, оскільки для типа INT MYSQL завжди
використовує 32 розрядне ціле число. Типа TINYINT займає один байт, що недостатньо. У
даному випадку підійде тип SMALLINT, тобто специфікація типа повинна виглядати так:
UNSIGNED SMALLINT ( 3 ) .

Значення в стовбцях_лічильниках мають бути беззнаковими, тому що негативні цілі числа


трактуватимуться як великі позитивні числа. Отже, вставка в стовпець негативного числа
приведе до того, що наступне число виявиться дуже великим. Таким чином, специфікація
поля_лічильника завжди повинна включати ключове слово UNSIGNED.
Стовпці, що зберігають короткі значення однакової довжини, наприклад коди деталей,
повинні мати типа CHAR. Правда, якщо в таблиці є поля змінної довжини, значення CHAR
можуть автоматично приводитися до типа VARCHAR. Строкові поля завдовжки більше 255
символів повинні мати типа BLOB або TEXT.

Стовпці, що зберігають грошові величини, повинні мати типа DECIMAL. Це тип чисел з
фіксованою кількістю цифр після коми. У MYSQL десяткові числа зберігаються в строковому
вигляді і не підлягають апроксимації, на відміну від інших типів чисел з плаваючою комою.
Ефект апроксимації приводить до того, що числа, що відрізняються на дуже незначну
величину, виявляються рівними. В разі порівняння грошових сум це може означати
незаплановану втрату грошей.
Значення типа DECIMAL перетворяться із строкової форми в числа з плаваючою комою при
виконанні математичних операцій. Щоб захистити себе від помилок апроксимації, виконуйте
ці операції в додатках.

Тестування
Тестування буває двох видів: на предмет пошуку недоліків і на предмет перевірки повноти
реалізації. Недоліки є наслідком людських помилок. За повну вважається система, що
задовольняє всім початковим вимогам.
На підставі специфікації вимог і специфікації проекту провіряються всі функціональні
можливості, реалізовані в базі даних. Потрібно переконатися, що всій інформаційній суті
поставлені у відповідність таблиці або стовпці. Виконаєте ряд типових операцій над базою
даних і переконаєтеся в отриманні очікуваних результатів.
Пошук недоліків спочатку здається легким завданням, і лише згодом з'ясовується, що це не
так. Синтаксичні помилки SQL_запитів виявляються відразу ж і швидко виправляються, але
є помилки, які виявляються лише в певних ситуаціях. Наприклад, об'єднання двох таблиць
без індексу виконується швидко при малій завантаженості системи. Проте коли 20
користувачів одночасно виконують один і той же запит, продуктивність падає нижче за
критичну відмітку.
Якщо в початкових вимогах обумовлені обмеження продуктивності, буде потрібно спеціальні
програми, які викличуть високу завантаженість бази даних. Тільки так можна буде
перевірити її роботу в екстремальних умовах.
У пакет MYSQL входять спеціальні утиліти тестування, що дозволяють вимірювати
продуктивність сервера. Вони є Perl_сценарії, що знаходяться в каталозі sql_bench
дистрибутива.

Планування життєвого циклу


Навіть після введення в експлуатацію системи, необхідний регулярний моніторинг і
супровід. Початкові вимоги міняються, від системи очікується все більш висока
продуктивність. У будь-якої системи є свій життєвий цикл. Має бути складений план, що
описує дії, що виконуються в ході нормальної експлуатації системи, її оновлення і
подальшого списання.
В процесі експлуатації системі необхідний адміністративний контроль. Журнальні файли
розростаються і можуть вимагати усікання. Слід регулярно створювати резервні копії на
випадок можливої аварії. Зовнішні події, наприклад збій живлення, можуть викликати
пошкодження файлів MYSQL, в яких зберігаються таблиці, і їх доведеться відновлювати.
Проте, всі ці питання мають більше відношення до адміністрування баз даних.

Проектування модулів застосувань


Проектування модулів застосувань
Вступ
На цій лекції будуть розглянуті в загальних рисах деякі завдання, які повинен виконати
проектувальник бази даних в процесі проектування бази даних.
Навіть добре спроектована база даних нічого не варта без застосувань, які забезпечують її
життєздатність, переводячи її з одного актуального стану в інший відповідаючи потребам
користувачів в інформації. При цьому користувачі очікують програм, які б допомагали їм
вирішувати їхні завдання швидко і мали б широкі можливості пошуку і обробки інформації.
Тому проектувальнику бази даних варто також звернути увагу на проектування модулів
застосувань, які будуть доповнювати базу даних.
Як вже було згадано раніше, на етапі аналізу аналітики IT-проекту розробляють
функціональну модель предметної області. Ця модель являє собою вхідні дані для етапу
проектування модулів застосувань бази даних.
Елементи функціональної моделі дозволяють описати функції обробки даних, організувати
їх у відповідності з бізнес-вимогами і, відповідно, побудувати відображення цих функцій в
набір визначень модулів застосувань. При цьому варто дотримуватися наступних двох
правил: уникати створення дублюючого коду і намагатися не створювати великих модулів
зі складною логікою.
Як правило, проектування модулів застосувань виконується паралельно з проектуванням
фізичної структури бази даних. Ці два завдання пов’язані. Практично будь-яке рішення в
моделюванні даних майже завжди вигідне для одних модулів і створює проблеми для інших.
Наприклад. Припустимо, що при пошуку одного виду структурованого документу,
розміщеного в таблиці бази даних, використовуються два ідентифікатори: внутрішній номер
організації, який генерується системою, і абревіатура організації (коротка назва). Наявність
цих колонок в базі даних є проектним рішенням. На екранній формі пошуку (модуль
додатка) в таких документах використовуються два розкривних списки. Один список
сформований за номером організації, а інший – за її абревіатурою.
Підтримка двох ідентифікаторів, фактично визначаючих одну і ту ж організацію, створює
наступну проблему для модуля вводу документа: при помилці в наборі абревіатури одна і
та ж організація буде мати дві короткі назви. Щоб запобігти такій ситуації, в модулі вводу
документа повинен бути передбачений код, який забезпечує введення абревіатур через
розкривний список, а в модулі вводу даних про організації передбачено, щоб поле
абревіатури не було пустим.
Тому проектувальник бази даних повинен враховувати наслідки рішень які він вибирає і
вибирати компромісний варіант.

Аналіз функціональної моделі предметної області бази даних


Щоб спроектувати модулі застосувань, необхідно знати, як буде працювати інформаційна
система з базою даних. Таку інформацію можна отримати із функціональної моделі
предметної області бази даних. Для проектування модулів застосувань проектувальнику
бази даних потрібен набір специфікацій функцій, які задають необхідні вимоги до обробки
бізнес-даних, а також набір залежностей між різними бізнес-функціями.
Фактично це значить, що входом для вирішення завдання проектування модулів застосувань
бази даних є ієрархія функцій. На виході проектувальник повинен отримати опис
(специфікацію) модулів застосувань, а в процесі проектування модулів проектувальник
будує відображення бізнес-вимог в специфікації модулів.
Алгоритм дій проектувальника бази даних такий: спочатку проектувальник намагається
сформулювати бізнес-вимоги (функції) в загальному вигляді, а потім виконує декомпозицію
кожної такої бізнес-функції до тих пір доки не буде отримана деяка функція, яку можна
вважати атомарною функцією. Критерієм атомарності функції є отримання відповіді на
запитання: чи доцільно виконати тільки частину функції?
Наприклад. Розглянемо фрагмент ієрархії функцій для обробки заяв про виплату страхового
відшкодування. На спрощеній схемі рис. показана функцію "2. Обробити заяву". Виконання
цієї функції включає в себе виконання чотирьох функцій наступного рівня:"2.1
Зареєструвати заяву", "2.2 Прийняти рішення щодо заяви", "2.3 Провести платіж щодо
заяви", "2.4 Закрити заяву".
На рис. показана наступна декомпозиція функції "2.2 Прийняти рішення щодо заяви".
Отримана на цьому етапі функція "2.2.5 Дозволити ремонт" є атомарною функцією. Ремонт
дозволяється або не дозволяється.

Ієрархія функції для обробки заяв про виплату страхового відшкодування


При розгляді ієрархії функцій проектувальнику бази даних потрібно звернути увагу на
наступні моменти:
 в функціональній моделі бази даних описуються бізнес-функції і не всі з них будуть
безпосередньо підтримуватися додатком бази даних;
 при розгляді ієрархій нерідко виникає ситуація, коли екземпляри однієї і тієї ж функції
будуть мати різні номера.
 Якщо в першому випадку додаткову інформацію про те, які бізнес-функції будуть
реалізовані в системі, можна отримати від керівника проекту, то в другому випадку
проектувальник бази даних, скоріш за все, має справу з помилкою аналітика у
визначенні функції.

Визначення функцій
При розробці ієрархії функцій аналітик повинен надати текстовий опис до кожної функції, у
крайньому випадку для верхнього і найнижчого рівнів ієрархії. Бажано, щоб у цьому описі
аналітики виділяли сутності предметної області. Це важливо для того, щоб знати з якими
сутностями предметної області працює функція, тобто які потенційні об’єкти реляційної бази
даних будуть використовуватися в кожній функції. Якщо це не зроблено, то
проектувальнику бази даних прийдеться робити це самостійно.
Приклад. Визначення функції "2.2.2. Перевірити чи забезпечена заява".
"Отримати і зареєструвати всі потрібні страховій компанії свідчення про заяву (СВІДЧЕННЯ
ПРО ЗАЯВУ), включаючи всі детальні свідчення про треті сторони (СТОРОННІ ЮРИДИЧНІ
ОСОБИ) і свідків (ФІЗИЧНІ ОСОБИ).
Вивчити страховий поліс (ПОЛІС) на предмет наявності виключень (ВИКЛЮЧЕННЯ) і
визначити, чи діють ці виключення у випадку даної заяви (ЗАЯВА).
Якщо є виключення, то закрити заяву і скласти стандартний лист заявнику про відмову у
виплаті (ЛИСТ) заявнику (ЗАЯВНИК).
Якщо ніяких виключень немає, то змінити статус заяви на очікування оцінки, назначити і
повідомити оцінника (ОЦІННИК). "
З прикладу видно, які сутності предметної області беруть участь у виконанні функції
(виділені в дужках), як міняється стан сутності (виділено курсивом) і який алгоритм роботи
цієї функції.
З прикладу ясно, що на цьому етапі проектувальник бази даних у якості вхідних даних
використовує також інформаційну модель предметної області бази даних (опис сутностей).
При виконанні аналізу функцій корисно мати якусь таблицю (матрицю) "Функція-Сутність".
Ця матриця повинна дати відповідь на такі питання:
 чи є у кожної сутності конструктор (функція, яка створює всі екземпляри сутності);
 чи є у неї деструктор (функція, яка видаляє екземпляри сутності);
 чи є ссилка на цю сутність (функції, які використовують цю сутність і яким чином)

Процес аналізу взаємодії функції і сутності прийнято визначати


абревіатурою CRUD (Create, Reference, Update, Delete – створення, ссилка, модифікація,
видалення).
Корисними для розуміння проектувальником бази даних призначення функцій і того, як дані
функції беруть участь в процесі обробки даних в системі, можуть бути діаграми потоку даних
і діаграми життєвих циклів сутностей, які були розглянуті нами у другій лекції. Вони дають
ясну картину змін стану сутності, що важливо у визначенні атрибутів статусу сутності.
Відображення функцій в модулі
Однією із основних задач проектування модулів застосувань є побудова відображення
функцій в модулі. При вирішенні цієї задачі проектувальник бази даних повинен
акцентувати увагу на структурі бази даних, яка складає основу додатка.
Як правило, вирішення задачі відображення функцій в модулі вирішується в чотири етапи:
1. Аналіз роботи функції.
2. Побудова моделі сутностей, яка підтримує ці функції.
3. Почати проектування фізичної структури зі створення схеми, яка підтримує
розроблену модель сутностей.
4. Завершити проектування розробкою специфікацій модулів, які реалізують функції
на запропонованій схемі бази даних.

Із запропонованого вище підходу видно, як тісно переплітаються в процесі проектування


процеси розробки фізичної моделі бази даних і специфікацій модулів застосувань. Таким
чином, якщо проектувальником був розроблений чорновий варіант фізичної моделі бази
даних по алгоритмам, розглянутим нами в попередніх лекціях, то на цьому етапі він повинен
бути адаптований до реалізації функцій і, можливо, значно перероблений.
На жаль, ніяких уніфікованих і простих способів відображення функцій в модулі застосувань
не існує. Це зумовлено двома обставинами: комбінаторною складністю побудови
відображення множин (теоретично доведено, що для такого класу комбінаторних задач не
існує в загальному випадку алгоритмів з лінійною збіжністю) і складністю вироблення
критерію того, що отримане відображення оптимальне (тобто достатньо широка семантична
довільність в обґрунтуванні варіантів того чи іншого відображення). Як показує досвід
проектування, думка щодо складу і кількості модулів застосувань в процесі проектування
міняється не однократно.
Останнім часом хороші результати в розробці і проектуванні систем (включаючи модулі
застосувань) отримані за допомогою використання об’єктно орієнтованого підходу на основі
уніфікованої мови моделювання UML і CASE-інструментарію, який ця мова підтримує. Однак
розгляд цієї методики розробки систем представляє собою предмет окремого курсу, і тут
викладатися не буде. В списку літератури до лекції вказані монографії і підручники по цій
популярній методиці.
При відображенні функцій в модулі необхідно отримати схему, яка ставить у відповідність
кожній функції певний модуль.
Наприклад. Розглянемо нашу учбову базу даних, яка містить інформацію про співробітників,
відділи і проекти організації. Припустимо, вона буде підтримувати бізнес-функцію
"Управління проектами в організації". Функціональна модель предметної області бази даних
в термінах ієрархії функції та перелік функції управління проектами в організації.

<

Ієрархія бізнес-функції "Управління проектами в організації"


Перелік функції управління проектами в організації
Завдання полягає у відображенні функцій із переліку у список модулів.
Спочатку із переліку функцій повинні бути видалені ті функції, які не будуть підтримуватися
додатком бази даних. Проектувальник взнає у керівника проекту, що в додатку бази даних
не будуть підтримуватися такі функції:
 призначити куратора проекту;
 повідомити керівників підрозділів;
 повідомити співробітників;
 зібрати нараду;
 приступити до виконання;
 скласти список робіт;
 визначити об’єм робіт;
 визначити вартість робіт;
 визначити час робіт;
 визначити виробничі потужності;
 розподілити виробничі потужності;
 розподілити роботи по співробітниках;
 контролювати хід виконання проекту.

Таким чином отримаємо список функцій, який показаний в лівій колонці таблиці. Цьому
списку функцій повинен бути поставлений у відповідність список модулів застосувань бази
даних.

Таблиця 14.1. Списки функцій и модулів


Функції Модуль

Призначити керівника проекту Введення інформації про проект

Визначити бюджет проекту Введення інформації про співробітників

Визначити список підрозділів Пошук інформації про співробітників

Визначити список співробітників Пошук інформації про проекти

Виконувати проект Генерація звіту про виконані проекти

Здати проект Генерація звіту про проекти, що виконуються

Керівник проекту передав проектувальнику бази даних характеристику додатку до бази


даних по управлінню виконанням проектів в організації. Цей застосування буде займатися
обліком виконаних проектів і проектів, що виконуються в організації. Головними питаннями
на які повинен давати відповідь застосування є:
 Які проекти виконуються в організації?
 Які співробітники в яких проектах беруть участь?
 Якими проектами хто керує?
 Які проекти виконувались в організації?
 Які співробітники в яких проектах брали участь?
 Якими проектами хто керував?

Проектувальник бази даних склав список модулів застосувань бази даних (права колонка
таблиці) і встановив відображення функцій в модулі, як показано на рисунку.

Відображення функцій в модулі


Наведений приклад показує загальний принцип побудови відображення бізнес-функцій в
модулі.
У доповненні буде дуже корисним до розробленої схеми "функції-модулі" скласти схему
"модулі-дані", опираючись на вивчення певних функцій.
При складанні схеми "модулі-дані" використовується опис функцій, логічна модель даних
або ітерація фізичної моделі даних.
Наприклад. Розглянемо модуль "Введення інформації про співробітників" з попереднього
прикладу і складемо для нього схему "модулі-дані". При цьому ми використовуємо схему
бази даних наведену на рисунку

Фізична модель бази даних


Один із можливих результатів, які може отримати проектувальник бази даних, наведено в
таблиці .
Таблиця 14.2. Фрагмент схеми "модулі-дані"

Модуль Таблиця Колонки Стан колонки

Введення інформації про співробітників Employee Empno Зчитування

Ename Зчитування, Пошук

Lname Зчитування, Пошук

Job Зчитування

Sal Зчитування

Depno Зчитування, Пошук

Department Depno Зчитування, Пошук

Manager Зчитування

Системні модулі
Як було вказано раніше, ціль проектувальника модулів – реалізація функціональних
можливостей, які задовольняють бізнес-вимоги, викладені в функціональній моделі
предметної області бази даних. Проте при цьому необхідно розглянути достатню кількість
процесів, які не витікають безпосередньо із сформульованих бізнес-функцій. Наприклад,
можливість видачі результатів роботи модуля у файл чи на принтер.
Набір модулів застосувань бази даних, який не витікає безпосередньо з бізнес-функцій, але
необхідний для забезпечення роботи системи, називається системним.
До таких модулів можна віднести процедури резервного копіювання і автоматичного
відновлення, модулі, які надають користувачам можливість змінювати свій пароль, модулі
друку, модулі навігації по додатках бази даних і т.д.
Проектувальник бази даних самостійно розробляє специфікації таких модулів.

Розміщення логіки обробки


Складність вирішення завдання проектування модулів також обґрунтована і тим, що
проектувальник баз даних повинен виділити зі всього коду, який планується, серверний
код, створення якого обговорювалося в одній із попередніх лекцій. При цьому варто
дотримуватися таких простих правил:
 Задіяти як можна більше обмежень на колонки реляційних таблиць для реалізації
правил обробки даних без процедурного коду.
 Задіяти тригери бази даних для процедурного вводу правил обробки даних, а саме
для підтримки ссилкової цілісності даних.
 Задіяти збережені процедури для інкапсуляції загальних бізнес-функцій.
 Використати вимоги продуктивності при прийнятті остаточного вибору про
розділення коду.

В цьому розділі ми розглянемо деякі фактори, які повинні враховувати проектувальники баз
даних при розмежуванні управління інтерфейсом застосувань користувача і виконання
операцій обробки даних в модулях.
Як відзначають спеціалісти в області розробки і проектування інформаційних систем, багато
недоліків в прикладних системах викликані тим, що в них не визначені
розбіжності між правилами для даних, правилами для процесів і правилами для
інтерфейсу. Розглянемо основні з них.
Правила для даних. В правилах для даних формулюються умови, які повинні задовольняти
дані. Ці правила діють для кожного екземпляра даних і виводяться із моделі даних.
Приклади правил для даних:
 Стать людини має бути або чоловічою, або жіночою. Це правило може бути введене
за допомогою обмеження CHECK у визначенні колонки таблиці бази даних.
 Кожне замовлення має бути призначене для одного і тільки одного покупця. Це
правило для даних може бути введене за допомогою
обмежень PRIMERY KEY або NOT NULL

Правила для процесів. В правилах для процесів визначається, що може (і що не може)


робити застосування. Ці правила зазвичай виводяться із моделі функцій.
Приклади правил для процесів:
 Розмір заробітної плати не повинен перевищувати 160000 рублів. Це правило
потрібно реалізувати в додатку, в ньому нічого не сказано про вміст і визначення
бази даних. Воно виражає твердження про те, що може бути, а чого не може бути.
 Тільки керівник може санкціонувати виплату преміальних. В момент санкціонування
платежу застосування повинен перевірити наявність у користувача необхідних прав,
тобто чи є він керівником.

Правила для інтерфейсу. В правилах для інтерфейсу встановлюється, яким повинен бачити
користувач застосування. Ці правила не стосуються обробки, а лише впливають на
уявлення користувача про застосування бази даних. Ці правила виводяться в специфікації
інтерфейсу користувача.
Приклади правил для інтерфейсу:
 Всі коди валют повинні бути пояснені. Це специфікація замовника до візуалізації
кодів валют.
 Номера відділів і підрозділів не мають показуватися. Це також є вимогою замовника
системи відносно візуалізації даних в додатку.

Деякі сформульовані правила бувають складеними, а їх частини відносяться до різних груп


правил. Наприклад, розглянемо правило:
Всі торгівельні операції, які проводяться в неділю, враховуються в бухгалтерських книгах
станом на наступний понеділок.
Це два правила. Перше стверджує, що торгівельні операції не можуть враховуватися в
бухгалтерських книгах станом на неділю. Це правило для даних. Друге пояснює додатку як
відкоректувати дату торгівельної операції, щоб вона стала задовільною. До дати, яка
випадає на неділю, потрібно додати одиницю. Це правило для процесів.
Виділення і аналіз цих трьох груп правил приводить до формування трьох наборів
документів: опис структури інтерфейсу, структура процесів, яка визначає, як повинен бути
реалізований інтерфейс, і структура даних, яка задає основні об’єкти бази даних, з якими
працюють процеси.
Ці документи відіграють важливу роль як у визначенні і логіці, і її розміщенні у додатку, так
і у складенні специфікацій модулів застосувань бази даних.
Коротко розглянемо основні принципи розміщення бізнес-логіки у модулях додатку бази
даних.
Правила для інтерфейсу реалізуються на зовнішній (клієнтській) частині системи,
незалежно від того, які мови програмування чи генератори звітів
використовуються. Правила для процесів реалізуються у вигляді процедур, які
викликаються із клієнтської частини системи. Вони можуть являти собою серверний код або
бути реалізованими у вигляді модулів чи бібліотек на сервері застосувань. Правила для
даних реалізуються самою базою даних у вигляді обмежень або тригерів.
Загальні принципи розробки специфікацій модулів
Після розробки схеми "функції-модулі" і схеми "модулі-дані" проектувальник приступає до
вирішення досить трудомісткого завдання – написання специфікацій модулів. Саме ця
специфікація дозволить програмістам і компонувальникам побудувати реальну систему з
використанням бази даних.
При написанні специфікацій варто виходити з того, що людина, яка буде писати код, вміє
це робити. Тому зі специфікацій потрібно за можливістю видалити усі вказівки по тому, як
потрібно, на вашу думку, писати код. Це є наслідком із практичного міркування, що ніхто
не може створити правильний код без його тестування. Оскільки проектувальник бази
даних, як правило, не збирається писати код, то йому в його специфікації не варто
диктувати структуру реального коду.
Алгоритми, навіть дуже складні, варто формулювати у загальному вигляді. Потрібно
намагатися уникати формальних мов опису алгоритмів.
Також не варто вставляти в специфікації модулів команди SQL. В процесі тестування
адміністратор бази даних може змінити розроблену проектувальником бази даних фізичну
модель бази даних і, відповідно, команди можуть змінитися.
Варто уникати зайвих інструкцій в специфікаціях. Наприклад, не варто пояснювати
програмістам, що вони повинні вийти із циклу за виняткових обставин.
Специфікація модуля обов’язково повинна включати:

 Умовну назву модуля.


 Функції, виконання яких забезпечує даний модуль.
 Список таблиць і колонок, до яких здійснюється доступ.
 Для кожної колонки – спосіб використання колонки, а саме,
запитуються, вставляються, видаляються чи обновляються дані вказаних колонок.
 Список колонок, які використовуються в предикатах пошуку.
 Конкретний опис того, що модуль має робити.

Наприклад. Наведемо типову специфікацію модуля для надання користувачу доступу до


додатку бази даних.
Ім’я модуля: Сторінка для входу в застосування (LogIn)
Ціль: ідентифікація користувача и надання доступу до додатку бази даних.
Вхідні дані
Ім’я користувача
Пароль
Таблиця бази даних: USERACCOUNT
Колонки:
USERNAME – запитується, використовується в предикаті пошуку
USERPASS – запитується, використовується в предикаті пошуку
Дії:
Якщо користувача з таким ім’ям і паролем немає в базі даних - відмовити в доступі і
попросити правильно ввести свої дані (на випадок помилки), але не більше трьох раз.
Якщо користувач є в базі даних - надати доступ до модулю "Головна сторінка", яка в
залежності від повноважень користувача може мати різний вигляд.
Коментарій:
В залежності від типу модуля (екранна форма, звіт і т.д.), специфікації можуть включати
додаткову інформацію, таку як вимоги до розміщення кнопок або формат звіту. Для таких
модулів специфікацію варто доповнити такими позиціями:
 дані про навігацію (який модуль викликає, і які модулі викликаються);
 значення вхідних параметрів по замовчуванню;
 список подій, який обробляється на екранній формі, і як вони обробляються;
 список помилок і дій, пов’язаних з їх обробкою;
 дані про безпеку;
 макет екранної форми або шаблон звіту.

Наприклад. В якості прикладу наведемо специфікацію екранної форми для роботи з базою
даних через браузер.
Ім’я екранної форми: Web-сторінка Форма 3: Список виконавців.
Ціль: приписати виконавців до проекту, визначити їх зайнятість і статус.

Вхідні дані
 Номер проекту

Навігація:
Викликається із модуля "Редагування Форми 1".
Повертає управління в модуль "Редагування Форми 1".
Дії:
 Вибрати зі списку виконавця
 Визначити його статус - основний, неосновний, керівник
 Визначити зайнятість виконавця
 Зберегти запис про виконавця
 Перейти на введення даних про наступного
 Повернутись на Редагування Форми 1.

Таблиці:
Таблиця tblProjEMP

Ім’я поля Зміст Використання


ENPID Внутрішній номер службовця INSERT

PROJID Внутрішній номер проекту INSERT

TN табельний номер (з представлення)

NM ПІБ INSERT

PS Посада

GR Розряд

DR Науковий ступінь

ZV Вчене звання

JOB Зайнятість у проекті в міс. INSERT

EMPSTATUS Статус виконавця INSERT

Таблиця tblEmpl

Ім’я поля Зміст Використання

ENPID Внутрішній номер службовця

TN табельний номер (з представлення)

NM ПІБ Предикат пошуку

PS Посада

GR Розряд

DR Науковий ступінь

ZV Вчене звання

Вимоги до макету сторінки:


 Повинен бути розкривний список, який містить ПІБ співробітників, з якого
здійснюється вибір співробітника для участі в проекті.
 Кнопка, яка ініціює збереження даних в таблиці бази даних, повинна бути розміщена
зверху і знизу сторінки.

 Повернення у викликаючий модуль повинен відбуватися через кнопку, розміщену
зліва зверху сторінки.

Помилки:
Повторне введення даних форми в базу даних вважається помилкою. Повинні
бути передбачені дії, які блокують повторне введення даних форми.
Як видно з обговорення і наведених прикладів, хороша специфікація
модуля повинна повідомити всім, що цей модуль повинен робити, а не як саме він повинен
це робити. Виділене курсивом слово "всім" означає не тільки безпосередніх учасників
проекту (керівника, програмістів, компонувальників і тестувальників), але також і
аналітиків, керівників вищої ланки, представників замовника.
Проектування процесу тестування модулів застосувань
Тестування додатку бази даних є одним із основних елементів підготовки і проведення
приймально-здавальних випробувань. Як показує практика, планування тестування
застосувань бази даних повинно починатися ще на стадії аналізу. Існує імовірність того, що
замовник може відмовитись від раніше прийнятих критеріїв випробувань в процесі
виконання проекту. Проте частіш за все планування тестування відкладають до етапу
проектування, і, таким чином, складання плану тестування стає завданням
проектувальника бази даних чи адміністратора бази даних.
В процесі тестування повинно бути з’ясовано, що застосування бази даних робить те, що
від нього вимагається, тобто відповідає сформульованим вимогам приймально-здавальних
випробувань.
Як правило, в процесі проектування проектувальник бази даних пропонує стратегію (чи
план) комплексного і системного тестування. При розробці стратегії тестування варто
пам’ятати про те, що повинні використовуватися тести таких категорій:
 Автономні тести (тести модулів).
 Тести зв’язків модулів.
 Системний тест для додатку бази даних в цілому.
 Приймально-здавальні випробування (які може проводити замовник).
 Тести продуктивності.

Зазвичай після проведення приймально-здавальних випробувань підписується акт


приймання-здачі. Вважається, що система переходить у стан дослідної експлуатації, під час
якої виявляються і виправляються помилки. Після закінчення стадії дослідної експлуатації
система переходить в стан промислової експлуатації, тобто стає виробничим ресурсом
компанії.
Як правило, тести і їх проведення плануються для задоволення вимог приймально-
здавальних випробувань. Тому розробку стратегії тестування варто починати з детального
вивчення цих вимог.
Планування тестування застосувань бази даних залежить від стандартів і методик розробки
інформаційних систем з базами даних, які використовуються всередині організації. Такі
методики відрізняються як за своїм підходом до розробки систем, так і по складу проектної
документації. Так, наприклад, методики розробки, які пропонують компанії Microsoft і IBM,
відрізняються по складу проектної документації, хоча багато в чому вони схожі за
методологічною основою (об’єктно-орієнтованому підходу).
Розглянемо підхід, який ґрунтується на модулі проектної групи Модель MSF версії 3.1,
запропонований компанією Microsoft. У цій методиці передбачений так званий рольовий
кластер "Тестування".

Завдання рольового кластера "Тестування" (test) - схвалення випуску продукту тільки після
того, як всі дефекти виявлені и улагоджені. Будь-яке програмне забезпечення містить
дефекти. Виявлення і усунення дефектів може означати різні рішення, починаючи від
усунення і закінчуючи документуванням способів обходу дефекту. Поставка продукту з
відомим дефектом, але з описом способів його обходу є кращою, ніж поставка продукту з
невиявленим дефектом, який в подальшому стане сюрпризом - як для проектної команди,
так і для замовника.
Щоб досягти успіху, команда тестувальників повинна сфокусуватися на певних ключових
завданнях. Вони структуруються у вигляді трьох областей компетенції.
1. Планування тестів:
o розробка методології і плану тестування;
o участь у встановленні стандарту якості (quality bar);
o розробка специфікацій тестів.
2. Розробка тестів:
o розробка і підтримка автоматизованих тестів (automated test cases),
інструментів і скриптів;
o проведення тестів з ціллю визначення стану проекту;
o управління білдами (manage the build process).
3. Звітність про тести:
o доведення до відома проектної групи інформації про якість продукту;
o моніторинг знайдених помилок з метою забезпечення їх залагодження до
випуску продукту.

Планування тестів. Ця область компетенції (планування тестів - test planning) рольового


кластера "Тестування" формулює методологію надходження і врегулювання проблем якості
продукту.
Команда тестувальників розробляє плани і методики тестування і таким чином формує
стратегію, яка буде використовуватися в проекті для тестування рішення. Плани тестування
включають в себе опис типів тестів, складових, що тестуються, та інформацію про необхідні
ресурси (як людські, так і технічні).
Велика частина роботи даної області компетенції полягає в участі у виробленні необхідного
рівня якості (quality bar) продукту. Ця діяльність включає в себе надання проектній групі
метрик контролю якості і критеріїв успішності рішення.
Ще один рід діяльності, який виконується даною областю компетенції, полягає у розробці
специфікацій тестів. Його суть - в детальному описі інструментарію і програмного коду,
необхідних для виконання плану тестування.
Розробка тестів. Ця область компетенції (розробка тестів - test engineering) відповідальна
за передбачені планом тестування заходи, направлені на знаходження і врегулювання всіх
проблем якості продукту, що створюється. В тому числі - робота по створенню і підтримці
тестових сценаріїв (test cases), розробка засобів, скриптів і документації процесу
тестування, управління щоденними білдами (daily builds), проведення над ними тестів з
метою чіткого визначення рівня завершеності продукту.
Звітність про тести. Дана область компетенції (звітність про тести - test reporting) забезпечує
проектну групу інформацією про поточні вади в рішенні, так само як і про досягнуті успіхи.
Завдяки цьому проектна група має чітку картину поточного стану розробки.
Щоб всі знайдені проблеми були вирішені до остаточного випуску продукту, проводиться їх
моніторинг (tracking). Регулярно здійснюється документування стану проблем (включаючи
завдання по їх вирішенню, пріоритети, методи врегулювання і можливі шляхи їх обходу),
що дозволяє проектній групі постійно мати поточні дані про якість продукту і детальний
аналіз тенденцій його зміни.
Таким чином, при розробці стратегії (або загального плану тестування) проектувальник
повинен опиратися на прийняті в організації стандарти розробки систем. Якщо він
грунтується в своїй роботі на використанні моделі проектної групи MSF, то повинен
формулювати пункти стратегії тестування відповідно до вищевикладених вимог по
організації роботи рольового кластера "Тестування".
На закінчення розділу розглянемо деякі практичні поради проектувальникам баз даних при
розробці стратегії тестування.
Стратегія тестування – це план проведення робіт по тестуванню системи або її модуля, який
враховує специфіку функціональності і взаємозалежності з іншими компонентами системи і
платформи. Стратегія визначає типи тестів, які потрібно виконувати для даного функціонала
системи, включає опис необхідних підходів з точки зори цілей тестування і може задавати
описи або вимоги до необхідних для проведення тестування інструментів та інфраструктури.
Стратегія тестування повинна відповідати на такі питання:
 Як, яким чином тестування дасть відповідь, що даний функціонал працює?
 Що потрібно зробити і чим скористатися з інструментальних засобів, для досягнення
цілей тестування?
 Коли певний функціонал буде тестуватися і, відповідно, коли очікувати отримання
результатів?

В якості додаткового завдання, яке вирішується в процесі розуміння стратегії тестування,


можна розглядати завдання мінімізації затрат на тестування.
Зі стратегії тестування органічно виписується план тестування. Шаблони планів тестування,
які пропонуються різними методологіями, часто напряму включають одним із розділів опис
стратегії тестування або ж включають опис стратегії в пункти плану, які відповідають за
тестування конкретних частин функціоналу. Наприклад, шаблон методології Rational Unified
Process визначає стратегію тестування, як найбільший розділ плану тестування.
Замовник часто хоче контролювати процес тестування і бачити розуміння завдання
тестування виконавцями проекту. Для нього стратегія тестування – це менш детальний
документ-бачення того, як буде тестуватись система в процесі розробки.
При розробці стратегії тестування для розподіленої системи з базою даних проектувальнику
бази даних потрібно виділити основні області, які можуть тестуватися окремо один від
одного. Для тестування складних систем також корисно виділяти не тільки оперативні кроки
тестування (тобто що, як і де буде тестуватися), але і проводити аналіз тактичних кроків
тестування з врахуванням розвитку системи в часі.
Наприклад. Проведемо орієнтовну розбивку функціональності на тестові області для того,
щоб зрозуміти, як спланувати тестування і мінімізувати витрати.
Нехай система має "товстого" клієнта, сервер застосувань і сервер бази даних, які можуть
функціонувати на різних фізичних платформах. Основна логіка вводу/виводу, перевірки
даних і побудови звітів сконцентрована на клієнті, сервер застосувань забезпечує необхідну
сервісну логіку (автоматична архівація даних, повідомлення користувачів про позаштатні
ситуації і т.д.), а база даних забезпечує, окрім безпосереднього зберігання даних, певну
частину обробки даних, яка реалізується, наприклад, у вигляді пакетів функцій.
Для простоти припустимо, що система має фіксовану конфігурацію для сервера бази даних
і сервера застосувань. Клієнтський застосування працює під двома операційними системами
зі строго фіксованою конфігурацією компонентів. Як правило, завдання тестування
формулюється на мові тестових сценаріїв, тобто для оцінки трудомісткості завдання або його
частини використовується кількість тестів, необхідних для перевірки працездатності
функціонала.
Клієнт: 50 тестів на роботу з даними (введення форм, розрахунок даних на основі даних,
які зберігаються в словниках, пошук даних, редагування словників і т.д.), 10 тестів на
роботу з формами друку (формування періодів вибірок, вибір типів звітів, друк або експорт
в передбачений список форматів і т.д.). Нехай для тестування роботи з системою потрібно
ще 5 тестів. Для перевірки функціональності, пов’язаної із самою операційною системою,
буде потрібно (5 + 10)*2 = 30 тестових прогонів. Будемо вважати, що 50 тестових прогонів
буде достатньо для перевірки логіки роботи з даними. Підсумок - 80 тестових прогонів для
тестування клієнта системи.
Об’єднаємо в рамках прикладу, що розглядається тестування функціональності сервера
застосувань і бази даних. Нехай сервер застосувань реалізує 20 команд по обробці даних і
сесій користувачів (без врахування роботи з системними пулами з’єднань; функцій
стиснення трафіку, який передається по мережі і т.д.). Сервер баз даних реалізує 10
системних операцій архівації даних, побудови статистики використання звітів і ще кілька
схожих операцій. Загальний зміст полягає в тому, що ми маємо остаточний набір операцій,
що тестуються, і так як конфігурації визначені заздалегідь, можемо говорити про остаточний
набір тестів, які необхідно виконати, щоб перевірити дієздатність серверного функціонала
системи. Підсумок – 30 тестів на серверній стороні. Зауважимо, що в даному прикладі ми не
говоримо про навантажувальну складову тестування: мова йде лише про функціональне
тестування.
При розробці стратегії тестування проектувальник бази даних повинен враховувати, що,
плануючи тестування, він не починає розбиратися із системою, а займається безпосередньо
плануванням, виділенням ресурсів і термінів на конкретні завдання.
Тестування інформаційних систем є прикладною наукою, що бурхливо розвивається.
Практика показує доцільність застосування CASE-засобів для організації і проведення
тестування. У списку літератури до лекції вказані джерела, які варто використовувати для
поглибленого вивчення розробки планів тестування застосувань баз даних.
На цій лекції ми завершили обговорення основних завдань проектувальника бази даних, які
він повинен обов’язково виконати (побудова логічної, фізичної моделі даних, підготовка
скрипту для створення бази даних і документування моделі), і у вирішенні яких його участь
дуже бажана (планування модулів застосувань, планування тестування).
На двох останніх лекціях ми розглянемо задачі управління змінами у структурі бази даних
(або завдання зворотного впливу), які можуть вимагати безпосередньої участі
проектувальника бази даних.

Розробка прикладного
програмного
забезпечення для бази
даних

The Big Picture


Server-side development

Програмне забезпечення на стороні сервера (server-side


development), це об'єкти,
які розробляються і зберігаються в базі даних.

Сюди відносяться:

 Збережені процедури (Stored Procedures)
 Визначені користувачем функції (User-defined
Functions або UDFs))
 Тригери (Triggers)

Stored procedures
Збережені процедури є об'єктами СУБД, які можуть
інкапсулювати SQL запити і бізнес-логіку.

Збереження частини логіки застосування в базі даних


може
- поліпшити продуктивності роботи
- зменшити обєм мережевого трафіку між застосуванням
і базою даних.
- визначити єдине місце збереження коду логіки

Для виклику використовується запит CALL.

Писати можна з використанням різних мова, включаючи:


SQL PL, PL/SQL, Java, C/C++, CLR, OLE, and COBOL

db2 create procedure P1 begin end


db2 call P1

User-defined functions
Визначені користувачем функції (UDF) є об'єктами бази
даних, які дозволяють користувачам розширити SQL
мову.

Функція завжди повертає одне або декілька значень.


Зазвичай реалізує якусь бізнес-логіку.

Щоб викликати функцію, її назва використовується в


межах SQL запиту.

Розробляти на декількох мовах, у тому


числі SQL PL, PL / SQL, Java, C / C + +, OLE DB, CLR.

db2 create function F1() returns integer


begin return 1000; end
db2 values F1
Triggers
Тригер це об'єкт, який автоматично виконує операцію
над таблицю або представленням.
Виконання дії над об'єктом, для якої визначений тригер
призводить до виклику (fire) тригера.

Приклад тригера

create trigger myvalidate no cascade before insert


on T1
referencing NEW as N
for each row
begin atomic
set (N.myxmlcol) = XMLVALIDATE(N.myxmlcol
according to xmlschema id myxmlschema);
end

Client-side development
Розробка клієнтської частини (Client-side
development), це написання застосувань, які
запускаються на стороні клієнта,
а потім отримують доступ до бази даних за допомогою п
рограмних інтерфейсів (API).

Найбільш типові мови та технології, що


використовуються:
 Embedded SQL
 CLI та ODBC
 JDBC та SQLJ
 OLE DB
 ADO.NET
 ORM
Embedded SQL
Вбудований SQL (Embedded SQL), де SQL запити, що
включені в синтаксис мови програмування, такі як C, C
+ + або COBOL.

Застосування вбудованого SQL може включати в себе


статичний або динамічний SQL.

Static SQL vs Dynamic SQL


Статичні SQL (Static SQL) запити це SQL запити,
структура яких повністю відомі під час в прекомпіляції
коду.

SELECT lastname, salary FROM employee (1)


SELECT lastname, salary FROM employee WHERE
firstnme = :fname (2)

SELECT ?, ? FROM ? (3)

Якщо імена стовпців і таблиць, на які посилається запит


не відомі до моменту виконання то такі запити
називаються динамічними SQL (Dynamic SQL) запитами.

CLI and ODBC


Інтерфейс рівня викликів (Call Level Interface , CLI) був
розроблений компанією X / Open Company і групою SQL
Access.
Це специфікації для викликає SQL запитів з метою
розробки переносимого коду на
C/C++ незалежно від постачальника СУБД.

На основі CLI, корпорація Microsoft розробила Open


Database Connectivity (ODBC).
CLI / ODBC має наступні характеристики:
 код легко переносити між декількома
постачальниками СУБД
 На відміну від вбудованого SQL,
немає необхідності прекомпілятора
 Працює з динамічним SQL
 Досить поширений

Для розробки програм з


використанням CLI/ODBC необхідно встановити драйвер
(наприклад DB2 CLI driver) та відповідні бібліотеки

Для запуску, на клієнті має бути встановлений драйвер.


JDBC та SQLJ
Java Database Connectivity (JDBC) є Java API, що
стандартним способом роботи і доступу до баз даних.
- JDBC коду легко переносити між декількома
постачальниками СУБД.
- Вимагає JDBC драйвер для завантаження
- використовує тільки динамічний SQL
- дуже популярний.
SQLJ є стандартом для вбудованого SQL в програмах
Java.
- в основному використовується зі статичним SQL,
- може взаємодіяти з JDBC
- як правило, більш компактний, ніж JDBC
- забезпечує більш високу продуктивність,
- повинен бути запущений через препроцесор
(SQLJ translator)

OLE DB
Object Linking and Embedding, Database (OLE DB)
являє собою набір інтерфейсів, що забезпечують доступ
до даних, що зберігаються в різних джерелах. Він був
розроблений в якості заміни ODBC та розширений для
підтримки більшої кількості джерел інформації, у тому
числі й не реляційних баз даних
OLE DB реалізований з використанням COM технології.

Component Object Model (COM) технологічний


стандарт від Microsoft, що передбачає створення
програмного забезпечення на основі взаємодії
компонентів, кожен з яких може використовуватися у
багатьох програмах одночасно.

ADO.NET
ActiveX Data Objects (ADO) - об'єкти даних ActiveX
прикладний програмний інтерфейс для доступу до
даних, розроблений компанією Microsoft і заснований на
технології компонентів ActiveX. ADO дозволяє
представляти дані з різноманітних джерел: (реляційної
СУБД, текстових файлів тощо) в об'єктно-орієнтованому
програмуванні виді.

ActiveX - є основою для визначення повторно


використовуваних компонентів програмного
забезпечення незалежно від мови програмування.
Програмні застосування можуть складатися з одного або
кількох компонентів з метою забезпечення їхньої
функціональності

ADO.NET це спосіб забезпечення доступу до даних


(data provider) в .NET Framework.

.NET Framework є заміною від Microsoft для COM


технології.

ORM
Object-relational mapping ( Об'єктно-реляційна
проекція) технологія програмування, яка зв'язує бази
даних з концепціями об'єктно-орієнтованих мов
програмування, створюючи віртуальну об'єктну базу
даних.

Hibernate засіб відображення між об'єктами та


реляційними структурами для платформи Java. Hibernate
є вільним програмним забезпеченням, яке поширюється
на умовах GNU

Java Persistence API стандартизований інтерфейс


для Java ORM фреймворків. Є частиною EJB3 та J2EE 5,
хоча може використовуватись незалежно від них.
Виник в результаті бажання мати незалежний від
конкретної реалізації стандарт.

pureQuery - високопродуктивний доступ до


даних від IBM спрямований на спрощення
розробки та забезпечення управління та оптимізації
нових та існуючих застосувань для доступу
до даних. Підтримує як Java так. NET.

ADO.NET Entity Framework (EF) - об'єктно-


орієнтована технологія доступу до даних
для. NET Framework від Microsoft. Надає можливість
взаємодії з об'єктами як за допомогою LINQ в
вигляді LINQ to Entities, так і з
використанням Entity SQL.

Розробка прикладного
програмного забезпечення для
роботи з СУБД на мові Java
The big picture

Переконатися в наявності
- JDK (розробник) або JRE(клієнт)
- коректного налаштувати JDK_PATH та JRE_PATH
- JDBC/SQLJ driver
- коректного налаштування CLASSPATH

Драйвера
Тип Імя драйвера Опис
Type 1 The JDBC-ODBC bridge driver Для доступу використовується O
Type 2 The Native-API driver Вимагає встановлення на ма
програмного забезпечення
інформацією з СУБД
Type 3 The JDBC net pure-java driver Чистий Java клієнт, який бе
сервером використовуючи СУБД
Type 4 The native-protocol pure-java Найбілш гнучкий дравер, який
driver. безпосередні зверення до СУБД
JDBC application using the type 2 driver
JDBC application using the type 4 driver

Програмування з використанням JDBC

Розробка з використанням JDBC включає наступні кроки:


Крок 1 - Зєднатися з БД використовуючи JDBC
Крок 2 - Виконати SQL запити
Крок 3 - Отримати результат
Крок 4 - Обробити помилки SQL та попередження
Крок 5 - Закрити зєднання
Крок 1 - Зєднання з СУБД
Type 2 syntax

(1) import java.sql.*;

class myprg {

public static void main (String argv[]){


try {
Connection con = null;
(2) Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
(3) String url = "jdbc:db2:SAMPLE";
if (argv.length == 2){
String userID = argv[0];
String passwd = argv[1];
(4) con = DriverManager.getConnection(url,userID,passwd);
}
else
{ throw new Exception
("\n Usage: java myprg userID password\n");
}

Drivers:
MySQL com.mysql.jdbc.Driver
MS SQL
Server com.microsoft.jdbc.sqlserver.SQLServerDriver
Oracle DB oracle.jdbc.driver.OracleDriver

Type 4 syntax:

import java.sql.*;

class myprg {

public static void main (String argv[]){


try {
Connection con = null;
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
(1) String url = "jdbc:db2://127.0.0.1:50000/SAMPLE";
if (argv.length == 2){
String userID = argv[0];
String passwd = argv[1];
con = DriverManager.getConnection(url,userID,passwd);
}
else
{ throw new Exception
("\n Usage: java myprg userID password\n");
}

Cинтаксис рядка зєднання


"jdbc:db2://<IP address or hostname>:<DB2 Instance
port number>/<dbname>"

MySQL Jdbc:mysql://<ip>:3306/<dbname>
MS SQL
Server jdbc:Microsoft:sqlserver://<ip>:1433/<dbname>
Oracle jdbc:thin:@<server-id>:1521/dbname

Крок 2 - Виконання SQL запиту

Метод Що створюється Опис


createStatement Statement object Використовується для
виконання SQL
запитів, що не містять
маркерів параметрів
prepareStatement PreparedStatement Використовується для
object виконання запитів,
що містять маркер
параметрів
prepareCall CallableStatement Використовується для
object виклику
збережуваних
процедур

Приведення Java типів до типів СУБД


The Statement interface
Метод Опис
executeQuery Використовується, коли в якості результату
очікується множина кортежів (SELECT)
executeUpdate Використовується, коли в якості результату
очікується ціле число
(INSERT, UPDATE, DELETE)
execute Використовується, коли результат виконання
не відомим до моменту запуску програми

Виконання SELECT з використанням executeQuery


try {
(1) Statement stmt = con.createStatement();
(2) ResultSet rs = stmt.executeQuery
("SELECT EMPNO, FIRSTNME, LASTNAME " +
" FROM EMPLOYEE " +
" WHERE SALARY > 80000" );
(3) while ( rs.next() ) {
System.out.println("Empno = " +
rs.getString(1) +
" Full name = " +
rs.getString(2) +
" " + rs.getString(3));
}
(4) rs.close();
(5) stmt.close();
(6) con.close();
} catch (Exception e) {
e.printStackTrace();
}

Виконання UPDATE з використанням


executeUpdate
Statement updStmt = con.createStatement();
(1) int numRows = updStmt.executeUpdate
("UPDATE EMPLOYEE " +
" SET FIRSTNME = 'Raul', " +
" LASTNAME = 'Chong' " +
" WHERE EMPNO = '000010' ");
System.out.println("Number of rows updated " +
numRows);

Виконання INSERT з використанням executeUpdate


String query = null;
query = "INSERT INTO employee (EMPNO, " +
"FIRSTNME, LASTNAME, EDLEVEL,
SALARY)" +
"VALUES ('099999', 'Jin', 'Xie',
25, 90000)";
Statement stmt = con.createStatement();
int numRows = stmt.executeUpdate( query );
System.out.println("Number of rows inserted: " +
numRows);
stmt.close();

Виконання DELETE з використанням executeUpdate


String query = null;
query = "DELETE FROM employee where empno =
'000999'";
Statement stmt = con.createStatement();
int numRows = stmt.executeUpdate( query );
System.out.println("Number of rows deleted: " +
numRows);
stmt.close();

Виконання SELECT чи UPDATE з використанням


execute
String passedStmt = "SELECT firstnme, lastname "
+
"FROM employee " +
"WHERE salary > 80000";
Statement stmt = con.createStatement();
ResultSet rs = null;
int numrows = 0;
(1) if (stmt.execute(passedStmt)){
rs = stmt.getResultSet();
while ( rs.next() ) {
System.out.println("Full name = " +
rs.getString(1) +
" " +
rs.getString(2)
);
}
rs.close();
}
else {
numrows = stmt.getUpdateCount();
System.out.println("Number of rows updated:
" + numrows);
}

The PreparedStatement interface


Інтерфейс PreparedStatement наслідує Statement

Класи, що реалізовують інтерфейс PreparedStatement


використовуються для запитів, які можуть містити
маркери параметрів.
Маркер параметра (?), ставиться в динамічних запитах
на місці змінних.

Якщо запит містить маркери параметрів, то значення


параметрів, на які він вказує необхідно встановити
перед виконанням запиту.

Методи мають вигляд setXXX, де ХХХ тип значення


(setInt, setString, setDouble, setBytes, setClob, setBlob)

Після встановлення цих значень можна викликати


методи executeQuery, executeUpdate чи r execute для
виконання запиту

Виконання SELECT з використанням executeQuery

(1) PreparedStatement pStmt = con.prepareStatement


("SELECT firstnme,
" +
" lastname " +
"FROM employee
WHERE salary > ? ");
(2) pStmt.setInt(1,80000);
(3) ResultSet rs = pStmt.executeQuery();
while ( rs.next() ) {
System.out.println("Full name = " +
rs.getString(1) +
" " + rs.getString(2));
}
(4) rs.close();
(5) pStmt.close();

Виконання UPDATE з
використанням executeUpdate
(1) PreparedStatement pStmt = con.prepareStatement
("UPDATE employee "
+
" SET salary = ? "
+
" WHERE empno = ?
");
(2) pStmt.setInt (1,85000);
(3) pStmt.setString(2,"000010");
(4) int numRows = pStmt.executeUpdate();
System.out.println("Number of rows updated:
" + numRows);
pStmt.close();

Виконання SELECT з використанням execute


(1) String passedStmt = "SELECT firstnme, lastname
" +
"FROM employee " +
"WHERE salary > ?";
pStmt.setInt (1,85000);
ResultSet rs = null;
int numrows = 0;
(2) if (pStmt.execute())
{
rs = pStmt.getResultSet();
while ( rs.next() ) {
System.out.println("Full name = " +
rs.getString(1) +
" " +
rs.getString(2)); }
rs.close();
}
else
{
numrows = pStmt.getUpdateCount();
System.out.println("Number of rows
updated: " + numrows);
}
pStmt.close();

The CallableStatement interface


Інтерфейс CallableStatement наслідує PreparedStatement

Використовується для виклику збережуваних процедур.

Мають три типи параметрів:IN, OUT, INOUT


Параметри IN та INOUT мають бути встановлення
через setXXX перед виконанням запиту

Параметри OUT та INOUT мають бути


зареєстровані через registerOutParameter
перед виконанням запиту

Виконання цих запитів можливе з використанням


executeUpdate коли не очікується повернення
результату
executeQuery - коли очікується повернення одиночного
результату
execute коли очікується повернення множини
результатів

Збережувана процедура

view_salary_increase ( IN p_empno varchar(6),


INOUT p_increase int,
OUT p_firstname)

Виклик збережуваної процедури


(1) CallableStatement cstmt;
(2) cstmt = con.prepareCall("call
view_salary_increase(?,?,?)");
(3) cstmt.setString(1,"000010");
(4) cstmt.setInt(2,10000000);
(5) cstmt.registerOutParameter(3, Types.VARCHAR);
(6) cstmt.executeUpdate();
(7) System.out.println(cstmt.getString(3) +
" would receive and increase of " +
cstmt.getInt(2));
(8) cstmt.close();
Якщо збережувана процедура повертає параметри

high_paid_employees (IN p_salary INT))

CallableStatement cstmt;
(1) cstmt = con.prepareCall("call
high_paid_employees(?)");
(2) cstmt.setInt(1,80000);
(3) ResultSet rs = cstmt.executeQuery();
System.out.println("High-paid employees list\n" +
"------------------------");
(4) while ( rs.next() ) {
System.out.println( rs.getString(1) + " " +
rs.getString(2) );
}
rs.close();
cstmt.close();

3 крок - Обробка результатів


В результаті виконаня запиту з використанням методів
обєктів ExecuteQuery, PreparedStatement і
CallableStatement повертається об'єкт ResultSet.

Об'єкт ResultSet це містить курсор, який можна


переміщати на наступний рядок вибірки за допомогою
методу next().
Курсор за замовчуванням можуть бути переміщені тільки
вперед і використовуватися тільки для читання, однак,
можна визначити курсор, який можна прокручувати або
оновлювати.

Значення стовпців поточного рядка (на які вказує


курсов) можна вибрати шляхом виклику гетерів об'єкта
ResultSet.
Якщо всі рядки вибрані, то метод next() генерує
виняток.

Властивості ResultSet,

Властивості Опис
resultSetType Задає можливість прокручування
resultSetConcurrency Задає властивість оновлення
resultSetHoldability Позначає, що вибірка має
залишатися доступною навіть
після закінчення роботи із
запитом

Перевантажені конструктори

createStatement (int resultSetType,


resultSetConcurrency,
resultSetHoldability)

prepareStatement (int resultSetType,


resultSetConcurrency,
resultSetHoldability)

Використання ResultSet

(1) Statement stmt =


con.createStatement(ResultSet.TYPE_SCROL
L_SENSITIVE,
Re
sultSe
t.CONC
UR_UPD
ATABLE
);
(2) ResultSet rs=stmt.executeQuery("Select
POID,Status from purchaseorder");
(3) while(rs.next()) {
int id = rs.getInt(1);
String status = rs.getString(2);
if(id==5003 &&
status.toUpperCase().compareTo("UNSHIPPE
D")==0) {
System.out.println("updating status to
shipped for id value "+

(4) rs.updateString(2,"Shipped");
(5) rs.updateRow();
}
}
(6) rs.beforeFirst();
System.out.println("Printing all the purchase
order record status");
while(rs.next()) {
int id = rs.getInt(1);
String info = rs.getString(2);
System.out.println("id="+id+" info="+ info
);
}

Крок 4 Обробка помилок


SQLException генерується у випадку виникнення
помилки під час доступу до бази даних.
Тип Опис Метод для
інформації отримання
Message Текстовий опис коду getMessage()
помилки
SQLState Стрічка SQLState getSQLState()
ErrorCode Числове значення getErrorCode()
помилки

Якщо генерується декілька помилок, то вони


обєкднуються у вигляді ланцюжка, наступний елемент
якого можна отримати методом getNextException() для
поточного обєкту SQLException.

// code which can throw SQLException go here


} catch (SQLException sqle) {
System.out.println("Rollback the transaction and
quit the program");
System.out.println();

try { con.rollback();}
catch (Exception e) { }

System.exit(1);
}

SQLWarning генерується у випадку виникнення


попереджень зі сторони СУБД при виконанні методів
інтерфесів Connection, Statement, PreparedStatement, Ca
llableStatement, ResultSet.

Усі ці інтерфеси містять метод getWarning().

Statement stmt=con.createStatement();
stmt.executeUpdate("delete from product where
pid='101'");
SQLWarning sqlwarn=stmt.getWarnings();
while(sqlwarn!=null)
{
System.out.println ("Warning description: " +
sqlwarn.getMessage());
System.out.println ("SQLSTATE: " +
sqlwarn.getSQLState());
System.out.println ("Error code: " +
sqlwarn.getErrorCode());
sqlwarn=sqlwarn.getNextWarning();
}
Крок 5 Закриття зєднання
try{
Connection con =
DriverManager.getConnection(url,userID,p
asswd);
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery
("SELECT EMPNO, FIRSTNME, LASTNAME " +
" FROM EMPLOYEE " +
" WHERE SALARY > 80000" );
while ( rs.next() ) {
. . . . . . . . . . . . . . .
}
rs.close();
stmt.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}

The big picture

SQLJ - це стандарт для embedding-SQL запитів в


програмах на Java.

SQL запити виконуються статично використовуючи


контекст (context).
Є два типии контекстів:
- Connection context (контекст підключення)
еквівалетний обєкту Connection
- Execution context (контекст виконання) - це необхідно,
щоб отримати інформацію про SQL заяви до і після
виконання інструкції.

Синтаксис SQLJ

Усі SQLJ вирази починаються з конструкції #sql:


#sql [connection-context] { sql statement }
#sql [connection-context, execution context]
{ sql statement }
#sql { sql statement }
#sql [execution context] { sql statement }

Наприклад

#sql {SELECT EMPNO FROM EMP WHERE WORKDEPT = :dept};

Connection context
Для роботи з SQL через SQLJ спочатку треба встановити
контекст зєднання з СУБД

(1) #sql context ctx; // This should be outside the


class
(2)
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
(3) ctx ctx1 = new ctx(jdbc:db2:sample,false);
(4) #sql [ctx1] { DELETE FROM dept };

Комбінація SQLJ та JDBC

#sql context ctx; // This should be outside the class


Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
(1) Connection con=DriverManager.getConnection();
(2) ctx ctx1 = new ctx(con);
#sql [ctx1] { DELETE FROM dept };

Також можна створити контекст зєднання по


замовчуванню(default context):
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
Connection con = DriverManager.getConnection();
(1) DefaultContext ctx1 = new DefaultContext(con);
(2) DefaultContext.setDefaultContext(ctx1);
(3) #sql { DELETE FROM dept };

Приклад коду з використанням SQLJ


import java.sql.*;
(1) import sqlj.runtime.*; // SQLJ runtime support
(2) import sqlj.runtime.ref.*; // SQLJ runtime
support

class myprg3 {
public static void main(String argv[]) {
try {
Connection con = null;
Class.forName("com.ibm.db2.jcc.DB2Driver");
String url = "jdbc:db2://127.0.0.1:50000/SAMPLE";
if (argv.length == 2) {
String userID = argv[0];
String passwd = argv[1];
con = DriverManager.getConnection(url,userID,passwd);
}
else { throw new Exception
("\n Usage: java myprg3 userID password\n");
}
(3) DefaultContext ctx = new DefaultContext(con);
(4) DefaultContext.setDefaultContext(ctx);
(5) if( ctx != null )
(6) { ctx.close();}
} catch (Exception e) { }
}
}
Execution contexts
Контекст виконання здійснює моніторинг і контроль за
виконанням SQL запитів.
Це еквівалент Statement в JDBC

Щоб створити ExecutionContext необхідно викликати


метод getExecutionContext() над контекстом зєднання.

Приклад:

#sql context ctx; // this should be outside the class


String url = "jdbc:db2:sample";
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
Connection con=DriverManager.getConnection(url);
ctx ctx1=new ctx(con);
(1) ExecutionContext exectx1 =
ctx1.getExecutionContext();
(2) #sql[ctx1,exectx1] = { DELETE FROM purchaseorder
WHERE status='UnShipped'}
(3) int i = exectx1.getUpdateCount();

Ітератори
Ітератори (Iterators) це еквівалент ResultSet в JDBC.

Є два типи ітераторів:


- іменні ітератори (Named iterators): ідентифікує
колонки за їх іменем. При оголошенні літератора,
необхідно зазначити імена колонок та їх тип.
- позиційні ітератори (Position iterators): ідентифікує
колонки за їх положенням в результуючому кортежі. При
оголошенні ітератора, необхідно зазначити лише тип
колонок.
Використання іменного ітератора

(1) #sql iterator namediterator (int poid, String


status)
(2) namediterator iterator1;
(3) #sql [ctx1] iterator1 = { select poid,status from
purchaseorder };
(4) while(iterator1.next()) {
(5) System.out.println("poid: " + iterator1.poid() +
"Status: "+ iterator1.status());
}
(6) iterator1.close();

Використання позиційного ітератора

(1) #sql iterator positionedIterator (int, String);


(2) String status = null;
(3) int poid = 0;
(4) positionedIterator iterator1;
(5) #sql [ctx1] iterator1={ select poid, status from
purchaseorder };
(6) #sql { fetch :iterator1 into :poid, :status };
(7) while(!iterator1.endFetch()) {
(8) System.out.println("poid: " + poid + "Status: "+
status);
(9) #sql { fetch :iterator1 into :poid, :status };
}

Використання оновлюваного (updatable) ітератора


(1) #sql public iterator namediterator implements
sqlj.runtime.ForUpdate
with (updateColumns="STATUS") (int poid, String
status);
(2) namediterator iterator1;
(3) #sql [ctx1] iterator1={ select poid,status from
purchaseorder };
(4) while(iterator1.next()) {
(5) System.out.println("before update poid: " +
iterator1.poid() +
"Status: "+ iterator1.status());
(6)
if(iterator1.status().toUpperCase().compareTo("UNSHIPPED"
)==0){
#sql [ctx1] {update purchaseorder set status=
'shipped' where current of :iterator1 };
}
(7) #sql [ctx1] {commit};

Спільне використання SQLJ та JDBC


SQLJ та JDBC можна спільно використовувати в межах
однієї програми.
Наприклад
- JDBC обєкт зєднання може бути отриманий
з ConnectionContext
getConnection()
- ітератор SQLJ може бути отриманий з JDBC ResultSet (
#sql iterator = {CAST :result-set }
і т.п.

Приклад:
#sql public iterator positionIterator (int, String);
Class.forName("com.ibm.db2.jcc.DB2Driver").newInstanc
e();
Connection con=DriverManager.getConnection(url);
con.setAutoCommit(false);
(1) ctx ctx1=new ctx(con);
positionIterator iterator;
Statement stmt = con.createStatement();
ResultSet rs=stmt.executeQuery("select poid, status
from purchaseorder");
(2) #sql [ctx1] iterator={cast :rs};
#sql {fetch :iterator into :poid, :status};
while(!iterator.endFetch()) {
System.out.println("id: "+poid+" status: "+status);
#sql {fetch :iterator into :poid, :status};
}
iterator.close();

Підготовка SQLJ програм


Розробка програмного
забезпечення для роботи з
СУБД на
C/C++

The big picture


Еmbedded SQL

Розширення файлів:

Platform C source File C++ source file


Linux .sqc .sqC
Windows .sqc .sqx

Співвідношення типів даних в SQL та


C/C++
SQL типи C та C++ типи Опис колонок в SQL

SMALLINT Short 16 bit signed integer


INTEGER sqlint32 32 bit signed integer
DOUBLE Double Double-precision
floating point
CHAR(n) char[n+1] where n is Fixed-length, null-
large enough to hold terminated character
the data 1<=n<=254 string
VARCHAR(n) char[n+1] where n is Null-terminated
large enough to hold varying length string
the data 1<=n<=254
DATE char[11] Null-terminated
character form
TIME char[9] Null-terminated
character form

Кроки для розробки вбудованих SQL


C/C++ запитів

1. Включити необхідні заголовкові файли


2. Оголосити змінні сервера (Declare host variables)
3. З'єднатися з СУБД (Connect to a database)
4.Виконати необхідні SQL запити (Execute SQL
statements)
5. Обробити помилки ( Handle SQL errors )
6. Підтвердити транзакції (Commit the transactions)
7. Від'єднатися від СУБД (Disconnect from the database)

Embedded SQL C program template


(1) /* Include required header files
(2) /* Declaration of host variables */
EXEC SQL BEGIN DECLARE SECTION;
.......
.......
EXEC SQL END DECLARE SECTION;
/* Declaration of SQLCA structure */
EXEC SQL DECLARE SQLCA;
/* Declaration of main function */
void main() {
/* Connect to the database */
(3) EXEC SQL CONNECT TO <database name> ;
/* Error handling to check connection is
successful*/
if (SQLCODE < 0) {
printf ("\n Error while connecting to database");
printf ("\n Returned SQLCODE = ");
exit;
} else {
printf ("\n Connect to database successfully");
}
/* End of error handling */
(4) /* Execute SQL statements
EXEC SQL SELECT <col1>, <col2> INTO :var1 :var2
FROM <table name> WHERE <condition> ;
/* Error handling to check SQL statement executed
successfully */
(5) if (SQLCODE < 0) {
printf ("\n Error while executing SQL statement");
printf ("\n Returned SQLCODE = ");
exit;
}
(6) /* Commit the transaction */
EXEC SQL COMMIT;
/* Error handling to check SQL statement executed
successfully */
if (SQLCODE < 0) {
printf ("\n Error while Commiting data");
printf ("\n Returned SQLCODE = ");
exit;
}
(7) /* Disconnect from the database */
EXEC SQL DISCONNECT FROM <database name>;
/* Error handling to check whether disconnection
is successful */
if (SQLCODE < 0) {
printf ("\n Error while disconnecting from
database");
printf ("\n Returned SQLCODE = ");
exit;
} else {
printf ("\n Disconnect from database
successfully");
}
}

Приклад розробки embedded SQL C/C++


програми

Програма управління персоналом, що повинна


виконувати наступні функції:

Function Operation
AddEmployeeInfo( ) INSERT new employee information in the
table
UpdateEmployeeInfo( UPDATE employee salary into the table
)
FetchEmployeeInfo( ) SELECT employee information from the
table
DeleteEmployeeInfo( ) DELETE employee information from the
table
Підключення необхідних заголовкових
файлів

Першик крок підключення необхідних бібліотек.

Для використання embedded SQL необхідно підключити


бібліотеку <sqlca.h>

Оголошення змінних
(host variables)

EXEC SQL BEGIN DECLARE SECTION;


sqlint32 hempno; /* to store employee id */
char hfirstname[20]; /* to store employee first
name */
char hlastname[20]; /* to store employee last name
*/
char hedlevel[4]; /* to store employee education
level */
double hsalary ; /* to store employee salary */
double hnewsalary; /* to store employee new salary
*/
char hdynstmt[16384]; /* to store SQL statements*/
EXEC SQL END DECLARE SECTION;

З'єднання з базою даних

Є явне та неявне встановлення з'єднання з СУБД.


Неявне, коли в якості ID для зєднання з СУБД
використовується ID поточного користувача системи.
EXEC SQL CONNECT TO sample;

Явне, коли ID і пароль задаються в явному вигляді


EXEC SQL CONNECT TO sample USER administrator
USING admin123;

З'єднання з базою даних

Є явне та неявне встановлення з'єднання з СУБД.


Неявне, коли в якості ID для зєднання з СУБД
використовується ID поточного користувача системи.
EXEC SQL CONNECT TO sample;

Явне, коли ID і пароль задаються в явному вигляді


EXEC SQL CONNECT TO sample USER administrator
USING admin123;

(1) EXEC SQL CONNECT TO sample; /* Database name


is SAMPLE*/
(2) if (SQLCODE < 0) {
printf ("\n ERROR WHILE DATABASE CONNECTION\n");
printf ("\n SQLCODE = %d", SQLCODE);
rc = 1;
exit(1);
} else {
printf ("\n CONNECT TO DATABASE SUCCESSFULLY\n");
}

Виконання SQL запитів

Для виконання запитів використовується ключове


слово EXEC SQL
Воно передує SQL запиту, що треба виконати.
Запит повинен закінчуватися крапкою з комою (;).
Вставка інформації в таблицю (INSERT)

int AddEmployeeInfo() {
int rc = 0;
printf("\n=========================");
printf("\n ADD EMPLOYEE INFORMATION");
printf("\n=========================");
(1) EXEC SQL INSERT INTO employee
(empno, firstnme, lastname, edlevel, salary)
VALUES (50001, 'RAUL', 'CHONG', 21, 6000),
(50002, 'JAMES', 'JI', 20, 5786),
(50003, 'MIN', 'YAO', 20, 5876),
(50004, 'IAN', 'HAKES', 19, 5489),
(50005, 'VINEET', 'MISHRA', 19,5600);
(2) if(SQLCODE < 0) {
printf ("\n ERROR WHILE ADDING EMPLOYEE
INFORMATION");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1
} else {
printf("\n EMPLOYEE ADDED SUCESSFULLY ");
EXEC SQL COMMIT;
}
return rc;
}

Вибірка інформації з таблиці

Вибірка даних виконується при допомозі команди


SELECT.

Якщо отримується одинарний результат, то


використовується конструкція SELECT INTO, яка поміщає
результат в задану змінну.

Якщо в результаті вибірки повертатиметься множина


даних, то необхідно використовувати курсор (cursor).
При роботі з курсором необхідно:
1. Оголосити курсор при допомозі DECLARE CURSOR
2. Відкрити курсор при допомозі OPEN
3. Отримати почергово рядки при допомозі FETCH
4. Закрити курсор при допомозі CLOSE

int FetchEmployeeInfo() {
int rc = 0;

(1) EXEC SQL DECLARE cur1 CURSOR FOR SELECT empno,


firstnme, lastname, edlevel, salary FROM employee
WHERE empno BETWEEN 50001 AND 50005;
if(SQLCODE < 0) {
printf ("\n ERROR WHILE CURSOR DECLARATION");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}

/* open cursor */
(2) EXEC SQL OPEN cur1;
/* fetch cursor */
(3) EXEC SQL FETCH cur1
INTO :hempno, :hfirstname, :hlastname, :hedlevel,
:hsalary ;
printf("\n\nEMPNO FIRSTNAME LASTNAME EMPSALARY");
printf("\n----- --------- -------- -----------
\n");

while (SQLCODE != 100) {


printf("%d %10s %11s %15f \n", hempno,
hfirstname, hlastname, hsalary);
EXEC SQL FETCH cur1
INTO :hempno, :hfirstname, :hlastname, :hedlevel,
:hsalary;
if(SQLCODE < 0) {
printf ("\n ERROR WHILE FETCHING DATA");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}
}

(4) EXEC SQL CLOSE cur1;


EXEC SQL COMMIT;
return rc;
}

Оновлення даних в таблиці

int UpdateEmployeeInfo() {
int rc = 0, noofemp, loop;
printf("\n============================");
printf("\n UPDATE EMPLOYEE INFORMATION");
printf("\n============================");

(1) strcpy(hdynstmt, "UPDATE employee SET SALARY =


?
WHERE empno = ?");

(2) EXEC SQL PREPARE stmt FROM :hdynstmt;


if(SQLCODE < 0) {
printf ("\n EROROR WHILE PREPARING STATEMENT");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}

printf("\n NUMBER OF EMPLOYEE TO UPDATE: ");


scanf("\n%d", &noofemp);
for(loop = 0; loop != noofemp; loop++) {
printf("\n ENTER EMPLOYEE ID AND NEW SALARY: ");
scanf("\n %d %lf",&hempno, &hnewsalary);

(3) EXEC SQL EXECUTE stmt USING :hnewsalary,


:hempno;
if(SQLCODE < 0) {
printf ("\n EROROR WHILE EXECUTING STATEMENT");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}
}

printf("\n EMPLOYEE INFORMATION UPDATED


SUCESSFULLY ");
(4) EXEC SQL COMMIT;
if(SQLCODE < 0) {
printf ("\n EROROR WHILE COMITTING DATA");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}
return rc;
}

Видалення даних з таблиці

int DeleteEmployeeInfo() {
int rc = 0;
int option;
char diagoption;
printf("\n============================");
printf("\n DELETE EMPLOYEE INFORMATION");
printf("\n============================");
printf("\n ENTER 1: (TO DELETE EMPLOYEE
INFORMATION) ");
printf("\n ENTER 2: (TO DELETE ALL EMPLOYEES
INFORMATION) ");
scanf("\n%d", &option);
if(option == 1) {

printf("\n ENTER EMPLOYEE ID:");


scanf("\n%d", &hempno);
(1) EXEC SQL DELETE employee WHERE empno =
:hempno;
if(SQLCODE < 0) {
printf ("\n EROROR WHILE DELETING INFORMATION");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}
printf("\n EMPLOYEE WITH ID %d DELETED SUCESSFULLY
",
hempno);

} else {
(2) EXEC SQL DELETE employee WHERE empno BETWEEN
50001 AND 50005;
if(SQLCODE < 0) {
printf ("\n EROROR WHILE DELETING INFORMATION");
printf ("\n RETURNED SQLCODE = %d", SQLCODE);
rc = -1;
exit(1);
}

printf("\n ALL EMPLOYEES DELETED SUCESSFULLY ");


(3) EXEC SQL COMMIT;
}
return rc;
}

Підтвердження запитів
Після виконання SQL запиту, в залежності від логіки
роботи вашої програми, потрібно здійснити commit або
rollback.
EXEC SQL COMMIT;
if (SQLCODE < 0) {
printf ("\n COMMIT ERROR");
printf ("\n SQLCODE = %d", SQLCODE);
exit(1);
}

Від'єднання від бази даних


EXEC SQL CONNECT RESET;
/* Error handling to check whether disconnection
is successful */
if (SQLCODE < 0) {
printf ("\n Error while disconnecting from
database");
printf ("\n Returned SQLCODE = ", SQLCODE);
exit (1);
} else {
printf ("\n DISCONNECT FROM SAMPLE DATABASE
SUCCESSFULLY \n\n");
}

Компіляція програм з використанням


вбудованого SQL

Кроки
1. Здійснити прекомпіляцію програми
використовуючи команду PRECOMPILE
2. Якщо ви використовуєте файл звязку (опція
BINDFILE для прекомпілятора), необхідно звязати цей
файл з СУБД для створення програмного пакету
використовуючи команду BIND.
3. Скомпілювати змінений код програми і код що не
містить вбудованого SQL та отримати обєктний файл
(.obj).
4. Злінкувати отриманий обєктний файл з
бібліотеками СУБД і створити виконуваний файл (.exe)
Розробка програм на C/C++ з використанням
ODBC/CLI

ODBC (Open DatabaseConnectivity) це альтернатива


embedded SQL, основна перевага якої полягає в
можливості роботи написаних програм з широким
спектром СУБД від різних виробників без необхідності
перекомпільовувати вихідний код програми.
Для запуску ODBC програм необхідно встановити
відповідний ODBC/CLI драйвер, що зазвичай надається
розробником СУБД
Для використання OBDC на клієнті необхідно:
LINUX
1. Встановити ODBC менеджер
2. Зареєструвати СУБД в файлі .odbc.ini
3. Встановити шлях в LD_LIBRARY_PATH на libodbc.so
4. Встановити значення ODBCINI
Windows
1. Відкрити Microsoft ODBC Data Source (odbcad32.exe)
2. Сконфігурувати в ODBC DataSource нове джерело
даних

Handles

Environment handle (SQL_HANDLE_ENV) інформація про


глобальний стан
програми
Connection handle (SQL_HANDLE_DBC) інформація про
поточне зєднання з
СУБД
Statement handle (SQL_HANDLE_STMT) інформація про
останній виконаний
SQL запит
Descriptor handle (SQL_HANDLE_DESC) інформація про
колонки в
результуючій вибірці

Кроки розробки програм з використанням


ODBC/CLI

Підключення заголовкових файлів


Перелік бібліотек, які необхідно підключити для
розробки
з використанням ODBC/CLI:

/* Include header files */


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sqlcli1.h>

Отримання дескриптора оточення


(environment handle)

Для створення дескрипторів


використовується SQLAllocHandle API

SQLRETURN SQLAllocHandle(
SQLSMALLINT HandleType, // тип
дескприптора
SQLHANDLE InputHandle, // вхідний
дескриптор
SQLHANDLE *OutputHandlePtr); // вихідний
дескриптор

Результат виконання:
SQL_SUCCESS
SQL_SUCCESS_WITH_INFO
SQL_INVALID_HANDLE
SQL_ERROR
Приклад отримання дескриптора оточення

/* allocate an environment handle */


(1) rc = SQLAllocHandle(SQL_HANDLE_ENV,
SQL_NULL_HANDLE, pHenv);
(2) if (rc != SQL_SUCCESS) {
printf("\n\nERROR while allocating environment
handle.\
funcRc = 1;
exit (1);
}
printf("\n\nAllocate environment handle
successfully.");

З'єднання з базою даних

Після отримання дескриптора оточення, наступним


кроком є
отримання дескриптора з'єднання (SQL_HANDLE_DBC)
на основі якого буде проводитися зєднання з СУБД.

SQLRETURN SQLConnect (
SQLHDBC ConnectionHandle, /* hdbc */
SQLCHAR *ServerName, /* szDSN */
SQLSMALLINT ServerNameLength, /* cbDSN */
SQLCHAR *UserName, /* szUID */
SQLSMALLINT UserNameLength, /* cbUID */
SQLCHAR *Authentication, /* szAuthStr */
SQLSMALLINT AuthenticationLength /* cbAuthStr */
);

Приклад отримання дескриптора з'єднання


(1) rc = SQLAllocHandle(SQL_HANDLE_DBC, *pHenv,
pHdbc);
if (rc != SQL_SUCCESS) {
printf("\n\nERROR while allocating connection
handle.\n");
funcRc = 1;
exit (1);
}
printf("\n\nAllocate Connection handle
successfully.");

/* connect to the database */


(2) rc = SQLConnect(*pHdbc, (SQLCHAR *)dbAlias,
SQL_NTS,
(SQLCHAR *)user,SQL_NTS,(SQLCHAR *)pswd, SQL_NTS);
if (rc != SQL_SUCCESS) {
printf("\n\nERROR while connecting to
database.\n");
funcRc = 1;
exit (1);
}

printf("\n\nConnected to %s database
successfully\n", dbAlias);

SQLDriverConnect() API

CLI Connection API Use of API


SQLConnect Встановити зєданння з джерелом
даних (datasource)
SQLBrowseConnect Отримати необхідні атрибути для
підключення до джерела даних
SQLSetConnectAttr Встановити атрибути зєднання
SQLGetConnectAttr Отримати атрибути зєднання
SQLDisconnect Відєнатися від джерела даних
Обробка SQL запитів

Перед виконанням SQL запитів необхідно спочатку


отримати дескриптор запитів.
Цей дескриптор має бути пов'язаний з конкретним
з'єднанням в рамках якого виконуватимуться запити.
Виконання SQL запитів складається з наступних кроків:
1. Отримати дескриптор запитів
2. Підготувати і виконати SQL запит
3. Опрацювати результат
4. Вивільнити дескриптор запитів

Обробка SQL запитів


/* SQL INSERT statement to be executed */
SQLCHAR *stmt = (SQLCHAR *)"INSERT INTO employee
(empno, firstnme, lastname, edlevel, salary)
VALUES (50006, 'SANJAY', 'KUMAR', 21, 50000),
(50007, 'RAJIT', 'PILLAI', 19, 47860),
(50008, 'PRIYANKA', 'JOSHI', 20, 45600)";

/* SQL INSERT statement to be executed */


SQLExecDirect (hstmt, (SQLCHAR *)
"INSERT INTO employee(empno, firstnme, lastname,
edlevel, salary)"
"VALUES (50006, 'SANJAY', 'KUMAR', 21, 50000), "
"(50007, 'RAJIT', 'PILLAI', 19, 47860), "
"(50008, 'PRIYANKA', 'JOSHI', 20, 45600)",
SQL_NTS);

CLI API

Function Description
SQLPrepare Підготувати запит
SQLSetParam Встановити параметр
SQLDescribeParam Повернути опис маркера
параметра
SQLExecute Виконати запит
SQLExecDirect Виконати запит
безпосередньо
SQLNumParams Отримати число параметрів
в запитів
SQLNumResultCols Отримати число колонок в
результаті
SQLBindCol Зв'язати колонку із
змінною в програмі
SQLFetch Отримати наступний рядок
SQLGetDiagField Отримати діагностичні дані
для поля
SQLEndTran Закінчити транзакцію для
з'єднання

Вставка даних

/* Perform INSERT operation */


int AddEmployeeInfo(SQLHANDLE hdbc) {
int funcRc = 0;
SQLRETURN rc = SQL_SUCCESS;
SQLHANDLE hstmt; /* statement handle */
/* SQL INSERT statement to be executed */
(1) SQLCHAR *stmt = (SQLCHAR *)"INSERT INTO
employee
(empno, firstnme, lastname, edlevel, salary) "
"VALUES (50006, 'SANJAY', 'KUMAR', 21, 50000), "
"(50007, 'RAJIT', 'PILLAI', 19, 47860),"
"(50008, 'PRIYANKA', 'JOSHI', 20, 45600)";

/* allocate a statement handle */


(2) rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc,
&hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while allocating statement
handle");
funcRc = 1;
exit (1);
}

/* execute the statement */


(3) rc = SQLExecDirect(hstmt, stmt, SQL_NTS);
if(rc != SQL_SUCCESS) {
printf("\n Error while statement execution");
funcRc = 1;
exit (1);
}

/* Commit the transaction */


(4) rc = SQLEndTran(SQL_HANDLE_DBC, hdbc,
SQL_COMMIT);
if(rc != SQL_SUCCESS) {
printf("\n Error while committing the
transaction");
funcRc = 1;
exit (1);
}

/* free the statement handle */


(5) rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while freeing handle");
funcRc = 1;
exit (1);
}
printf("\n Employee added successfully ");
return funcRc;
}

Вибірка даних
Для вибірки даних з використанням запиту SELECT
необхідно зробити звязування змінних програми з
колонками результату і
покроково отримувати рядки даних.

/* perform Select operation */


int FetchEmployeeInfo(SQLHANDLE hdbc) {
int funcRc = 0;
SQLRETURN rc = SQL_SUCCESS;
SQLHANDLE hstmt; /* statement handle */

(1) /* SQL SELECT statement to be executed */


SQLCHAR *stmt = (SQLCHAR *) "SELECT firstnme,
lastname, edlevel
FROM employee WHERE empno >= ? ";
sqlint32 empno = 0;

(2) struct {
SQLINTEGER ind;
SQLCHAR value[20];
} firstname; /* variable to be bound to the
firstnme column */

struct {
SQLINTEGER ind;
SQLCHAR value[15];
} lastname; /* variable to be bound to the
lastname column */
struct {
SQLINTEGER ind;
SQLSMALLINT value;
} edlevel; /* variable to be bound to the edlevel
column */

/* set AUTOCOMMIT OFF */


(3) rc = SQLSetConnectAttr(hdbc,
SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS);
if(rc != SQL_SUCCESS) {
printf("\n Error while handle allocation");
funcRc = 1;
exit (1);
}

/* allocate a statement handle */


(4) rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc,
&hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while allocating statement handle
");
funcRc = 1;
exit (1);
}

/* prepare the statement */


(5) rc = SQLPrepare(hstmt, stmt, SQL_NTS);
if(rc != SQL_SUCCESS) {
printf("\n Error while preparing statement");
funcRc = 1;
exit (1);
}

/* bind empno to the statement */


(6) rc = SQLBindParameter(hstmt, 1,
SQL_PARAM_INPUT,
SQL_C_LONG, SQL_INTEGER, 0, 0, &empno, 0, NULL);
if(rc != SQL_SUCCESS) {
printf("\n Error while binding paremeters");
funcRc = 1;
exit (1);
}

/* execute the statement for empno = 50006 */


empno = 50006;
/* execute the statement */
(7) rc = SQLExecute(hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while statement execution");
funcRc = 1;
exit (1);
}

/* bind column 1 to variable */


(8) rc = SQLBindCol(hstmt, 1, SQL_C_CHAR,
firstname.value,
20, &firstname.ind);
if(rc != SQL_SUCCESS) {
printf("\n Error while binding column");
funcRc = 1;
exit (1);
}

/* bind column 2 to variable */


(9) rc = SQLBindCol(hstmt, 2, SQL_C_CHAR,
lastname.value,
15, &lastname.ind);
if(rc != SQL_SUCCESS) {
printf("\n Error while binding column");
funcRc = 1;
exit (1);
}

/* bind column 3 to variable */


(10) rc = SQLBindCol(hstmt, 3, SQL_C_SHORT,
&edlevel.value,
0, &edlevel.ind);
if(rc != SQL_SUCCESS) {
printf("\n Error while binding column");
funcRc = 1;
exit (1);
}
printf("\n\n FIRSTNAME LASTNAME EDLEVEL \n");
printf(" --------- -------- -------\n");

/* fetch each row and display */


(11) rc = SQLFetch(hstmt);
if (rc == SQL_NO_DATA_FOUND) {
printf("\n Data not found.\n");
}
while (rc != SQL_NO_DATA_FOUND) {
printf(" %8s %14s %8d \n", firstname.value,
lastname.value,
edlevel.value);
/* fetch next row */
rc = SQLFetch(hstmt);
}

/* Commit the transaction */


(12) rc = SQLEndTran(SQL_HANDLE_DBC, hdbc,
SQL_COMMIT);
if(rc != SQL_SUCCESS) {
printf("\n Error while committing the
transaction");
funcRc = 1;
exit (1);
}

/* free the statement handle */


(13) rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while freeing handle");
funcRc = 1;
exit (1);
}
return funcRc;
}

Видалення даних
/* Perform Delete operation */
int DeleteEmployeeInfo(SQLHANDLE hdbc) {
int funcRc = 0;
SQLRETURN rc = SQL_SUCCESS;
SQLHANDLE hstmt; /* statement handle */
/* SQL DELETE statement to be executed */
(1) SQLCHAR *stmt = (SQLCHAR *)"DELETE FROM
employee
WHERE empno >= 50006";

/* set AUTOCOMMIT OFF */


(2) rc = SQLSetConnectAttr(hdbc,
SQL_ATTR_AUTOCOMMIT,
(SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS);
if(rc != SQL_SUCCESS) {
printf("\n Error while setting Auto Commit OFF");
funcRc = 1;
exit (1);
}

/* allocate a statement handle */


(3) rc = SQLAllocHandle(SQL_HANDLE_STMT, hdbc,
&hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while allocating statement
handle");
funcRc = 1;
exit (1);
}

/* directly execute the statement */


(4) rc = SQLExecDirect(hstmt, stmt, SQL_NTS);
if(rc != SQL_SUCCESS) {
printf("\n Error while statement execution");
funcRc = 1;
exit (1);
}

/* Commit the transaction */


(5) rc = SQLEndTran(SQL_HANDLE_DBC, hdbc,
SQL_COMMIT);
if(rc != SQL_SUCCESS) {
printf("\n Error while committing transaction");
funcRc = 1;
exit (1);
}

/* free the statement handle */


(6) rc = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
if(rc != SQL_SUCCESS) {
printf("\n Error while freeing handle");
funcRc = 1;
exit (1);
}
printf("\n Employee Deleted successfully");
return funcRc;
}

Відєднання від бази даних

/* disconnect from the database */


(1) rc = SQLDisconnect(*pHdbc);
(2) if (rc != SQL_SUCCESS) {
printf("\n\nERROR while disconnecting from
database.\n");
funcRc = 1;
exit (1);
}
printf("\n\nDisconnect from %s database
successfully", dbAlias);

Звільнення дескрипторів

/* free connection handle */


(1) rc = SQLFreeHandle(SQL_HANDLE_DBC, *pHdbc);
if (rc != SQL_SUCCESS) {
printf("\n\nERROR while freeing connection
handle.\n");
funcRc = 1;
exit (1);
}
printf("\n\nFree connection handle successfully.")
;

/* free environment handle */


(2) rc = SQLFreeHandle(SQL_HANDLE_ENV, *pHenv);
if (rc != SQL_SUCCESS) {
printf("\n\nERROR while freeing environment
handle.\n");
funcRc = 1;
exit (1);
}
printf("\n\nFree environment handle
successfully.\n\n") ;

Розробка прикладного
програмного забезпечення
для роботи з СУБД
на мові С#/.NET

The big picture


.NET підтримує доступ до баз даних
через ActiveX Data Objects для .NET.

Архітектура даних в ADO.NET


За доступ до даних в ADO.NET відповідають два класи
DataSet і Data Provider.

DataSet
Це відєднане від СУБД представлення даних.
Представляє собою локальну копію відповідної частити
БД.
Дані можуть бути змінені незалежно від бази даних
Коли робота з DataSet завершена, зміни можуть бути
надіслані до СУБД для оновлення
Можна отримати для будь-якого джерела даних
(DataSource)

Data Provider
Відповідає за забезпечення та підтримку зєднання з
СУБД.
Являє собою набір компонентів, що забезпечують
ефективну роботу з даними
Кожен DataProvider складається з набору класів:
- Connection обєкт, що забезпечує зєднання з СУБД
- Command обєкт, що використовується для
виконання команд
- DataReader обєкт, що забезпечує forward-only та
read only зчитування даних
- DataAdapter - обєкт, що наповнює
відєднаний DataSet даними і
виконує оновлення

В архітектурі ADO.NET прикладне програмне


забезпечення (Data Consumers) зєднується з
СУБД (Resource) використовуючи data provider.
Data provider інкапсулює дані і забезпечує взаємодію з
включаючи зєднання, виконання SQL запитів і отримання
результатів.

Connection
Connection використовується для зєднання з базою
даних.
Кожен data providers має свій власний
обєкт Connection Object
(DB2Connection, OleDbConnection,
і OdbcConnection).

connection.ConnectionString = Database=Sample;

Provid Приклад
er
DB2Connection connection =
IBM new DB2Connection(Database=SAMPLE);
Data
Server
Provide
r for
.NET

OLE DB
OleDbConnection connection =
.NET
new OleDbConnection(Provider=IBMDADB2;" +
Data "Data
Provide Source=sample;UID=userid;PWD=password;);
r

ODBC.
NET OdbcConnection connection = new
Data OdbcConnection("DSN=sample;UID=userid;PWD
Provide =password;");
r

Метод Опис Приклад


Open Відкриває connection.Open();
зєднання з
базою даних
відповідно до
connection_stri
ng.
Close Закриття connection.Close();
зєднання
CreateComma Повертає connection.CreateComma
nd обєкт nd();
command,
асоційований
з зєднанням
BeginTransact Розпочати connection.BeginTransact
ion транзакцію ion()

Command

Обєкт Command дозволяє виконати будь-який


коректний SQL запит чи вбудовану процедуру для
заданого обєкту Connection.

Provider Приклад
IBM Data Server
DB2Command cmd = new
Provider for .NET DB2Command();
OLE DB .NET
OleDbCommand cmd = new
Data Provider OleDbCommand();
ODBC.NET OdbcCommand cmd = new
Data Provider OdbcCommand();

Приклади:
cmd.CommandType = CommandType.Text;
cmd.CommandText = "SELECT manager FROM org WHERE
DEPTNUMB=10";

cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = procName;
Методи обєкту Command

CreateParameter - використовується для опрацювання


параметрів:
set param1 = cmd.CreateParameter
("DEPTNAME", adVarChar,
adParamInput, 14, "Test");
set param2 = cmd.CreateParameter
("DEPTNUMB", adTinyInt,
adParamInput, , 510);

ExecuteNonQuery - Використовується для


виконання SQL запитів, що не повертають ніяких даних
(UPDATE, INSERT чи DELETE) SQL. Метод повертає число
змінених рядків в базі даних:
int rowsAffected = cmd.ExecuteNonQuery();

ExecuteReader - Використовується для


виконання SQL запитів, що
повертають DataReader обєкт.

DB2DataReader reader = cmd.ExecuteReader ( );



ExecuteScalar - Використовується для
виконання SQL запитів, що повертають одиничне
значення з бази даних:

int count=(int)cmd.ExecuteScalar();

Методи обєкту DataAdapter


Обєкт наповнює відєднаний обєкт DataSet даними та
відповідає за виконання операцій оновлення.
Provider Приклад
IBM Data Server
Provider for DB2DataAdapter adapter = new
.NET DB2DataAdapter();

OLE DB .NET
OleDbDataAdapter adapter = new
Data Provider OleDbDataAdapter();
ODBC.NET OdbcDataAdapter adapter = new
Data Provider OdbcDataAdapter();

Властивості класу DataAdapter

DeleteCommand видаляє запис з бази даних

adapter.DeleteCommand = new DB2Command


(DELETE From org WHERE
DEPTNUMB= 10, connection);

InsertCommand додає новий запис в базу даних

adapter.InsertCommand = new DB2Command


(INSERT INTO org VALUES
(30,Test, 60,
Eastern, Toronto),
connection);

SelectCommand вибирає записи з бази даних

adapter.SelectCommand = new DB2Command


(SELECT manager FROM org
WHERE
DEPTNUMB = 30,
connection);

UpdateCommand змінує записи в базі даних


adapter.UpdateCommand = new DB2Command
(UPDATE org SET manager=70
WHERE
DEPTNUMB=20
,
connection)
;

Методи класу DataAdapter

Fill - заповнює дані в DataSet

DataSet results= new DataSet();


adapter.SelectCommand = new DB2Command
("Select * from
dept", connection);
adapter.Fill(results);

Update - оновлює дані в DataSet і в базі даних шляхом


використання операцій INSERT, UPDATE DELETE:

DataSet results= new DataSet();


adapter.UpdateCommand = new DB2Command
(UPDATE org SET
Manager=70
WHERE
DEPTNUMB=20,
connection);
adapter.Update(results);

Клас DataReader
Клас DataReader застосовується для швидкого доступу
до записів в базі даних, отриманого в результаті
виконання SQL запиту чи вбудованої процедури.
Підтримує лише просування вперед по списку
результатів, і лише для читання.

Обєкт типу DataReader не може бути на пряму


створений, а його необхідно отримати як результат
виконання методу ExecuteReader.

Provider Приклад
IBM Data Db2DataReader reader =
Server cmd.ExecuteReader();
Provider for
.NET

OLE DB .NET OleDbDataReader reader =


Data Provider cmd.ExecuteReader();

ODBC.NET OdbcDataReader reader =


Data Provider cmd.ExecuteReader();

Клас DataReader
Властивості
FieldCount повертає загальне число колонок для
поточного рядку
HasRows дозволяє чизначити чи є ще рядки для
читанням поверненням true або false.
int cols=reader.FieldCount;
bool rows=reader.HasRows;

Методи
Read зчитує один рядок і переміщає курсор до
наступного. Повертає true або false для позначення
того, чи є ще рядки для читання

bool done=reader.read();

Close Закриває обєкт DataReader


reader.Close();

Getxxxx використовується для отримання даних


типу xxxx з вибірки:

Console.WriteLine (reader.GetString(1));

DataSet для ADO.NET

Обєкт типу DataSet є представленням закешованих в


памяті даних, отриманих з бази даних
Обєкт DataSet надає уніфіковану реляційну модель
даних, що не залежить від джерела цих даних

Методи DataSet:
AcceptChanges виконує коміт змін в DataSet
ds.AcceptChanges();

Clear - Очищає вміст DataSet


ds.Clear();

GetXML - Повертає XML-представлення даних з DataSet:


Console.WriteLine(ds.GetXml())

ReadXML Повертає XML-схему та XML дані з DataSet


ds.ReadXML(reader);

WriteXML Записує XMLдані в DataSet:


ds.WriteXML ( ".\\test.xml" ) ;

Зєднання з базою даних через IBM Data Server


Provider for .NET

String connectString = "Database=SAMPLE";


DB2Connection conn = new
DB2Connection(connectString);
conn.Open();
return conn;

Зєднання з базою даних через OLE DB .NET Data


Provider

OleDbConnection con = new


OleDbConnection("Provider=IBMDADB2;" +
"Data
Source=sample;UID=userid;PWD
=password;" );
con.Open()

Зєднання з базою даних через ODBC.NET Data


Provider

OdbcConnection con = new OdbcConnection


("DSN=sample;UID=use
rid;PWD=password;");
con.Open()

Робота з базою даних через OLE DB .NET Data


Provider

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.OleDb;
namespace c2 {
class Program {
static void Main(string[] args) {
OleDbCommand cmd = null;
OleDbConnection con = null;
OleDbDataReader rdr = null;
int rowCount;
string v_IBMREQD, strMsg;
try {
con = new OleDbConnection
("DSN=sample;UID=db2admi
n;PWD=mypsw;" +
"Provider='IBMDADB2';");
cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandText = "SELECT * FROM
SYSIBM.SYSDUMMY1";
cmd.CommandTimeout = 20;
con.Open();
rdr = cmd.ExecuteReader
(System.Data.Command
Behavior.SingleResult);
v_IBMREQD = "";
while (rdr.Read() == true) {
v_IBMREQD = rdr.GetString(0);
}
strMsg = " Successful retrieval of
record. Column" + "
'IBMREQD' has a
value of '" + v_IBMREQD
+ "'";
Console.WriteLine(strMsg);
Console.ReadLine();
rdr.Close();
con.Close();
} catch (OleDbException myException) {
}
}
}
}

Робота з базою даних через ODBC .NET Data


Provider

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Odbc;
namespace c3 {
class Program {
static void Main(string[] args) {
OdbcCommand cmd = null;
OdbcConnection con = null;
OdbcDataReader rdr = null;
string v_IBMREQD, strMsg;
try {
con = new
OdbcConnection("DSN=sample;UID=db2admin
;PWD=mypsw;"
+ "Driver={IBM DB2 ODBC DRIVER};");
cmd = new OdbcCommand();
cmd.Connection = con;
cmd.CommandText = "SELECT * FROM
SYSIBM.SYSDUMMY1";
cmd.CommandTimeout = 20;
con.Open();
rdr = cmd.ExecuteReader
(System.Data.Command
Behavior.SingleResult);
v_IBMREQD = "";

while (rdr.Read() == true) {


v_IBMREQD = rdr.GetString(0);
}
strMsg = " Successful retrieval of
record. Column" +
" 'IBMREQD' has a value
of '" + v_IBMREQD + "'";
Console.WriteLine(strMsg);
Console.ReadLine();
rdr.Close();
con.Close();
} catch (OdbcException myException) { }
}
}
}

Маніпулювання даними в .NET

Приклад виконання SELECT


(1) cmd.CommandText = "SELECT deptnumb, location
FROM org " +
" WHERE deptnumb < 25";
(2) DB2DataReader reader = cmd.ExecuteReader();

Приклад виконання INSERT


cmd.CommandText = "INSERT INTO staff(id, name,
dept, job, salary) "
+ "VALUES(380, 'Pearce', 38,
'Clerk', 13217.50),
+ "(390, 'Hachey', 38,
'Mgr', 21270.00), "
+ "(400, 'Wagland', 38,
'Clerk', 14575.00);
(1) cmd.ExecuteNonQuery();

Приклад виконання UPDATE


cmd.CommandText = "UPDATE staff "
+ "SET salary = (SELECT
MIN(salary) "
+ "FROM staff "
+ "WHERE id >= 310) "
cmd.ExecuteNonQuery();

Приклад виконання DELETE


cmd.CommandText = "DELETE FROM staff "
+ "WHERE id >= 310 "
+ "AND salary > 20000";
cmd.ExecuteNonQuery();

Розробка вбудованих процедур та користувацьких

Ця лекція присвячена розробці приграмного забезпечення на стороні сервера, що яких відносяться.

Вбудовані процедури (stored procedures) є об'єктами


докладання баз даних, які можуть інкапсулювати SQL заяви та бізнес-
логіки. Збереження частини логіки програми в базі даних забезпечує підвищення продуктивності, як
обсяг мережевого трафіку між додатками і базою даних значно знижується. Крім того, вбудовані
процедури забезпечують централізоване місце для зберігання коду, таким чином, що й інші додатки
можуть їх використовувати.

Користувацька функція (UDF User Defined Function) дозволяє розширити SQL мови
та інкапсуляції бізнес-логіки.
Тригери бази даних об'єктів, що дозволяють адміністраторам баз даних автоматично перевірити прав
ильність даних перед їх вставкою чи зміною.

Вбудовані процедури

В DB2 збережені процедури можуть бути написані з використанням SQL PL SQL (процедурний мова), C
/ C + +, Java, COBOL, CLR (Common Language Runtime). У цьому
розділі ми зосередимося на SQL процедури PL через їх популярність, хорошу продуктивністю
і простоту. Мова SQL PL заснована на SQL / PSM стандарті.

Рис.1 зменшення мережевого трафіку за рахунок використанням вбудованих процедур

У лівому верхньому кутку малюнка, ви побачите кілька SQL операторів, що виконуються один
за іншим. Кожен SQL передається від клієнта до
сервера даних, а сервер баз даних повертає результат клієнтові. Якщо виконуються багато SQL
запитів, це призводить до збільшення мережевого трафіку. З іншого боку, в нижній
частині альтернативний метод, який вимагає
менше мережевого трафіку. Другий метод викликає процедуру MyProc,
що зберігаються на сервері, яка містить ті ж SQL, а потім на стороні клієнта (на лівій стороні),
виклик оператор використовується для виклику збережених процедур. Другий спосіб
є більш ефективним, так як здійснюється тільки один запит до БД, що проходить через мережу, і
один результуючий набір повертається клієнтові.

Збережені процедури також можуть бути корисні в цілях безпеки в бази даних. Наприклад,
можна дозволити користувачам доступ до таблиць або представлень тільки через збережені
процедури, що допомагає блокувати роботу сервера і підтримувати доступ користувачів
до інформації, яку вони не повинні отримати. Це можливо тому, що користувачі не
вимагають явних привілеїв на таблиці або представлення, до
яких вони отримують доступ через збережені процедури, а їм просто повинні бути
надані достатні привілеї для виклику збережених процедур.

Робота з Data Studio

IBM Data Studio буде використовуватися в цьому розділі, для розробки збережених процедур,
призначених для користувача функцій і сервісів передачі даних мережі.
Рис.
2 Середовище IBM Data Studio

Перш ніж розробляти процедури користувача


необхідно створити проект. В меню студії даних, виберіть File -> New -> Project і виберіть Дані проекту
розвитку. Це показано на рис. 3.

Рис. 3 Створення нового проекту


Дотримуючись інструкцій майстра створення нового проекту, необхідно ввести ім'я проекту і вказати,
яку базу даних, з якою ваш проект буде пов'язаний. Якщо у вас немає існуючого підключення до
бази даних, натисніть на кнопку Створити в вікні
вибору підключення, і зявиться , показано на малюнку 4.

Рис. 4 створення нового зєднання

На рис. 4, переконайтеся, що у вікні Вибір поля бази даних вибрано DB2 для Linux, UNIX та Windows. У
пункті JDBC драйвер, за умовчанням після вибору DB2 для Linux, UNIX та Windows, буде
вибрано JDBC IBM Data Server JDBC Driver для SQLJ і JDBC (4.0). В поле хоста, ви можете ввести IP-
адресу або ім'я хоста (наприклад локальний). Переконатися, що з'єднання з
базою даних працює, можна натиснувши на кнопку Test Connection (в лівому нижньому кутку
рисунка). Якщо перевірка з'єднання пройшла успішно, натисніть кнопку Готово, і ім'я бази даних буде
додана в список з'єднань.

Далі вибравши базу даних, необхідно натиснути кнопку Готово і ваш проект зявиться у Project Explorer.
Після цього, натиснувши на символ "+", ви можете розгорнути проект, щоб побачити різні папки,
такі як PL / SQL пакети, SQL скрипти, збережені процедури і т.д.

Створення збережених процедур

Для створення Java, PL / SQL або PL SQL збережених


процедури в DataStudio, необхідно виконайти такі дії. (Зверніть увагу, що процедури на інших мовах
не можуть бути створені зі DataStudio).

Крок 1: Напишіть чи створювати код збережених процедур

Якщо ви хочете створити збережену процедуру, клацніть правою кнопкою миші на папці, збережених
процедур і виберіть New -> Stored Procedure.. Всю необхідну інформацію майстра Stored Procedure.,
такі як проект, що пов'язаний з процедурою, назва і
мова процедур і SQL заяви для використання в процедурі. За замовчуванням, Data Studio надає заяву
наприклад SQL. Прийміть всі значення за замовчуванням для всіх інших груп,
і в цей момент, ви можете натиснути Finish і збережена процедура створюється за
допомогою деякого коду шаблону і заяву SQL надані до якості прикладу. Це показано на рис. 5.

Крок 2: Розгортання збереженням процедур

Після того, як процедури створені, для їх розгортання, виберіть Data Project


Explorer клацніть правою кнопкою міші на ньому,
а потім виберіть Deploy. Розгортання процедур в основному реалізується
шляхом на виконані інструкції CREATE PROCEDURE, компіляції процедури і збереженні
в базі даних. Рисунок 6 ілюструє цей крок.
Крок 4: Запуск збережених процедур

Коли процедура, була розгорнута, ви можете запустити її, клацнувши правою кнопкою на ній і
вибравши Run. Результати
будуть з'являтися на вкладці Result в нижньому правому кутку вікна Data Studio, як показано на рис. 7.
Для запуску процедури з вікна DB2 Command або командного редактор, ви можете використовувати
команду CALL <procedure name>. Але, перед цим необхідно підключитися до бази даних, де ця
процедура знаходиться.

Мова PL SQL

Структура процедур
CREATE PROCEDURE proc_name [( {optional parameters} )]
[optional procedure attributes]
<statement>

Де <statement> є одним оператором, або набором операторів, згрупованих в


межах BEGIN [ATOMIC] ... END

Додаткові атрибути зберігаються процедури

LANGUAGE SQL - цей атрибут задає мову, яки використовувати процедура. Мова SQL є значенням за
замовчуванням. Для інших мов, таких як Java або C необхідно використовувати Java і C відповідно.
RESULT SETS <n> - wе необхідно,
якщо збережена процедура буде повертатися n множин результату.
SPECIFIC my_unique_name - це унікальне ім'я, яке може бути задано процедурі.

Параметри

Є три типи параметрів у SQL PL збережених процедур:

IN - вхідний параметр
OUT - вихідний параметр
INOUT - вхідний і вихідний параметр

Наприклад:

CREATE PROCEDURE proc(IN p1 INT, OUT p2 INT, INOUT p3 INT)

Для виклику процедури використовється CALL. Наприклад:

CALL proc (10,?,4)

Знак питання (?) використовується для OUT параметри у виклику. Ще один


приклад процедури з параметрами:
CREATE PROCEDURE P2 ( IN v_p1 INT,
INOUT v_p2 INT,
OUT v_p3 INT)
LANGUAGE SQL
SPECIFIC myP2
BEGIN
-- my second SQL procedure
SET v_p2 = v_p2 + v_p1;
SET v_p3 = v_p1;
END

Для виклику
call P2 (3, 4, ?)

Коментарі в SQL PL збережених процедур

Є два способи вказати коментарів у SQL PL збережених процедур:

- За допомогою двох тире. Наприклад:


-- This is an SQL-style comment
- Використання форматі, схожому на мову Сі. Наприклад:
/* This is a C-style coment */

Складені оператори

Складений оператор в збереженій процедурі це оператор, що складається з


декількох процедурних інструкцій та інструкцій SQL заключних між
словами ключові BEGIN і END. Якщо pf словом BEGIN слідує ключове слово ATOMIC, то
складовий оператор розглядається як єдине ціле, і всі запити повинні бути успішно
виконаними для того, щоб виклик процедури завершився успішно. Якщо ж хоча б один одне із запитів
не вдалося виконати, то все відкочується назад. Рисунок 3.9 показує структуру складеного оператора.

Оголошення змінних

Щоб оголосити змінну, використовуйте оператор Declare

ЗАЯВЛЯЮТЬ ім'я_змінної <data type> [DEFAULT значення];


DECLARE var_name <data type> [DEFAULT value];

DECLARE temp1 SMALLINT DEFAULT 0;


DECLARE temp2 INTEGER DEFAULT 10;
DECLARE temp3 DECIMAL(10,2) DEFAULT 100.10;
DECLARE temp4 REAL DEFAULT 10.1;
DECLARE temp5 DOUBLE DEFAULT 10000.1001;
DECLARE temp6 BIGINT DEFAULT 10000;
DECLARE temp7 CHAR(10) DEFAULT 'yes';
DECLARE temp8 VARCHAR(10) DEFAULT 'hello';
DECLARE temp9 DATE DEFAULT '1998-12-25';
DECLARE temp10 TIME DEFAULT '1:50 PM';
DECLARE temp11 TIMESTAMP DEFAULT '2001-01-05-12.00.00';
DECLARE temp12 CLOB(2G);

Присвоювання

Щоб присвоїти значення змінної, використовуйте SET заяві. Наприклад:


SET total = 100;

Або таким чином


VALUES(100) INTO total;

Крім того, будь-яка змінна може бути встановлений в NULL. Наприклад:


SET total = NULL;

Ви можете присвоїти значення змінній на основі результату SELECT. Наприклад:


SET total = (select sum(c1) from T1);
SET first_val = (select c1 from T1 fetch first 1 row only)

Про, виникане помилка, якщо більше одного значення витягується з таблиці, і ви намагаєтеся
привласнити їй однієї змінної. Якщо вам потрібно зберігати більше інформації, ніж одне значення,
використовувати масиви або курсори.

Курсори

Курсори множини, що містять результати виконання SELCT.

ЗАЯВЛЯЮТЬ <cursor name> CURSOR [RETURN З target> <return]


<SELECT Statement>;
Відкритий name> <cursor;
FETCH, <cursor name> INTO <variables>;
ЗАКРИТИ name> <cursor;

В якості параметрів WITH RETURN може бути використано значеннями:

- CLIENT: результат буде повернутися до клієнтського додатка

- CALLER: результуючий набір повертається клієнтові або збережена процедура, яка зрівнює
CREATE PROCEDURE set()
DYNAMIC RESULT SETS 1
LANGUAGE SQL
BEGIN
DECLARE cur CURSOR WITH RETURN TO CLIENT
FOR SELECT name, dept, job
FROM staff
WHERE salary > 20000;
OPEN cur;
END

Управління потоком

Як і в багатьох інших мовах, SQL PL має кілька контрукцій, які можуть бути використані для управління
потоком логіки:
- CASE (вибирає шляхи виконання, простий пошук)
- IF
- FOR (виконує тіло для кожного рядка таблиці)
- WHILE
- ITERATE (перехід до наступної ітерації. Як continue в C)
- LEAVE (вийти з блоку або циклу)
- LOOP (нескінченний цикл)
- REPEAT

Обробка помилок

В DB2 ключові слова SQLCODE і SQLSTATE використовуються для визначення успішного або
неуспішного виконання інструкції SQL. Ці ключові слова повинні бути явно оголошені в процедурі
наступним чином:
DECLARE SQLSTATE CHAR(5);
DECLARE SQLCODE INT;

DB2 встановить значення ключові слова автоматично після кожної операції SQL. Для SQLCODE
значення встановлюються таким чином:
- = 0, успішного.
- > 0, успішного з попередженням
- <0, невдало
- = 100, ніяких даних не було знайдено. (Тобто: FETCH повернув no data)

Для SQLSTATE, значення встановлюються таким чином:


- успіх: SQLSTATE '00000 '
- не знайдено: SQLSTATE '02000 '
- попередження: SQLSTATE '01XXX "
- виняток: усі інші значення

SQLCODE є СУБД конкретні і більш детальні, ніж SQLSTATE. SQLSTATE є стандартом серед СУБД, але
дуже загальний характер. Кілька SQLCODE, може відповідати одному SQLSTATE.

Обробники умов

Для опрацювання станів, можна створити обробник умови, в якому вказати:


- які умови він опрацьовує
- де відновити до виконання (в залежності від типу обробника: CONTINUE, EXIT, або UNDO)
- zкі дії виконати для обробки станe. В якості дій можуть бути будь-які команди, в тому числі
структури управління.

Якщо в SqlException свстановлюється якийсь стан і немає обробника, процедура завершується і


повертає клієнту повідомлення про помилку.

Типи обробників

Є три типи обробників:

- CONTINUE - Цей обробник використовується для вказівки, що після того, як згенерується виняток і
обробник стану його обробить, потік виконання продовжить роботу з наступної інструкції після
інструкції, яка згенеревала виключення.

- EXIT - цей обробник використовується для вказівки на те, що після виключення і його обробник,
потік виконання переміститься в кінец процедури.

- Undo - Цей обробник використовується для вказівки, що після виникнення винятку і його обробки,
потік виконання переміститься кінця процедури, а всі попередньо виконані дії скасуються.

Рисунок 10 ілюструє різні обробники стану і поведінки.

Виклик вбудованих процедур

Наступні фрагменти коду показує, як для викликати збережені процедур з програм написаних
з використаннням CLI / ODBC і Java.
Dynamic SQL

У динамічних SQL, на відміну від статичного SQL, весь оператор SQL не відомо, під час виконання.
Наприклад, якщо col1 і tabname є змінними в цій заяві, то ми маємо справу з динамічним SQL:

'SELECT ' || col1 || ' FROM ' || tabname;

Динамічний SQL рекомендується для DDL, щоб уникнути проблем з залежностями і пакет
недійсними. Також, необхідних для реалізації рекурсії.
Динамічний SQL може бути виконаний з використанням двох підходів:

- використання EXECUTE IMMEDIATE, підходить для одноразового виконання SQL

- За допомогою директиви PREPARE разом із EXECUTE - це підходить для виконання декількох SQL
запитів

Фрагмент коду, показаний в лістингу, являє собою приклад динамічного SQL за допомогою двох
підходів. У прикладі передбачається, що таблиця T2 була створена з цим визначенням:
CREATE TABLE T2 (c1 INT, c2 INT)

CREATE PROCEDURE dyn1 (IN value1 INT, IN value2 INT)


SPECIFIC dyn1
BEGIN
DECLARE stmt varchar(255);
DECLARE st STATEMENT;
SET stmt = 'INSERT INTO T2 VALUES (?, ?)';
PREPARE st FROM stmt;
EXECUTE st USING value1, value1;
EXECUTE st USING value2, value2;
SET stmt = INSERT INTO T2 VALUES (9,9)';
EXECUTE IMMEDIATE stmt;
END

Користувальницькі функції

Визначені користувачем функції (UDF) цє об'єкти баз даних, що перетворюють набір вхідних значень
даних в набір вихідних значень. Наприклад, функція може приймати значення величини в дюймах в
якості вхідних даних і повертати результат в сантиметрах.

DB2 підтримує створення функцій за допомогою SQL PL, PL/SQL, C/C++, Java, CLR
(Common Language Runtime) і OLE.

Є чотири типи функцій: скалярні, табличні, рядки і стовпці.

Скалярні функції

Скалярні функції повертають одне значення. Скалярні функції, не можуть включати в себе SQL запити,
які змінюють стан бази даних, тобто, INSERT, UPDATE і DELETE.

Деякими вбудованами скалярними функціями є SUM (), AVG (), DIGITS (), COALESCE () і SUBSTR ().

Користувацькі функції створюються з метою інкапсуляції часто використовуваної логіки.


CREATE FUNCTION deptname(p_empid VARCHAR(6))
RETURNS VARCHAR(30)
SPECIFIC deptname
BEGIN ATOMIC
DECLARE v_department_name VARCHAR(30);
DECLARE v_err VARCHAR(70);
SET v_department_name = (
SELECT d.deptname FROM department d, employee e
WHERE e.workdept=d.deptno AND e.empno= p_empid);
SET v_err = 'Error: employee ' || p_empid || ' was not found';
IF v_department_name IS NULL THEN
SIGNAL SQLSTATE '80000' SET MESSAGE_TEXT=v_err;
END IF;
RETURN v_department_name;
END
У наведеному прикладі, функція deptname повертає номер відділу працівника на основі його
ідентифікатора. Скалярні UDF можуть бути викликані через VALUE вирази. Вона також можу бути
викликані включені в SQL запити в будь-якому місці, де вимагається наявність скалярної змінної.
Наприклад:
db2 "values (deptname ('000300'))"

або
db2 "select (deptname ('000300')) from sysibm.sysdummy1"

Зверніть увагу, у другому прикладі, використовується SYSIBM.SYSDUMMY1. Це спеціальна таблиця з


одним рядком і одним стовпцем. Вона використовується для забезпечення того, щоб тільки одне
значення поверталося. Якщо ви застосуєте SELECT з будь-якою іншою таблицею, де буде більше рядків,
функція буде викликатися стільки раз, скільки в таблиці рядків.

Функції таблиці

Табличні функції повертають таблицю рядків. Їх можна використовувати після ключового


слова FROM запиту. Табличні функції, на відміну від скалярних, можуть змінювати стан бази даних,
тому, INSERT, UPDATE і DELETE в допускаються.

Приклади вбудованих табличних функції SNAPSHOT_DYN_SQL () і MQREADALL ().

Табличні функції схожі на представлення (VIEW), але оскільки вони допускають використання
інструкцій зміни даних (INSERT, UPDATE і DELETE), вони є більш потужними. Як правило, вони
використовуються для збереження аудиторських даних.
CREATE FUNCTION getEnumEmployee(p_dept VARCHAR(3))
RETURNS TABLE
(empno CHAR(6),
lastname VARCHAR(15),
firstnme VARCHAR(12))
SPECIFIC getEnumEmployee
RETURN
SELECT e.empno, e.lastname, e.firstnme
FROM employee e
WHERE e.workdept=p_dept

Тригери
The big picture
Тригери

Тригери (triggers) це об'єкти бази даних, пов'язані з


таблицею, які визначають додаткові операції, що
виконуватимуться при здійснені модифікації даних через
запити INSERT, UPDATE, DELETE.

Event-Condition-Action Rules

При виникненні події -> перевірити умови,


якщо вони
виконуються > виконати дії

Тригери

Тригеру активуються автоматично.

Операції, що призводять до активації тригера


(fire trigger) називаються тригерними SQL запитами.
Основна мета:
- перенесення моніторингу логіки роботи з клієнта на
СУБД
- механізм дотримання цілісності (integrity constrains)
предметної області

Підтримка тригерів та їх можливостей суттєво


відрізняється для різних СУБД!

Створення тригера

Create Trigger name


Type Of events
[ referencing-variables ]
[ For Each Row ]
When ( condition )
action

< Type > of events [ For Each Row ]


- before - Тригер виконуватиметься
- after для кожної кортежу
- instead of - Тригер виконується один
раз для запиту

[ referencing-
variables ] insert new data
- Old Row As delete old data
- New Row As update old/new data
- Old Table
- New Table

Приклад тригера

Referential Integrity:
R.A посилається на S.B, реалізація каскадного
видалення (cascaded delete)

Create Trigger Cascade


After Delete On S
Referencing Old Row As O
For Each Row
[ no condition ]
Delete From R Where A = O.B

Create Trigger Cascade


After Delete On S
Referencing Old Table As OT
[ For Each Row ]
[ no condition ]
Delete From R Where A in
(select B from OT)

Before triggers

Before-тригер активується перед тим, як кортеж буде


додано, оновлено чи видалено.
Операції, що виконуються не можуть призвести до
активації іншого тригера, а тому виконання запитів
INSERT, UPDATE чи DELETE в цьому тригері не
допускається.
Приклад використання before trigger

Таблиця розкладу занять (class schedule)


insert into cl_sched (class_code, day, starting)
values ('abc',1,current time)
Тригер для перевірки коректності часу проведення
CREATE TRIGGER validate_sched
NO CASCADE BEFORE INSERT ON cl_sched
REFERENCING NEW AS n
FOR EACH ROW
MODE DB2SQL
BEGIN ATOMIC
-- supply default value for ending time if
null
IF (n.ending IS NULL) THEN
SET n.ending = n.starting + 1 HOUR;
END IF;
-- ensure that class does not end beyond 9pm
IF (n.ending > '21:00') THEN
SIGNAL SQLSTATE '80000'
SET MESSAGE_TEXT='class ending time is
beyond 9pm';
ELSEIF (n.DAY=1 or n.DAY=7) THEN
SIGNAL SQLSTATE '80001'
SET MESSAGE_TEXT='class cannot be
scheduled on a weekend';
END IF;
END

After triggers
After тригери активуються після виконання
дій SQL запиту і до його успішного завершення.

Операції цього тригеру можуть призводити до активації


інших тригерів (допускається каскадне вкладення до 16
рівнів)

Такі тригері підтримують операції INSERT, UPDATE і


DELETE.

CREATE TRIGGER audit_emp_sal


AFTER UPDATE OF salary ON employee
REFERENCING OLD AS o NEW AS n
FOR EACH ROW
MODE DB2SQL
INSERT INTO audit
VALUES ( CURRENT TIMESTAMP, ' Employee ' ||
o.empno || '
salary changed from ' || CHAR(o.salary) ||
' to '
|| CHAR(n.salary) || ' by ' || USER)

Instead of triggers

Instead of тригери визначаються на представленнях


(views).
Так як представлення формуються динамічно за
допомогою виконання SELECT з однієї або декількох
таблицях, то представлення не може бути оновлене.

Використання таких тригерів дозволяє створити ілюзію,


що представлення може бути поновлений, оскільки
логіка, визначена в тригер виконується замість запуску
прямого SQL запиту.

Приклад представлення
СREATE VIEW EMPV(EMPNO, FIRSTNME, MIDINIT,
LASTNAME, PHONENO,
HIREDATE, DEPTNAME)
AS SELECT EMPNO, FIRSTNME, MIDINIT, LASTNAME,
PHONENO,
HIREDATE, DEPTNAME
FROM EMPLOYEE, DEPARTMENT
WHERE EMPLOYEE.WORKDEPT = DEPARTMENT.DEPTNO
Операція INSERT
CREATE TRIGGER EMPV_INSERT INSTEAD OF INSERT ON EM
PV
REFERENCING NEW AS NEWEMP FOR EACH ROW
INSERT INTO EMPLOYEE (EMPNO, FIRSTNME, MIDINIT,
LASTNAME,
WORKDEPT, PHONENO, HIREDATE)
VALUES(EMPNO, FIRSTNME, MIDINIT, LASTNAME,
COALESCE(
(SELECT DEPTNO FROM DEPARTMENT AS D
WHERE D.DEPTNAME = NEWEMP.DEPTNAME),
RAISE_ERROR('70001', 'Unknown dept name')),
PHONENO, HIREDATE)

Операція DELETE
CREATE TRIGGER EMPV_DELETE INSTEAD OF DELETE ON EM
PV
REFERENCING OLD AS OLDEMP FOR EACH ROW
DELETE FROM EMPLOYEE AS E WHERE E.EMPNO =
OLDEMP.EMPNO

Операція UPDATE
CREATE TRIGGER EMPV_UPDATE INSTEAD
OF UPDATE ON EMPV
REFERENCING NEW AS NEWEMP OLD AS OLDEMP FOR EACH
ROW
BEGIN ATOMIC
VALUES(CASE WHEN NEWEMP.EMPNO = OLDEMP.EMPNO THEN
0
ELSE RAISE_ERROR('70002', 'Must not change
EMPNO') END);
UPDATE EMPLOYEE AS E
SET (FIRSTNME, MIDINIT, LASTNAME, WORKDEPT,
PHONENO, HIREDATE)
= (NEWEMP.FIRSTNME, NEWEMP.MIDINIT,
NEWEMP.LASTNAME, COALESCE(
(SELECT DEPTNO FROM DEPARTMENT AS D
WHERE D.DEPTNAME = NEWEMP.DEPTNAME),
RAISE_ERROR ('70001', 'Unknown dept name')),
NEWEMP.PHONENO, NEWEMP.HIREDATE)
WHERE NEWEMP.EMPNO = E.EMPNO;
END

Приклади
Завдання:
Нові студенти з GPA > 4 автоматично записуються на напрям
прогрaмна інженерія та компютерні науки в ТНТУ

CREATE TRIGGER R1
AFTER INSERT ON STUDENT
FOR EACH ROW
WHEN NEW.GPA > 4
BEGIN
INSERT INTO APPLY VALUES (NEW.SID, TNTU, 'SE',
NULL);
INSERT INTO APPLY VALUES (NEW.SID, 'TNTU', 'CS',
NULL);
END;

Приклади
Завдання:
Каскадне видалення з таблиці заявок (apply) при видаленні
студента

CREATE TRIGGER R2
AFTER DELETE ON STUDENT
FOR EACH ROW
BEGIN
DELETE FROM APPLY WHERE SID = OLD.SID;
END;

Приклади
Завдання:
Каскадне оновлення назви вузу в таблиці заявок(apply) при її
зміні в таблиці вузів (univ)

CREATE TRIGGER R3
AFTER UPDATE OF UNAME ON UNIV
FOR EACH ROW
BEGIN
UPDATE APPLY
SET UNAME = NEW.UNAME
WHERE UNAME = OLD.CNAME;
END;

Приклади
Завдання:
Перевірка унікальності назви університету (uname)

CREATE TRIGGER R4
BEFORE INSERT ON UNIV
FOR EACH ROW
WHEN EXISTS (SELECT * FROM UNIV WHERE UNAME =
NEW.UNAME)
BEGIN
SELECT RAISE(IGNORE);
END;

Приклади
Завдання:
Коли кількість заявок у вуз перевищує 100, позначити його як
заповнений (додати до назви done)

CREATE TRIGGER R6
AFTER INSERT ON APPLY
FOR EACH ROW
WHEN (SELECT COUNT(*) FROM APPLY WHERE CNAME =
NEW.CNAME) > 100
BEGIN
UPDATE UNIV SET UNAME = UNAME || '-DONE'
WHERE UNAME = NEW.UNAME;
END;
Приклади
Завдання:
При зменшенні обсягу замовлення для університету із > 1000
до < 1000, видалити усій заявки на спеціальність
зварювання (ZV) і змінити рішення (DECISION) для вже
прийнятих (Y)студентів на невизначене (U)

CREATE TRIGGER TOOMANY


AFTER UPDATE OF ENROLLMENT ON UNIV
FOR EACH ROW
WHEN
(OLD.ENROLLMENT => 1000 AND NEW.ENROLLMENT < 1000)
BEGIN
DELETE FROM APPLY
WHERE UNAME = NEW.UNAME AND MAJOR = 'ZV';
UPDATE APPLY
SET DECISION = 'U'
WHERE UNAME = NEW.UNAME
AND DECISION = 'Y';
END;

Обєктно-реляційний
мапінг
(ORM)

Що таке ORM
ORM або Object - relational mapping (Об'єктно-
реляційне відображення ) - це технологія програмування
, яка дозволяє перетворювати несумісні типи моделей в
ООП , зокрема , між сховищем даних і об'єктами
програмування.

ORM використовується для спрощення процесу


збереження об'єктів в реляційну базу даних та їх
вилучення , при цьому ORM сама піклується про
перетворення даних між двома несумісними станами.

Вирішує проблему невідповідності між представленням


даних в реляційних базах даних та обєктно-орієнтованих
мовах програмування (наприклад Java, C#).

Основні переваги від використання ORM

1. Дозволяє логіці програми працювати з обкатами а не з


таблиця БД

2. Приховує деталі SQL запитів від обєктів ООП

3. Не потрібно мати справу з реалізацією Бази даних


4. Керування транзакціями та автоматичне управління
ключами

5. Швидка розробка застосунків

Основні переваги від використання ORM

1. Дозволяє логіці програми працювати з обкатами а не з


таблиця БД

2. Приховує деталі SQL запитів від обєктів ООП

3. Не потрібно мати справу з реалізацією Бази даних

4. Керування транзакціями та автоматичне управління


ключами

5. Швидка розробка застосунків

ORM складається з таких елементів:

1.API для виконання базових CRUD-операцій на обєктами


класів
2. Мова чи API для задання запитів що стосуються класів
чи їх атрибутів

3. Конфігурації для визначення метаданих

4. Функції оптимізації.

Приклади ORM Framework

Java C#
- Enterprise JavaBeans - ADO.NET Entity Framework,
Entity Beans
- Business Logic Toolkit
- Java Data Objects - DataObjects.NET,
- Castor
- iBATIS,
- TopLink
- LINQ to SQL,
- Spring DAO
- Persistor.NET
- OpenJPA
- NHibernate,
- Hibernate

C++ PHP
- LiteSQL - CakePHP
- ODB - Doctrine,
- Wt::Dbo - Redbean
- QxOrm - Torpor,
- Yii,
- Zend Framework,

Source: http://en.wikipedia.org/wiki/List_of_object-relational_mapping_software

Hibernate

ORM фреймворк для мови Java, виник як open-


source проект в 2001 році.
Архітектура Hibernate
Hibernate Configuration

hibernate.dialect Вибір СУБД

hibernate.connection.driver_class Клас JDBC драйвера

hibernate.connection.url URL до запущеного СУБД

hibernate.connection.username Імя користувача для авторизації

hibernate.connection.password Пароль для авторизації

hibernate.connection.pool_size Розмір пулу зєднань

hibernate.connection.autocommit Увімкнення режиму автомкоміту


Hibernate Configuration

hibernate.dialect Вибір СУБД

hibernate.connection.driver_class Клас JDBC драйвера

hibernate.connection.url URL до запущеного СУБД

hibernate.connection.username Імя користувача для авторизації

hibernate.connection.password Пароль для авторизації

hibernate.connection.pool_size Розмір пулу зєднань

hibernate.connection.autocommit Увімкнення режиму автомкоміту

Підтримувані СУБД

DB2 org.hibernate.dialect.DB2Dialect

HSQLDB org.hibernate.dialect.HSQLDialect

HypersonicSQL org.hibernate.dialect.HSQLDialect

Informix org.hibernate.dialect.InformixDialect

Ingres org.hibernate.dialect.IngresDialect

Interbase org.hibernate.dialect.InterbaseDialect

Microsoft SQL Server 2000 org.hibernate.dialect.SQLServerDialect

Microsoft SQL Server 2005 org.hibernate.dialect.SQLServer2005Dialect

Microsoft SQL Server 2008 org.hibernate.dialect.SQLServer2008Dialect

MySQL org.hibernate.dialect.MySQLDialect
Oracle (any version) org.hibernate.dialect.OracleDialect

Oracle 11g org.hibernate.dialect.Oracle10gDialect

Oracle 10g org.hibernate.dialect.Oracle10gDialect

Oracle 9i org.hibernate.dialect.Oracle9iDialect

PostgreSQL org.hibernate.dialect.PostgreSQLDialect

Progress org.hibernate.dialect.ProgressDialect

SAP DB org.hibernate.dialect.SAPDBDialect

Sybase org.hibernate.dialect.SybaseDialect

Sybase Anywhere org.hibernate.dialect.SybaseAnywhereDialect

Приклад конфігураційного файлу:

hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>

<!-- Assume test is the database name -->


<property name="hibernate.connection.url">
jdbc:mysql://localhost/test
</property>
<property name="hibernate.connection.username">
root
</property>
<property name="hibernate.connection.password">
root123
</property>

<!-- List of XML mapping files -->


<mapping resource="Employee.hbm.xml"/>

</session-factory>
</hibernate-configuration>

Hibernate Persistent Class

Persistent class це клас, екземпляри яких будуть


зберігатися в таблицях БД

Такі класи повинні слідувати певним правилам, відомим


як POJO (Plain Old Java Object)

- клас повинен мати конструктор по замовчуванню


- клас повинен містити поле ID
- усі атрибути класу, які зберігатимуться в таблиці БД
повинні мати публічні гетери і сетери з
назвами getXXX та setXXX

Приклад POJO класу


public class Employee {
private int id;
private String firstName;
private String lastName;
private int salary;

public Employee() {}
public Employee(String fname, String lname, int salary) {
this.firstName = fname;
this.lastName = lname;
this.salary = salary;
}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName( String first_name ) {
this.firstName = first_name;
}
public void setLastName( String last_name ) {
this.lastName = last_name;
}
public int getSalary() {
return salary;
}
public void setSalary( int salary ) {
this.salary = salary;
}

Таблиця, що відповідає класу:


create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);

Таблиця, що відповідає класу:


create table EMPLOYEE (
id INT NOT NULL auto_increment,
first_name VARCHAR(20) default NULL,
last_name VARCHAR(20) default NULL,
salary INT default NULL,
PRIMARY KEY (id)
);

Файл employee.hbm.xml
<?xml version="1.0" encoding="utf-8"
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="Employee" table="EMPLOYEE">
<meta attribute="class-description">
This class contains the employee detail.
</meta>
<id name="id" type="int" column="id">
<generator class="native"/>
</id>
<property name="firstName" column="first_name" type="string"/>
<property name="lastName" column="last_name" type="string"/>
<property name="salary" column="salary" type="int"/>
</class>
</hibernate-mapping>

@Entity
@Table(name = "EMPLOYEE")
public class Employee {
@Id @GeneratedValue
@Column(name = "id")
private int id;

@Column(name = "first_name")
private String firstName;

@Column(name = "last_name")
private String lastName;

@Column(name = "salary")
private int salary;

public Employee() {}
public int getId() {
return id;
}
public void setId( int id ) {
this.id = id;
}
public String getFirstName() {
return firstName;
...

Створення інтерфейсу для взаємодії з СУБД

public interface EmployeeDAO {


public void addEmployee (Employee employee) throws SQLException;
public void updateEmployee (Employee employee) throws SQLException;
public Employee getEmployeeById(Long id) throws SQLException;
public List getAllEmployee () throws SQLException;
public void deleteEmployee (Employee employee) throws SQLException;
}

Реалізація інтерфейсу EmployeeDAO

public class EmployeeDAOImpl implements EmployeeDAO {


public void addEmployee (Employee emp) throws SQLException {
Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession(
);
session.beginTransaction();
session.save(emp);
session.getTransaction().commit();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
e.getMessage(), "Error I/O", JOptionPane
.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
}

public void updateEmployee (Employee emp) throws SQLException {


Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession(
);
session.beginTransaction();
session.update(emp);
session.getTransaction().commit();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
e.getMessage(), "Error I/O", JOptionPane.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
}

public Employee getEmployeeById(Long id) throws SQLException {


Session session = null;
Student emp = null;
try {
session = HibernateUtil.getSessionFactory().openSession(
);
emp = (Employee) session.load(Employee.class, id);
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
e.getMessage(), "Error I/O", JOptionPane.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
return emp;
}

public List<Employee> getAllEmployee () throws SQLException {


Session session = null;
List<Employee> emps = new ArrayList<Employee>();
try {
session = HibernateUtil.getSessionFactory().openSession(
);
studs = session.createCriteria(Employee.class).list();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
e.getMessage(), "Error I/O", JOptionPane.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
return emps;
}

public void deleteEmployee (Employee emp) throws SQLException {


Session session = null;
try {
session = HibernateUtil.getSessionFactory().openSession(
);
session.beginTransaction();
session.delete(emp);
session.getTransaction().commit();
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
e.getMessage(), "Error I/O", JOptionPane.OK_OPTION);
} finally {
if (session != null && session.isOpen()) {
session.close();
}
}
}
}

Оптимізація виконання запитів

Виконання запитів в Oracle. Загальна схема і взаємодія з клієнтським


дотком і машиною PL/SQL
Всі SQL-запити, які поступають в СУБД, обробляються приблизно по одній схемі.
На першій фазі запит, заданий на мові запитів, піддається лексичному і синтаксичному
аналізу. При цьому виробляється його внутрішнє уявлення, яке відображає структуру запиту
і містить інформацію, яка характеризує обєкти бази даних, які згадані в запиті (відношення,
поля і константи). Інформація про обєкти які зберігаються в базі даних вибирається з
каталогу бази даних. Внутрішня уява запиту використовується і перетворюється на
наступних стадіях обробки запиту.
На другій фазі запит у внутрішньому поданні піддається логічній оптимізації. Можуть
застосовуватись різні перетворення, "поліпшуючі" початкове представлення запиту. Серед
перетворень можуть бути еквівалентні, після проведення яких виходить внутрішнє
уявлення, семантично еквівалентне початковому (наприклад, приведення запиту до деякої
канонічної форми), Перетворення можуть бути і семантичними: одержуване представлення
не являється семантично еквівалентним початковому, але гарантується, що результат
виконання перетвореного запиту співпадає з результатом запиту в початковій формі при
дотриманні обмеженої цілісності, існуючих в базі даних. Після виконання другої фази
обробка запиту його внутрішнє уявлення залишається непроцедурним, хоча і являється в
деякому смислі більш ефективним, чим початкове.
Третій етап обробки запиту складається в виборі на основі інформації, який має в своєму
розпорядженні оптимізатор, набору альтернативних процедурних планів виконання даного
запиту в відповідності з його внутрішнім уявленням, отриманим на другій фазі. Для кожного
плану оцінюється передбачувана вартість виконання запиту. При оцінках використовується
статистична інформація про стан бази даних, доступна оптимізатору. Із отриманих
альтернативних планів вибирається найбільш дешевий, і його внутрішнє уявлення тепер
відповідає оброблюваному запиту.
На четвертому етапі по внутрішньому уявленні найбільш оптимального плану виконання
запиту формується виконуване подання плану.
Нарешті, на пятому етапі обробки запиту відбувається його реальне виконання.
Оптимізатор. Його призначення. Етапи роботи оптимізатора
Одною з основних переваг реляційних СУБД являється механізм запитів на основі
декларативної мови запитів SQL. При формулюванні запиту користувач вказує ЩО він
хоче отримати, и а за те ЯК це отримати, відповідає СУБД. Оскільки існує потенційно дуже
велика безліч способів виконати конкретний запит (комбінація способів і порядку зєднання
таблиць, шляхів доступу до даних і т.д.), зявляється задача вибрати з всієї безлічі способів
виконання запиту оптимальний. За цю задачу відповідає оптимізатор запитів.
Функція оптимізатора - вибрати найбільш оптимальний (виходячи з набору критеріїв) план
план виконання запиту. При формуванні оптимального плану, оптимізатор вирішує наступні
задачі
1. Обчислення виразів і операцій
2. Перетворення SQL операторів
3. Вибір способу оптимізації - по вартості або по правилам
4. Вибір шляхів доступу
5. Вибір порядку зєднання таблиць
6. Вибір методу зєднання таблиць
7. Визначення найбільш ефективного плану виконання
В Oracle реалізовано два підходи до оптимізації запиту, які відрізняються у виборі
критеріїв оптимізації.
o Оптимізація по правилах (RULE BASED). Підхід, при якому враховуються тільки
способи доступу до даних, із зафіксованими пріоритетами по ефективності
доступу. Даний підхід використовувався в різних версіях ORACLE і володіє
суттєвим недостатком - він не враховує реального розподілу даних.
o Оптимізація по вартості (COST BASED). Крім ефективності різних шляхів
доступу до даних, враховується тако ж статистика по розподілу даних і
ресурсів операційної системи.

Режим роботи оптимізатора по вартості. Установка режимів. Параметри,


що впливають на роботу оптимізатора
CBO керується статистикою. Причому, коли він вираховує вартість, він враховує кількість
блоків в таблиці, кількість рядків, кількість різних значень індексів і так дальше. Щоб він
коректно працював, статистику необхідно регулярно збирати. Робота оптимізатора
керується параметром optimizer_mode, який може вказувати на рівень сесії або на рівні
екземпляру. Він може мати наступні значення.
optimizer_mode = rule - RBO (був заморожений в версії 7), RBO, наприклад, не вміє
користуватися Bitmap індексами.
optimizer_mode = all_rows - CBO, вибирає план виконання з оптимальною вартістю, режим
роботи оптимізатора по замовчуванню.
optimizer_mode = first_rows - CBO, обчислюється вартість різних планів виконання,
вибирає кілька планів з оптимальною вартістю, по різних евристичним міркуванням
намагається вибрати план, який більш швидше повертає перші рядки.
optimizer_mode = choose - Oracle сам вибирає, який режим оптимізатора вибрати Самий
поганий випадок встановлений даний режим і по якимось таблицях є статистика, а по
якихось нема. Наприклад, якщо хоча б по одній з таблиць в запиті статистика є, то в
більшості випадків буде використовуватись all_rows, а якщо ні по одній з таблиць немає,
то - rule. якщо RBO не підтримує інтерфейс запиту (наприклад, Bitmap-індекси), то
використовується CBO. CBO може оптимізувати запити по таблицях, по яких не зібрана
статистика, викорисовуєчи замовчування для таблиць.
optimizer_mode = first_rows_1, first_rows_10, first_rows_1000 - при
використанні first_rows Oracle обчислюється вартість виконання всього оператора, потім
вибирається оптимальний план, при використанні first_rows_n обчислює вартість
отримання перших n рядків, а вартість всього оператора не обчислюється (ці режими
оптимальні для форм і перших операторів ).
Приклад:

alter session set optimizer_mode= first_rows;

Статистика. Призначення, способи формування


Відсутність статистики оптимізатора або застарілі статистичні дані часто являються
причиною неоптимальної продуктивності обробки запитів. Оптимізатор, який працює на
основі вартості, використовує для визначення вартості шляхи доступу такої статистики, як
число елементів (cardinality) таблиці, число можливих значень стовпця і розподілу даних.
Вартість являється мірою того, скільки памяті, ресурсів процесора і каналів вводу-виводу
необхідно для виконання запиту. Щоб ефективно використовувати опимізатор, працюючий
на основі вартості, потрібно зібрати статистику числа елементів (cardinality) і розподілу
даних для кожної таблиці, індексу і матеріалізованого представлення. Статистика
збирається з допомогою пакету DBMS_STATS. Статистичні дані можна збирати або шляхом
читання всіх рядків, або шляхом проведення оцінки на основі читання тільки невеликого
відбору рядків або блоків. В пакеті DBMS_STATS пропонуються процедури для збору
статистики рівня бази даних, схеми або таблиці, а також розділу таблиці.
Збір статистики з допомогою analyze

analyze table t compute statistics for


table for all indexes for all columns;
analyze table t compute statistics for table for
all indexes for all indexed columns;
analyze table t compute statistics for table for
columns i, s;

analyze index t_i compute statistics for table for


all indexes for all columns;

analyze table t estimate statistics for table for


all indexes for all columns sample 10 rows;
analyze table t estimate statistics for table for
all indexes for all columns sample 10 percent;

analyze table t compute statistics for table for


all indexes for all columns size 100;
analyze table t compute statistics for table for
columns i size 100, s size 200;
Збір статистики з допомогою пакету dbms_stats

execute dbms_stats.gather_index_stats(ownname=>'stud',
indname=>'i', partname=>null, estimate_percent=>50, stattab=>null, statid=>null,
statown=>null);

execute dbms_stats.gather_table_stats(ownname=>'stud',
tabname=>'t', partname=>null, estimate_percent=>50, block_sample=>false,
method_opt=>'FOR ALL COLUMNS', degree=>null,
cascade=>true, stattab=>null, statid=>null, statown=>null);

execute dbms_stats.gather_table_stats(ownname=>'stud',
tabname=>'t', partname=>null, estimate_percent=>50, block_sample=>false,
method_opt=>'FOR COLUMNS object_name, object_id',
degree=>null, cascade=>true, stattab=>null,
statid=>null, statown=>null);

execute dbms_stats.gather_schema_stats(ownname=>'stud',
estimate_percent=>50, block_sample=>false, method_opt=>'FOR ALL COLUMNS',
degree=>null, cascade=>true, stattab=>null, statid=>null, statown=>null);

execute dbms_stats.delete_index_stats(ownname=>'stud',
indname=>'i', partname=>null, stattab=>null, statid=>null, statown=>null);

execute dbms_stats.delete_table_stats(ownname=>'stud',
tabname=>'t', partname=>null, stattab=>null, statid=>null,
statown=>null, cascade_parts=>true, cascade_columns=>true);

execute dbms_stats.delete_schema_stats(ownname=>'stud', stattab=>null,


statid=>null, statown=>null);
Листинг 12.1.

Статистика по таблицях

Дані по статистиці таблиць можна подивитись в словнику USER_TABLES. Основна статистика


-
 кількість рядків
 кількість блоків
 кількість пустих блоків
 середній доступний вільний простір
 кількість рядків які мігрували
 середня довжина рядка
Приклад:

select * from user_tables where table_name = 'T';

analyze table t delete statistics;

select num_rows, blocks, empty_blocks, avg_space,


chain_cnt, avg_row_len, avg_space_freelist_blocks,
num_freelist_blocks, sample_size, last_analyzed from user_tables
where table_name = 'T';

analyze table t compute statistics for table;

select num_rows, blocks, empty_blocks, avg_space,


chain_cnt, avg_row_len, avg_space_freelist_blocks,
num_freelist_blocks, sample_size, last_analyzed from user_tables
where table_name = 'T';

Статистика по індексах

Статистику по індексах можна подивитись в словнику USER_INDEXES. Основна статистика -


 глибина індексу
 кількість листових блоків
 кількість різних ключів
 середня кількість листових блоків на ключ
 середня кількість блоків даних на ключ
 кількість вузлів індексу
 фактор кластеризації (кількість блоків, яке необхідно вибрати для вибірки всіх рядків
з таблиці по індексу)
Приклад:

analyze table t delete statistics;

select blevel, leaf_blocks, distinct_keys,


avg_leaf_blocks_per_key, avg_data_blocks_per_key,
clustering_factor, num_rows, sample_size,
last_analyzed from user_indexes
where table_name = 'T' and index_name = 'T_I';

analyze table t compute statistics for all indexes;

select blevel, leaf_blocks, distinct_keys,


avg_leaf_blocks_per_key, avg_data_blocks_per_key,
clustering_factor, num_rows, sample_size,
last_analyzed from user_indexes
where table_name = 'T' and index_name = 'T_I';

Статистика по стовпцях

Статистику по стовпцях можна подивитись в


словнику USER_TAB_COLUMNS, USER_TAB_COL_STATISTICS. Статистика -
 кількість різних зачень
 мінімальне значення
 максимальне значення
 кількість null
Приклад:

select * from user_tab_columns where table_name =


'T' and column_name = 'I';
select * from user_tab_col_statistics where table_name =
'T' and column_name = 'I';

analyze table t delete statistics;

select * from user_tab_col_statistics where table_name =


'T' and column_name = 'I';

analyze table t compute statistics for all columns;

select * from user_tab_col_statistics where table_name =


'T' and column_name = 'I';
Дана статистика не містить одну дуже важливу інформацію - розподілення значень по
діапазонах. Для зберігання цієї інформації використовуються гістограми. Існує два типи
гістограм частотні гістограми і збалансовані по висоті. Максимальна кількість брикетів в
гістограмі - 254. Якщо кількість різних значень в стовпці менше вказаного розміру
гістограми, то будується частотна гістограма. В іншому випадку - збалансована по висоті.
Збалансовані по висоті гістограми містять однакову кількість рядків в кожному брикеті
гістограми. Значення комірки відповідає максимальному значенню стовпця в групі. Частотні
гістограми містять стільки брикетів, скільки є різних значень в стовпці. Значення комірки
містить кількість рядків із значеннями стовпця, меншого або рівного даному.
Приклад:

analyze table t compute statistics for columns s size 254;


select endpoint_number, endpoint_value,
substr(endpoint_actual_value, 1, 30)
from user_tab_histograms where table_name =
'T' and column_name = 'S';

analyze table t compute statistics for columns s size 8;

select endpoint_number, endpoint_value,


substr(endpoint_actual_value, 1, 30)
from user_tab_histograms where table_name =
'T' and column_name = 'S';

analyze table t compute statistics for columns s size 254;

select endpoint_number, endpoint_value,


substr(endpoint_actual_value, 1, 30)
from user_tab_histograms where table_name =
'T' and column_name = 'S';

select s, count(*) from t group by s;

Шляхи доступу до даних


Підготовка даних

-- створення обєктів
drop table h;

-- create table h(p number constraint pk primary key,


s varchar2(100) null, n number null,
nu number null constraint un unique);
create table h(p number, s varchar2(100) null,
n number null, nu number null);

Повне сканування таблиці. Переваги, недоліки


Для вибірки даних проводиться пребір всіх рядків таблиці, повертаються рядки які підходять
під умови запиту. Може бути ефективнішим використання індексу у випадках коли
необхідно вибрати >25-30% записів в таблиці. Виникає проблема High Water Mark.

-- повне сканування таблицуі. high water mark

insert into h select -rownum, object_name,


object_id, object_id from all_objects where rownum < 100;

insert into h select rownum, object_name,


object_id, object_id from all_objects;

select * from h where p < 0;

analyze table h compute statistics for table for


all columns for all indexes;
select num_rows, blocks, empty_blocks from
user_tables where table_name = 'H';

delete from h where p > 0;

Класичні індекси
Індекси на основі В*-дарева найбільш широко використовуваний тип індексної структури в
базі даних. По реалізації вони подібні бінарному дереву пошуку. Мета їх створення
мінімізувати час пошуку даних сервером Oracle. При наявності індексу по числовому
стовпцю, структура індексу може виглядати так:
Блоки самого нижчого рівня в індексі, які називають листовими вершинами, містять всі
проіндексовані ключі і ідентифікатори рядків (rid на схемі), що посилаються на відповідні
рядки. Проміжні блоки над листовими вершинами називають блоками розгалуження. Вони
використовуються для переходу по структурі. Наприклад, якщо необхідно знайти в індексі
значення 42, потрібно почати з вершини дерева і рухатись вправо. При перевірці цього
блоку виявляється, що необхідно перейти до блоку в діапазоні "от 40 до 50". Цей блок
виявляється листовим і посилається на рядки, які містять число 42. Цікаво відмітити, що
листові блоки фактично утворюють двохзвязний список. Як тільки знайдено "початок" серед
листових вершин, тобто перше значення, дуже легко переглядати значення по порядку (це
називають також переглядом діапазону по індексу, index range scan). Проходити по
структурі індексу більше не потрібно; ми просто переходим по листових вершинах. Це
суттєво спрощує пошук рядків по умовах слідуючого типу:

where x between 20 and 30

-- індекси
-- структура індексу, rowid
truncate table h;
insert into h select rownum, object_name,
object_id, object_id from all_objects where rownum < 10;
commit;

select rowid, p from h;

select * from h where rowid =


'AAAN95AAEAAAAfHAAA';

declare
r_t number;
o_n number;
f_n number;
b_n number;
r_n number;
r rowid;
begin
select rowid into r from h where rownum < 2;

dbms_rowid.rowid_info(r, r_t, o_n, f_n, b_n, r_n);

dbms_output.put_line('rowid type = ' || r_t);


dbms_output.put_line('object number = ' || o_n);
dbms_output.put_line('file number = ' || f_n);
dbms_output.put_line('block number = ' || b_n);
dbms_output.put_line('row number = ' || r_n);
end;

select * from user_objects where object_name = 'H';


select * from user_tables where table_name = 'H';
select * from dba_data_files;

-- створення індексів
truncate table h;

insert into h select rownum, object_name, object_id, object_id from all_objects;

commit;

create index ind_s on h(s);


select * from user_indexes where table_name = 'H';
drop index ind_s;
select * from user_indexes where table_name = 'H';

create index ind_s_1 on h(s desc);


create unique index ind_n on h(n);

select index_name, index_type, table_name, status, funcidx_status from user_inde


xes where table_name = 'H';

-- информация по таблицам и индексам


select * from user_tables;
select * from user_tab_columns;
select * from user_constraints;
select * from user_cons_columns;
select * from user_indexes;
select * from user_ind_columns;
Листинг 12.2.

Доступ до таблиць по індексах

analyze table h compute statistics for table for all indexes for all indexed col
umns;

set autotrace on
set timing on

-- операции по индексу
drop index ind_s on h(s);
select * from h where s = 'aaaa';

create index ind_s on h(s);


select * from h where s = 'aaaa';

select * from h where s||'a' = 'aaaa';


select * from h where upper(s) = 'aaaa';

select * from h where s like 'aaaa%';


select * from h where s like '%aaaa';

drop index ind_nu;


select * from h where nu = 1222;

create index ind_nu on h(nu);


select * from h where nu = 1222;

select * from h where nu+1 = 1222;


select * from h where nu = 1222+1;
select * from h where abs(nu) = 1222;
select * from h where s = '123';
select * from h where s = 123;

-- вибір між доступом по індексах і full scan


delete from h;

insert into h(p, s, n, nu) select object_id, object_name, object_id, object_id f


rom all_objects where rownum < 5;

analyze table h compute statistics for table for all indexes for all indexed col
umns;

select * from h where s = 'DUAL';

delete from h;

insert into h(p, s, n, nu) select object_id, object_name, object_id, object_id f


rom all_objects;

-- зі старою статистикою !!!


select * from h where s = 'DUAL';

analyze table h compute statistics for table for all indexes for all indexed col
umns;

-- з новою статистикою !!!


select * from h where s = 'DUAL';

-- обробка null значень

-- поля null не перевіряються на унікальність


insert into h(p, s, n, nu) values(-1, 'asd', null, null);
insert into h(p, s, n, nu) values(-2, 'asd', null, null);
insert into h(p, s, n, nu) values(-3, 'asd', null, -1);

select * from h where s is null;


Лістинг 12.3.

Функціональні індекси
Індекси по функції. Ці індекси на основі В*-дерева або бітових карт зберігають вирахуваний
результат застосування функції до стовпця або стовпцям рядка, а не самі дані рядка. Це
можна використовувати для прискорення виконання запиту виду:

SELECT * FROM T WHERE ФУНКЦІЯ(СТОВПЕЦЬ) = ДЕЯКЕ_ЗНАЧЕННЯ,


оскільки значення ФУНКЦІЇ(СТОВПЕЦЬ) вже обчислено і зберігається в індексі.

-- функціональні індекси
select * from h where n*n = 100;

-- необхідно мати такі права для створення функціональних індексів


alter system set query_rewrite_enabled=true;
grant query rewrite to stud;

create index ind_f_n on h(n*n);

select * from h where n*n = 100;

create index ind_n on h(n);

select index_name, index_type, table_name,


status, funcidx_status from user_indexes where table_name =
'H';
select * from h where n = 100;
select * from h where n > 0;

Бітові індекси
Зазвичай в В*-дереві є однозначна відповідність між записом індексом і рядком - запис
індексу вказує на рядок. В індексі на основі бітових карт запис використовує бітову карту
для посилання на більшу кількість рядків одночасно. Такі індекси підходять для даних з
невеликою кількістю різних значень, які звичайно тільки читаються. Стовпець, який має
всього три значення Y, N і NULL, в таблиці з мільйоном рядків дуже добре підходить для
створення індексу на основі бітових карт. Припустимо, створюється індекс на основі бітових
карт по стовпцю JOB в таблиці ЕМР:

create BITMAP index job_idx on emp(job);


Сервер Oracle буде зберігати в індексі приблизно таке:

Це показує, що в рядках 8, 10 і 13 знаходиться значення ANALYST, тоді як в рядках 4, 6 і 7


значення MANAGER. Також ясно, що порожніх рядків немає (індекси на основі бітових карт
містять записи для порожніх значень відсутність такого запису в індексі означає, що
порожніх рядків немає). Якщо необхідно порахувати, в скількох рядках зберігається
значення MANAGER, індекс на основі бітових карт дозволить зробити це дуже швидко. Якщо
необхідно заняйти всі рядки, в яких в стовпці JOB зберігається значення CLERK або MANAGER,
достатньо просто скомбінувати відповідні бітові карти з індексу.

-- bitmap індекси
drop table bt;

create table bt(n number, s varchar2(100), b number, i number);

select min(object_id), max(object_id), 0.5*(max(object_id)+min(object_id)) from a


ll_objects;

delete from bt;

insert into bt(n, s, b, i)


select object_id, object_name, case when object_id > 36116 then 1 else 2 end, ca
se when object_id > 36116 then 1 else 2 end from all_objects;

create index ibt_i on bt(i);


create bitmap index ibt_b on bt(b);

select index_name, index_type, table_name, status, funcidx_status from user_inde


xes where table_name = 'BT';

analyze table bt compute statistics for table for all indexes for all indexed co
lumns;

select i from bt where i = 1;


select b from bt where b = 1;

drop index ibt_i;


create bitmap index ibt_i on bt(i);
select * from bt where i = 0 or b = 0;
select * from bt where i = 1 or b = 0;

drop index ibt_i;


create index ibt_i on bt(i);

select /*+ index(bt ibt_b) */ * from bt where b = 1;


select /*+ index(bt ibt_i) */ * from bt where i = 1;

select count(*) from bt where b = 1;


select count(*) from bt where i = 1;

update bt set b = null where rownum < 100;


update bt set i = null where rownum < 100;

select * from bt where i is null;


select * from bt where b is null;
Листинг 12.4.

Індекс-організовані таблиці
Індекс-організовані таблиці - кластерні індекси, в індексі зберігаються значення стовпців,
вибраних для індексу, зєднанні в одне значення. Індекс-організовані таблиці мають
фіктивний rowid - значення індексу. При запиті здійснюється швидке сканування індексів.
Використовування кластерних індексів здаьне помітно збільшити продуктивність пошуку
даних навіть по порівнянню з некластерними індексами, особливо при роботі з
послідовностями даних. В якості кластерного індексу слід вибирати стовпці, що найбільш
часто задаються в якості критеріїв пошуку. При цьому не слід викорисовувати для
індексування дуже довгі стовпці. Кластерний індекс може включати кілька стовпців, але
кількість стовпців кластерного індексу слід по можливості звести до мінімуму. Слід уникати
створення кластерного індексу для часто змінюваних стовпців, так як сервер повинен буде
виконувати фізичне переміщення всіх даних в таблиці, щоб вони знаходились в
упорядкованому стані, як того потребує кластерний індекс. Для інтенсивно змінюваних
стовпців більше підходить не кластерний індекс .
індекс-організовані таблиці

drop table ih;

create table ih(p number constraint ipk primary key, s varchar2(100) null, n num
ber null, nu number null constraint iun unique)
organization index;

select constraint_name, constraint_type, table_name, index_name from user_constr


aints where table_name = 'IH';
select index_name, index_type, table_name, status, funcidx_status from user_inde
xes where table_name = 'IH';

insert into ih(p, s, n, nu) select object_id, object_name, object_id, object_id f


rom all_objects;

analyze table ih compute statistics for table for all indexes for all indexed co
lumns;

commit;

select * from ih where s = 'h';

select s from ih where p = 123;

create index iind_s on ih(s);


analyze table ih compute statistics for table for all indexes for all indexed co
lumns;

select * from ih where s = 'h';

-- фактично це не сегмент таблиці, а сегмент індексу


select * from user_segments where segment_name in ('H', 'IH', 'PK', 'IPK');

-- відсутність full table scan замість цього fast full scan


select * from ih;

-- відсутність rowid в індексних таблицях


select rowid from ih where rownum < 10;
Лістинг 12.5.

Принципи побудови запитів для ефективного використання індексів


Повного сканування таблиці при запиті, в тому числі і в Oracle, намагаються уникнути, для
цього використовують індекси. При виборі стовпця для індексу слід проаналізувати, які типи
запитів частіше всього виконуються користувачем, і які стовпці являються ключовими. Не
слід індексувати стовпці, які тільки зчитуються і не грають ніякої ролі в визначені порядку
виконання запиту. Не слід індексувати дуже довгі стовпці, наприклад, стовпці з адресами
або назвами компаній, які досягають девжини декількох десятків символів, так як
індексування довгих стовпців може суттєво знизити продуктивність роботи серверу. Дійсно,
кожен запис файлу індексу повинен містити, крім посилання на рядок таблиці і саме
значення в індексованому стовпці, тому, індексуючи довгі стовпці, простір бази даних
витрачається неекономно. Крім цього, операції оновлення і порівняння довгих стовпців
займають багато часу. В крайньому випадку, можна створити скорочений варіант такого
довгого стовпця (до десяти символів), і індексування проводити по цьому стовпцю.

Матеріалізовані уявлення
Як відомо, уявлення (view) це запит на вибірку, який зберігається на сервері, як окремий
обєкт. Так як, результат цього запиту можна розглядати в якості таблиці, уявлення
допускається використовувати в інших запитах, також як любу звичайну таблицю.
Матеріалізоване уявлення зберігається на сервері у вигляді таблиці, яка автоматично
оновляється при зміні даних, які мають відношення до цього уявлення. При виконанні
запиту, основаного на матеріалізованому уявленні, використовуються не вихідні таблиці і
запит, на якому базується уявлення, а дані, які зберігаються в цьому уявленні. За рахунок
цього швидкість виконання запитів може бути підвищена на порядки. Основним недоліком
матеріалізованого уявлення являється те, що для його використання потрібно додатковий
дисковий простір і його необхідно синхронізувати з основними даними.
Створення обєктів

drop table h1;


drop table h2;

create table h1(n number primary key, s varchar2(100) null, n1 number null, s1 v
archar2(100));
create table h2(n number primary key, s varchar2(100) null, n1 number null, s1 v
archar2(100));

insert into h1(n, s, n1, s1) select object_id, object_name, object_id, owner fro
m all_objects;
insert into h2(n, s, n1, s1) select object_id, object_name, object_id, owner fro
m all_objects;

analyze table h1 compute statistics for table for all columns for all indexes;
analyze table h2 compute statistics for table for all columns for all indexes;

create view v1 as select h1.n, h1.s, h2.s1, h2.n1 from h1 inner join h2 on h1.n =
h2.n and h1.s = h2.s;

select * from v1 where n = 10 and s = '23423';


grant create materialized view to bor;
grant query rewrite to bor;

create materialized view v2 as select h1.n, h1.s, h2.s1, h2.n1 from h1 inner joi
n h2 on h1.n = h2.n and h1.s = h2.s;

select * from v2 where n = 10 and s = '23423';

create index iv on v2(n);

select * from v2 where n = 10 and s = '23423';


Лістинг 12.6.

Інформація про матеріалізовані уявлення

select * from user_mviews;


select * from user_views;
select * from user_segments where segment_name in
('V1', 'V2');

create materialized view v3 as select h1.s1 s1,


count(h1.n1) n1 from h1 group by s1 having count(*) > 1;

select h1.s1 s1, count(h1.n1) n1


from h1 group by s1 having count(*) > 1;

select s1, n1 from v3;

Оцінка необхідного розміру

variable v_rows number


variable v_bytes number
exec DBMS_MVIEW.ESTIMATE_MVIEW_SIZE
(1, 'select h1.s1 s1, count(h1.n1) n1 from h1 group by s1 having count(*)
> 1', :v_rows, :v_bytes);
print :v_rows :v_bytes

Способи побудови
Існує два способи формування уявлення - безпосередньо при його створенні або
відкладене, по явній команді.

drop materialized view v3;

create materialized view v3 build immediate as select h1.s1 s1,


count(h1.n1) n1 from h1 group by s1 having count(*) > 1;
create materialized view v3 build deferred as select h1.s1 s1,
count(h1.n1) n1 from h1 group by s1 having count(*) > 1;

select * from v3;

exec dbms_mview.refresh('V3');

select * from v3;

Частота оновлення

Матеріалізоване уявлення може синхронізуватися з вихідними даними або автоматично на


момент завершення трансакції або по явній команді синхронізації. Можлива синхронізація
за розкладом.

drop materialized view v3;


create materialized view v3 build immediate refresh complete on commit as select
h1.s1 s1, count(h1.n1) n1 from h1 group by s1;

insert into h1(n, s, n1, s1) values(-1, 'aaa', -1, 'aaa');


insert into h1(n, s, n1, s1) values(-2, 'aaa', -2, 'aaa');

select * from v3;

commit;

select * from v3;

drop materialized view v3;

create materialized view v3 build immediate refresh complete on commit as select


h1.s1 s1, count(h1.n1) n1 from h1 group by s1 having count(*) > 1;

create materialized view v3 build immediate refresh complete on demand as select


h1.s1 s1, count(h1.n1) n1 from h1 group by s1 having count(*) > 1;

insert into h1(n, s, n1, s1) values(-3, 'bbb', -3, 'bbb');


insert into h1(n, s, n1, s1) values(-4, 'bbb', -4, 'bbb');

commit;

exec dbms_mview.refresh('V3', 'F' /* ? C */);

drop materialized view v3;

create materialized view v3 build immediate refresh complete start with '17-MAY-
2004' next sysdate+1 as select h1.s1 s1, count(h1.n1) n1 from h1 group by s1 hav
ing count(*) > 1;

@?/rdbms/admin/utlxmv.sql

set linesize 200


column statement_id format a15
column mvowner format a5
column mvname format a10
column statement_id format a3
column related_text format a10
column msgtxt format a60

exec dbms_mview.explain_mview('v3', '111');

select * from mv_capabilities_table;

exec dbms_mview.explain_mview('select h1.s1 s1, count(h1.n1) n1 from h1 group by


s1', '222');

select * from mv_capabilities_table where statement_id = 222;


Лістинг 12.7.

Спосіб оновлення
Існує два основних способи оновлення матеріалізованих уявлень
 Повна перебудова. В цьому випадку при кожному оновленні даних відбувається
виконання запиту, на основі якого побудовано уявлення і дані повністю
перегружаються.
 Часткове оновлення. Для кожної таблиці яка бере участь в запиті на уявлення,
створюється журнал змін і зміни подання виконуються тільки даних, измененных
змінених в основних таблицях.
drop materialized view v3;
create materialized view v3 build immediate refresh complete as select h1.s1 s1
, count(h1.n1) n1 from h1 group by s1 having count(*) > 1;

insert into h1(n, s, n1, s1) values(-1, 'aaa', -1, 'aaa');


insert into h1(n, s, n1, s1) values(-2, 'aaa', -2, 'aaa');

commit;

exec dbms_mview.refresh('v3');

select * from v3;

drop materialized view v3;

create materialized view v3 refresh fast as select h1.s1 s1, count(h1.n1) n1 fr


om h1 group by s1 having count(*) > 1;

create materialized view v3 refresh fast as select h1.s1 s1, count(h1.n1) n1 fr


om h1 group by s1;
create materialized view v3 refresh fast as select h1.s1 s1, avg(n1) n, count(h
1.n1) n1 from h1 group by s1;
create materialized view v3 refresh fast as select h1.s1 s1, avg(n1) n from h1 g
roup by s1;

create materialized view log on h1 nologging with sequence, rowid (n1, s1) incl
uding new values;
create materialized view log on h2 nologging with sequence, rowid (n1, s1) incl
uding new values;

drop materialized view v3;

create materialized view v3 refresh fast on commit as select h1.s1 s1, count(h1
.n1) n1 from h1 group by s1;

insert into h1(n, s, n1, s1) values(-11, 'aaa1', -11, 'aaa1');


insert into h1(n, s, n1, s1) values(-21, 'aaa1', -21, 'aaa1');

commit;

exec dbms_mview.explain_mview('v3', '2');


select * from mv_capabilities_table where statement_id = 2;

drop materialized view v3;

exec dbms_mview.explain_mview('select h1.s1 s1, count(h1.n1) n1 from h1 group b


y s1', '4');
select * from mv_capabilities_table where statement_id = 4;

select * from user_segments where segment_name like 'MLOG%';

select * from user_mview_logs;

drop materialized view log on h1;


drop materialized view log on h2;

create materialized view log on h1 nologging with sequence, rowid (n, n1, s1) i
ncluding new values;
create materialized view log on h2 nologging with sequence, rowid (n, n1, s1) i
ncluding new values;

truncate table mv_capabilities_table;

exec dbms_mview.explain_mview('select h1.s1 s1, h2.s1 s2, h1.n n from h1, h2 wh


ere h1.n = h2.n', '5');
select * from mv_capabilities_table where statement_id = 5;
truncate table mv_capabilities_table;

exec dbms_mview.explain_mview('select h1.rowid h1_rowid, h2.rowid h2_rowid, h1.


s1 s1, h2.s1 s2, h1.n n from h1, h2 where h1.n = h2.n', '5');
select * from mv_capabilities_table where statement_id = 5;

drop materialized view v3;

create materialized view v3 refresh fast as select h1.s1 s1, h2.s1 s2, h1.n n f
rom h1, h2 where h1.n = h2.n;
create materialized view v3 refresh fast as select h1.rowid h1_rowid, h2.rowid h
2_rowid, h1.s1 s1, h2.s1 s2, h1.n n from h1, h2 where h1.n = h2.n;

create materialized view v3 refresh fast on commit as select h1.s1 s1, h2.s1 s2
, h1.n n from h1, h2 where h1.n = h2.n;
create materialized view v3 refresh fast on commit as select h1.rowid h1_rowid,
h2.rowid h2_rowid, h1.s1 s1, h2.s1 s2, h1.n n from h1, h2 where h1.n = h2.n;

You might also like