Чому обмеження застосовуються в базі даних, а не в коді?


21

Чому обмеження застосовуються в базі даних? Чи не буде більш гнучким його вводити в код?

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

 entity type    |   sub-types
----------------+--------------------------------------------
   Person       |   Employee, Student,       ...
   Student      |   Graduate, Undergraduate, ...
   Employee     |   Teacher,  Administrator, ...

Поточні обмеження:

  1. Зареєстрована особа в системі може бути лише студентом чи працівником.
  2. Особиста особа вимагає унікальності соціального числа, яке, як ми вважаємо, кожна людина має лише один унікальний (він же є достатньо хорошим первинним ключем). (див. №1)

Пізніше ми вирішуємо зняти число 1: Якщо одного дня коледж вирішить, що Teacher( Employeeпідтип) також може бути Student, беручи курси у вільний час, набагато складніше змінити дизайн бази даних, який може мати тисячі, мільйони, мільярди, мільйони записів, а не просто зміна логіки в коді: саме та частина, яка не дозволяла людині бути зареєстрованою як студентом, так і працівником.

(Це дуже неймовірно, але я нічого іншого зараз не можу придумати. Мабуть, це можливо).

Чому нас цікавлять правила ведення бізнесу в дизайні баз даних, а не в коді?

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


2
Переважно ми дбаємо про те, щоб правила ведення бізнесу виконувались і який найкращий спосіб для цього.
ypercubeᵀᴹ

3
Ви насправді представляєте дуже поганий приклад того, для чого використовуються обмеження, оскільки гнучкість ваших утворень та розширюваність бази даних в основному визначаються нормалізацією. Сказавши це, обмеження є остаточним захистом від будь-яких пошкоджених даних, які коли-небудь потрапляють у базу даних, навіть якщо програма застосована, навіть якщо розроблено нову програму, навіть якщо додано зовнішній API, навіть якщо хтось редагує БД безпосередньо. Обмеження охороняють базу даних, крім того, що бізнес-логіка також повинна буде робити власні речі, перш ніж намагатися отримати доступ до БД.
Niels Keurentjes

3
Власне, як аспірант мене вважають і студентом, і співробітником, і вчителем. Тож ваш приклад насправді малоймовірний.
Вінстон Еверт

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

Об'єкт <-> Реляційне відображення - це мистецтво.
Thorbjørn Ravn Andersen

Відповіді:


34

Деякі обмеження найкраще виконувати в базі даних, а деякі найкраще виконувати в додатку.

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

Обмеження, що виконуються у програмі, можуть бути не принциповими для моделі даних, такі як усі продукти FooBar повинні бути синього кольору, але пізніше хтось може вирішити, що FooBars також може бути жовтим. Це логіка програми, яка насправді не повинна знаходитись у базі даних, хоча ви можете створити окрему coloursтаблицю, і база даних може вимагати, щоб посилання на продукт було дійсним записом із цієї таблиці. АЛЕ рішення про те, що єдиний запис у coloursзначенні blueмає все-таки прийти з- за меж бази даних.

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

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


Отже, згідно з цією відповіддю, правило <a person може існувати лише в таблиці підтипу Student або лише в таблиці підтипу Employees> слід застосовувати в коді, а база даних має <Підтип "Студент / Співробітник" повинен бути дійсним особа> обмеження. Я правий? (Це був приклад книги). Спасибі.
hkoosha

2
@loolooyyyy: Так, я думаю, що це правильно. Якщо база даних застосовує перше правило (що людина може тільки бути студентом або співробітником) , то ситуація ви описали (в якому працівник хоче зареєструвати для класу) неможливо , тому що: людина не може бути одночасно, і це не навіть можливо створити другий запис "особи", оскільки вони не можуть ділитися номерами соціального страхування, які, імовірно, видаються від третьої сторони (наприклад, уряду). Звичайно, ця надмірно обмежена модель даних може працювати в деяких випадках ...
FrustratedWithFormsDesigner

2
@loolooyyyy: Ще одним способом використання оригінальної моделі даних, і все ж дозволяти викладачам бути студентами, може бути мати ще одну таблицю, teachers_as_studentsяка називається ще одним підтипом Studentsі має новий зовнішній ключ Teachers, а також створений системою первинний ключ, а не соціальний Номер безпеки. Таким чином, "студент" насправді є псевдонімом для вчителя, тому вчитель все ще може зареєструватися, щоб взяти клас. Важко точно сказати, наскільки добре це буде працювати, не бачачи всієї моделі даних.
FrustratedWithFormsDesigner

2
Я спростував це. Немає часу, коли обмеження найкраще виконувати лише в додатку . Тон цієї відповіді зважується неправильно.
Еван Керролл

3
@FrustratedWithFormsDesigner, безумовно, це насправді дитина-постер для обмеження іноземного ключа. Припустимо, у вас є три клієнти різних версій / складових точки доступу db, що ви будете робити, коли перестанете перевозити цей продукт червоним кольором? Де ви збираєтесь зберігати список можливих поєднань кольорів? Підказка: У мене для вас централізоване місце. І якщо ви створите таблицю color_products, і color, ймовірно, зможете створити додаткові спади з більшою легкістю - більшість IDE / схем навантажувачів підтримують наступні фейки.
Еван Керролл

35

Оскільки:

  1. Я хочу, щоб всі дані в базі даних підпадали під однакові обмеження, а не лише нові дані підлягали обмеженням у версії коду, яка працює сьогодні.
  2. Я хочу декларативних обмежень, а не програмних обмежень.
  3. Дані в базі даних часто переживають код, написаний для взаємодії з ним сьогодні. І ці дані - не код - є перевагою організації.
  4. Мій код стає набагато простішим, коли я знаю, що всі дані підлягають жорстким обмеженням. Мені більше не доводиться розглядати особливі випадки, за якими я знаю, що база даних гарантує неможливість.

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


4
Напівпов'язані з (1) та (3): помилки в коді програми можуть бути виправлені, помилки у ваших даних часто непоправні.
mu занадто короткий

17

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

На мою особисту думку (на основі понад 30 років роботи з даними та досвіду роботи з сотнями різних баз даних, які використовуються для багатьох різних цілей) кожен, хто не помістить протипоказання в базу даних, куди вони належать, зрештою матиме бідні дані. Іноді погані дані стають непридатними. Особливо це стосується тих, хто має фінансові / регуляторні дані, які повинні відповідати певним критеріям аудиту.


17

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

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

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

До речі, дизайнерам мови додатків це невідомо. Прочитайте розділ 3.10 унікальності в керівництві Ruby on Rails: Активні перевірки записів та зворотні дзвінки

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


16

Переваги обмежень, що застосовуються базою даних:

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

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

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

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

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

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


11

Чому обмеження застосовуються на сервері? Тому що ви не можете змусити поганих хлопців використовувати ваш клієнт.

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

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


10

Ось чудові відповіді тут, і ризикуючи повторити інші думки:

  • SSN не обов'язково є унікальним. Хек, SSN навіть не завжди відомий, а в деяких випадках він ще не існує (поки що). SSN можна використовувати повторно, і не всі співробітники чи студенти можуть коли-небудь мати SSN. Це питання є периферійним питанням, але демонструє, що незалежно від того, де ви виконуєте свої обмеження, вам потрібно досить глибоко зрозуміти модель даних та домен, щоб приймати рішення щодо бізнес-правил.
  • Особисто я вважаю за краще, щоб обмеження були максимально наближеними до даних. Дуже проста причина полягає в тому, що не кожен використовуватиме код програми для зміни даних у базі даних. Якщо ви застосовуєте свої бізнес-правила на рівні програми, і я запускаю UPDATEзаяву безпосередньо проти бази даних, як ваша програма запобігає недійсній зміні? Ще одна проблема з бізнес-правилами в додатку полягає в тому, що перекомпіляція / повторна розробка може бути складною, особливо для розповсюджених програм, де можливо, що не кожен отримає оновлення одночасно. І нарешті, зміна бізнес-правил у додатку не робить абсолютно нічого щодо даних, які вже існують, що порушують нові правила - якщо ви додасте нове обмеження до даних, вам потрібно виправити ці дані.
  • Можливо, ви зможете виправдати декілька, зайвих перевірок на різних рівнях. Все це залежить від гнучкості методологій розгортання, наскільки ймовірна зміна та наскільки складно синхронізувати зміну бізнес-правил у базі даних та інших шарах. Переконливий аргумент для повторення перевірок на рівні додатків полягає в тому, що ви можете потенційно запобігти зворотному переходу в базу даних лише для того, щоб збити там обмеження (залежно від характеру обмеження та чи покладається він на наявні дані). Але якби мені довелося вибрати те чи інше, я б помістив його в базу даних з причин, що були вище.

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


9
  1. База даних може ефективно перевіряти обмеження. Краще за код.

  2. Обмеження цілісності допомагає базі даних знайти ефективний план виконання

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


8

Коротка відповідь ... для збереження цілісності даних (тобто точності та достовірності).

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

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

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

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

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

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

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

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

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

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


7

Окрім інших коментарів ...

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


5

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

Також тригери рідше є портативними, оскільки вони, як правило, записуються на конкретних мовах постачальника, таких як PL / SQL.

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


5
Також тригери не гарантують доброчесності через проблеми з прочитаною послідовністю.
Девід Олдрідж

3

Вони завжди повинні бути застосовані в базі даних перших , тому що,

  1. База даних забезпечує цілісність серед різних клієнтів. Ви можете мати різних клієнтів на різних платформах доступу до бази даних. Обмеження в базі даних не ризикують проблемами цілісності під час створення нового клієнта. Це позбавить вас від необхідності Q / A ваших обмежень у разі переписування або додаткової точки доступу.
  2. База даних має DSL для побудови обмежень: SQL DDL!
  3. База даних надає доступ до цих обмежень у системних каталогах, тому належний ORM або "завантажувач схем" може прочитати ці обмеження та внести їх у вашу програму. Наприклад, якщо у вашій базі даних вказано, що у вас є varchar(5)тип, є хороший шанс ви можете знайти схему завантаження ORM для вашого конкретного мови, яка відображає тип мови до типу схеми, і збирає власне обмеження щодо розміру. DBIx for Perl is one such schema loader; ось ще одна для Entity Framework . Можливості цих навантажувачів різні, але все, що вони можуть надати, - це гарний початок для забезпечення цілісності в додатку без походу в базу даних.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.