Сначала я должен уточнить, что столбец состояния не предназначен для отражения статуса элемента реального мира, представленного записью (строкой) в таблице. Скорее, он предназначен для отображения статуса самой записи.
Он может быть простым, например, активным / неактивным, или сложным, например, «Утверждено», «Удалено», «Заблокировано», «Ожидание», «Отклонено» и т. Д. Статус может быть сохранен в столбце «логическое / короткое целое число» или в столбце с одним символом, с отображениями, такими как « true
/ 1
=» A
= Одобрено.
Основная идея заключается в том, чтобы иметь в приложении поддержку восстановления корзины, похожую на корзину, и моделировать ее в базе данных. Если есть интерфейсный графический интерфейс или другой интерфейс, который может предположительно позволить пользователю «удалять» записи, он фактически не удаляет записи в таблице, а просто меняет статус записи на «Неактивно» или «Удалено». Когда интерфейс выбирает записи, он всегда получает записи, которые соответствуют только условию, что статус «Активный» или «Одобренный».
Если пользователь делает ошибку, и «удаленная» запись (с точки зрения пользователя) должна быть восстановлена, администратор базы данных может легко исправить запись как активную или утвержденную, что было бы лучше, чем поиск резервных копий и, надеюсь, поиск исходной записи. там. Либо сам интерфейс может позволить пользователю просматривать удаленные записи в отдельном представлении и восстанавливать их по мере необходимости, либо даже окончательно удалять их (удаляя фактическую запись).
Мои вопросы:
- Это хорошая практика или плохая практика?
- Влияет ли это на нормализацию данных?
- Каковы потенциальные подводные камни?
- Есть ли альтернативный метод достижения той же цели? (смотрите примечание)
- Как можно заставить базу данных применять уникальные ограничения к данным только для определенного статуса (но разрешить любое количество дубликатов для других статусов)?
- Почему базы данных не предоставляют функцию, похожую на «корзину», или отслеживание / восстановление таблиц, поэтому мы можем позволить интерфейсам без проблем удалять реальные записи?
Примечание: я читал о ведении отдельной таблицы истории, но это кажется хуже с точки зрения хранения и необходимости генерировать триггеры и поддерживать их в актуальном состоянии со схемой отслеживаемой таблицы.
источник
Ответы:
Я знаю это как «мягкое удаление»; просто пометить запись как «удаленную», даже если это не так.
По-разному.
Если это то, что нужно вашим пользователям [много], то, вероятно, это хорошо. Однако в подавляющем большинстве случаев я бы сказал, что это добавляет [много] накладных расходов для небольшой выгоды.
Нет, но это будет влиять на ваше индексирование этих данных.
Убедитесь, что вы включили «удаленный» столбец в свои индексы, чтобы эти строки были исключены как можно раньше в ваших запросах.
Ваши данные становятся немного сложнее. Все, что находится рядом с данными, должно «знать» об этих дополнительных, «не очень-то» записях. Или вы должны создать представления для тех таблиц, которые исключают эти строки, и использовать эти представления, например, в своем инструменте выбора отчетов.
Ваша база данных может увеличиться в размере. Если вы на самом деле не удаляете эти строки, они все еще там и занимают место. Это может быть или не быть проблемой, особенно если учесть, что вы включили их в свои индексы, поэтому занимаемое ими пространство увеличивается.
Не на самом деле нет.
Не легко. Декларативная ссылочная целостность (предложения по внешнему ключу) - самый чистый способ реализовать это, и для таких вещей, как инструменты отчетности, легко подобрать эти правила для определения отношений между таблицами. Такие правила применяются ко всем записям, независимо от «статуса» (и это никак не обойти).
Альтернативой является использование триггеров, фрагментов процедурного кода, которые обеспечивают ссылочную целостность между таблицами и делают все умные, условные вещи, которые вам нужны. Это хорошо для вашего конкретного случая, но большинство преимуществ декларативного RI вылезают за пределы окна - между вашими таблицами нет [внешне] обнаруживаемых связей; это все «спрятано» в триггерах.
Почему бы это?
В конце концов, это базы данных, а не файловые системы или электронные таблицы.
Что они делают, они [могут] делать очень, очень хорошо.
То, что они не делают, вероятно, не было большого спроса на.
источник
Это практика. Хорошо это или плохо, сильно зависит от вашего приложения и от того, насколько часто вам действительно нужно / нужно делать «восстановление». Я был бы весьма сомнителен в плане размещения такого рода столбцов в каждой таблице в системе - очень маловероятно, что вы действительно потрудитесь реализовать undelete для каждой таблицы в системе. И это требует реализации - в подавляющем большинстве случаев вы не удаляете ни одной строки из одной таблицы, вы должны проходить дочерние таблицы, удаляя строки и обновляя связанные таблицы.
Для большинства остальных вопросов это сильно зависит от реализации. Например, Oracle предоставляет различные методы для отслеживания всех изменений в таблице - Flashback Data Archive (FDA, также известный как Total Recall), являющийся самым последним подходом к ведению полной истории каждой версии строки и архивации в базе данных для реализации шаблон мягкого удаления. Другие базы данных могут предоставлять другие способы реализации шаблона. В зависимости от базы данных и того, как вы реализуете «мягкое» удаление, на производительность будут влиять различные факторы, могут ли ограничения применяться и как, и т. Д. Если мы говорим об Oracle, вы можете многое сделать, например, с помощью индексов на основе функций. В SQL Server вы часто можете использовать отфильтрованные индексы для аналогичных целей.
источник
В системах MRP / ERP очень часто используется поле «помечено для удаления».
Например, можно пометить деталь или инвентарную запись, которая больше не продается как неактивная, но с ней все еще остаются невыполненные заказы. Реальное удаление записи может повлиять на заказы, которые еще не были отправлены, записи в Главной книге, которые еще не были опубликованы, таблицы истории, которые не будут созданы до конца месяца, и т. Д. Многие системы запрещают удаление записи, если она не пройдет серию проверок в отношении других таблиц. Если вы каскадно удаляете свои отношения, реальное удаление может быть еще более разрушительным.
Вместо этого, помечая его для удаления, вы помещаете в запись четкий маркер намерения, и позже запланированное задание может удалить запись, если оно проверяет, что все связанные таблицы больше не ссылаются на нее.
Аналогичный случай может быть сделан для этой функции на клиентской таблице и других «долгосрочных» таблицах. Это даже имеет смысл на более изменчивых таблицах, таких как заказы, хотя название флага может стать чем-то вроде «отправлено» или «отменено». Он выполняет ту же функцию: не удаляйте его в этот момент, а используйте его в качестве флага для программы очистки, чтобы попытаться проверить удаление записи в будущем.
источник
В качестве альтернативного решения использование источника событий позволяет достичь аналогичных целей, не усложняя структуру таблицы, хотя и делает код для изменения ваших данных немного более сложным, поскольку вы должны записать изменение в событие, которое можно сохранить в истории событий. , Это затем позволяет вам воссоздать базу данных, как это было в любой момент времени, что может быть очень полезной функцией.
(Я не думаю, что это то, что вы имели в виду под «таблицей истории», что, я думаю, вы имели в виду, просто копируя измененные или удаленные записи в другую таблицу перед их изменением)
источник
Я часто вижу и использую этот шаблон для следующих случаев использования:
Проблема состоит в том, чтобы обеспечить целостность данных, если более чем одно приложение или веб-служба выполняет запись в таблицы. Как вы гарантируете, что для дела существует только одно текущее состояние? Как указывает Джастин Кейв, это можно сделать в Oracle, создав виртуальный индекс на основе функции, но это дополнительные затраты на то, что изначально казалось простой концепцией.
источник
Это хорошая практика, если вы планируете использовать свои данные для отчетности (любое достаточно большое приложение должно иметь отчеты).
Чтобы ускорить работу вашего приложения, вам не следует запускать инструменты отчетности в вашей базе данных. Таким образом, вам нужно будет сделать копию / синхронизировать с другой базой данных.
Я использую
recordStatus
только два состоянияACTIVE
илиCANCELLED
в сочетании сlastUpdatedOn
отметкой времени. Я использую,recordStatus
а не то,status
что обычно имеет деловое значение.Когда я синхронизирую базу данных отчетов с приложением, я включаю фильтр,
lastUpdatedOn
чтобы узнать, какие из них я собираюсь заменить на стороне отчетов.Что касается отчетности, у меня не будет полей
recordStatus
или,lastUpdatedOn
поскольку о них вообще не будет сообщено. Таким образом, когда я вижуCANCELLED
состояние, я удаляю запись со стороны отчетности таким образом, что она имеет только активные записи.Это может быть расширено до других типов хранилищ, таких как архивы или резервные копии, где требуется почти полная синхронизация. Тем не менее, отчетность является более распространенной целью.
Обратите внимание , ваш пример
Approved
,New
,Pending
это не очень хорошая идея , чтобы положить в общем поле , как есть бизнес означает , что он должен идти только туда , где это имеет смысл бизнес мудро.Что касается заблокированных, используйте,
versionNo
который обеспечивает оптимистическую блокировку для вашей записи.Другой вариант вместо
recordStatus
этоrecordActive
и хранят его в виде ,boolean
который занимает меньше места и меньше индексации, но я бы беспокоиться о потребностях в будущем , что вы не можете предвидеть.источник