Чи погана практика мати стовпчик "статус запису" в таблиці бази даних?


12

Спершу я повинен уточнити, що стовпець статусу не призначений для відображення стану реального елемента, представленого записом (рядком) у таблиці. Швидше, це покликане показати статус самої записи.

Він може бути таким же простим, як Активний / Неактивний або складний, як затверджений / видалений / заблокований / очікуючий / відхилений тощо. Статус можна зберігати у булевій / короткій цілій цільній колонці або стовпчику з одним символом, зі зіставленнями на кшталт true/ 1= Активний або A= Затверджено.

Основна ідея полягає у тому, щоб у додатку містилася підтримка відновлення кошика для сміття та сміття (та імітація в базі даних). Якщо є інтерфейс інтерфейсу інтерфейсу або інший інтерфейс, який нібито дозволяє користувачеві "видаляти" записи, він фактично не видаляє запис у таблиці, а просто змінює стан запису на "Неактивний" або "Видалений". Коли інтерфейс отримує записи, він завжди отримує записи, які відповідають лише умові, що статус "Активний" або "Затверджений".

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

Мої запитання:

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

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


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

Відповіді:


5

Я знаю це як "м'яке видалення"; просто позначив запис "видаленим", хоча він насправді не є.

Це хороша практика, чи погана практика?

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

Чи впливає це на нормалізацію даних?

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

Які потенційні підводні камені?

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

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

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

Не дуже, ні.

Як ви можете змусити базу даних застосовувати унікальні обмеження щодо даних лише для певного статусу (але дозволяти будь-яку кількість дублікатів для інших статусів)?

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

Альтернативою є використання тригерів, фрагментів процедурного коду, які забезпечують референтну цілісність між таблицями та виконують усі розумні, умовні речі, які вам потрібні. Це добре для вашого конкретного випадку, але більшість переваг Декларативного RI виходять з вікна - між вашими таблицями немає [зовні] виявлених зв’язків; це все "заховано" в тригерах.

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

Чому б це?

Зрештою, це бази даних, а не файлові системи та електронні таблиці.

Що вони роблять, вони [можуть] робити дуже, дуже добре.

Те, що вони не роблять, там, мабуть, не було великого попиту.


Хороша відповідь, але є альтернативні варіанти, наприклад, перемістіть рядки в резервну таблицю, звідки їх можна відновити. Таблиця резервного копіювання може мати мінімальні показники. Це зводить до мінімуму проблеми, які ви відмічаєте при існуючому підході (більший індекс, потенційна плутанина для користувачів таблиці тощо), але очевидно додає той факт, що у вас є інша таблиця для підтримки (а це означає, що записи відійшли wrt до іноземних ключових посилань). Існує досить багато інших варіантів - але насправді такі, які приходять в голову, - це якась спеціальна реалізація, а не щось загальне, що надається кожною базою даних SQL для таких випадків.
Френк Хопкінс

9

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

Для більшості решти питань це залежить від впровадження. Наприклад, Oracle надає різні методи відстеження всіх змін у таблиці. Архів Flashback Data Archive (FDA також відомий як Total Recall) є останнім підходом до збереження повної історії кожної версії рядка та архівації в базі даних для впровадження м'який шаблон видалення. В інших базах даних можуть бути передбачені інші способи реалізації схеми. Залежно від бази даних та того, як ви реалізуєте м'яке видалення, на продуктивність впливатимуть різні впливи, чи можна і як обмеження можна примусити і т. Д. Якщо ми говоримо про Oracle, можна багато зробити, наприклад, на основі функціональних індексів , у SQL Server часто можна використовувати відфільтровані індекси для подібних цілей.


Oracle Flashback - це саме ідеальне рішення для того, що я хочу. Шкода, що Oracle є власником.
ADTC

4

У системах MRP / ERP дуже часто використовується поле "позначений для видалення".

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

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

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


3

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

(Я не вірю, що це ви мали на увазі під «таблицею історії», що, на мою думку, ви мали на увазі просто скопіювати змінені чи видалені записи в іншу таблицю перед їх зміною)


Цікава концепція. Я розберуся, як це можна здійснити.
ADTC

1

Я часто бачу та використовую цей зразок для таких випадків використання:

  • метадані, де ви бажаєте відобразити лише ті значення, які діють сьогодні. Наприклад, щоб вибрати зі списку виробників автомобілів у випадаючому списку, де увімкнено = 1 значення таблиць для ID, VALUE, ENABLED - це 1, "Ford", 1 і 2, "Edsel", 0, 3, "Toyota" , 1 дає лише вибір Ford і Toyota
  • для системи управління справами, де парадигма полягає в тому, що справа може бути лише в одному стані. У цьому випадку стовпчик перемикання називався CURRENT зі значеннями 0 або 1, виконаними контрольними обмеженнями. У разі переходу випадку з одного стану в інший додаток оновлює СУЧАСНИЙ прапор старого стану на 0, а новий на 1

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


1

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

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

Я використовую recordStatusлише два стани ACTIVEабо CANCELLEDв поєднанні з lastUpdatedOnчасовою позначкою. Я використовую, recordStatusа не statusякий зазвичай має ділове значення.

Коли я синхронізую базу даних звітів із програмою, я роблю фільтр, lastUpdatedOnщоб знати, які з них я хочу замінити на стороні звітності.

На стороні звітності у мене не буде поля recordStatusабо lastUpdatedOnполя, оскільки про них зазвичай не повідомляється. Як такий, коли я бачу CANCELLEDстатус, я б видалив запис зі сторони звітування, таким чином, він має лише активні записи.

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

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

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

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.