Каков наилучший способ реализовать мягкое удаление?
-
09-06-2019 - |
Вопрос
В данный момент мы работаем над проектом, и нам необходимо внедрить мягкое удаление для большинства пользователей (ролей пользователей).Мы решили добавить поле "is_deleted='0'" в каждую таблицу базы данных и установить для него значение "1", если определенные роли пользователей нажимают кнопку удаления в определенной записи.
Для дальнейшего обслуживания теперь каждый запрос SELECT должен будет убедиться, что они не включают записи, где is_deleted='1'.
Есть ли лучшее решение для реализации мягкого удаления?
Обновить:Я должен также отметить, что у нас есть база данных аудита, которая отслеживает изменения (поле, старое значение, новое значение, время, пользователь, ip) во всех таблицах / полях в базе данных приложения.
Решение
Вы могли бы выполнять все свои запросы к представлению, содержащему WHERE IS_DELETED='0'
оговорка.
Другие советы
Я бы склонялся к "Рельсовому пути" с deleted_at
столбец, содержащий дата и время, когда произошло удаление.Затем вы получаете немного бесплатных метаданных об удалении.Для вашего SELECT
просто получите строки WHERE deleted_at IS NULL
Имея is_deleted
колонка - это достаточно хороший подход.Если это в Oracle, то для дальнейшего повышения производительности я бы рекомендовал разбить таблицу на разделы, создав раздел списка на is_deleted
колонна.Тогда удаленные и не удаленные строки физически будут находиться в разных разделах, хотя для вас это будет прозрачно.
В результате, если вы введете запрос типа
SELECT * FROM table_name WHERE is_deleted = 1
затем Oracle выполнит "обрезку раздела" и просмотрит только соответствующий раздел.Внутренне раздел представляет собой другую таблицу, но он прозрачен для вас как пользователя:вы сможете выбирать по всей таблице, независимо от того, разбита она на разделы или нет.Но Oracle сможет запрашивать ТОЛЬКО тот раздел, который ему нужен.Например, давайте предположим, что у вас есть 1000 строк с is_deleted = 0
и 100000 строк с is_deleted = 1
, и вы разбиваете таблицу на is_deleted
.Теперь, если вы включите условие
WHERE ... AND IS_DELETED=0
тогда Oracle будет сканировать раздел ТОЛЬКО с 1000 строками.Если бы таблица не была разбита на разделы, ей пришлось бы просканировать 101000 строк (оба раздела).
если таблица большая и производительность является проблемой, вы всегда можете переместить "удаленные" записи в другую таблицу, в которой есть дополнительная информация, такая как время удаления, кто удалил запись и т. Д
таким образом, вам не нужно добавлять еще один столбец в вашу основную таблицу
К сожалению, наилучший ответ зависит от того, чего вы пытаетесь достичь с помощью своих программных удалений и базы данных, в которой вы это реализуете.
В SQL Server лучшим решением было бы использовать столбец deleted_on / deleted_at с типом SMALLDATETIME или DATETIME (в зависимости от необходимой детализации) и сделать этот столбец обнуляемым.В SQL Server данные заголовка строки содержат битовую маску NULL для каждого из столбцов в таблице, поэтому выполнение IS NULL или NOT NOT NULL немного быстрее, чем проверка значения, хранящегося в столбце.
Если у вас большой объем данных, вам захочется изучить возможность разделения ваших данных либо через саму базу данных, либо через две отдельные таблицы (напримерProducts и ProductHistory) или через индексированное представление.
Обычно я избегаю полей флага, таких как is_deleted, is_archive и т.д., потому что они несут только один смысл.Обнуляемое поле deleted_at, archived_at предоставляет дополнительный уровень значимости вам и тому, кто унаследует ваше приложение.И я избегаю полей битовой маски, подобных чуме, поскольку они требуют понимания того, как была создана битовая маска, чтобы понять какой-либо смысл.
Это зависит от того, какая информация вам нужна и какие рабочие процессы вы хотите поддерживать.
Вы хотите иметь возможность:
- знаете, какая информация там была (до того, как она была удалена)?
- знаете, когда оно было удалено?
- знаете, кто его удалил?
- знаете, в каком качестве они действовали, когда удаляли его?
- сможете отменить удаление записи?
- сможете ли вы определить, когда оно было удалено?
- и т.д.
Если запись удалялась и не удалялась четыре раза, достаточно ли вам знать, что в данный момент она находится в не удаленном состоянии, или вы хотите иметь возможность сказать, что произошло за это время (включая любые правки между последовательными удалениями!)?
Будьте осторожны с записями, удаляемыми автоматически, что приводит к нарушению ограничений уникальности.Если в вашей базе данных есть столбцы с уникальными ограничениями, то будьте осторожны, чтобы предыдущие записи, удаленные автоматически, не помешали вам воссоздать запись заново.
Подумайте о цикле:
- создать пользователя (логин=JOE)
- автоматическое удаление (установите для удаленного столбца значение, отличное от нуля.)
- (повторно) создайте пользователя (login=JOE).ОШИБКА.ЛОГИН= ДЖО уже занят
Второе создание приводит к нарушению ограничения, потому что login=JOE уже находится в строке с программным удалением.
Некоторые методы:1.Переместите удаленную запись в новую таблицу.2.Установите ограничение уникальности в столбце login и deleted_at timestamp
Мое личное мнение - +1 за переход на новую таблицу.Требуется большая дисциплина для поддержания *И delete_at = NULL * во всех ваших запросах (для всех ваших разработчиков)
У вас определенно повысится производительность, если вы переместите удаленные данные в другую таблицу, как сказал Джим, а также получите запись о том, когда они были удалены, почему и кем.
Добавление where
выполнение всех ваших запросов значительно замедлит их выполнение и затруднит использование любого из индексов, которые могут быть у вас в таблице.По возможности избегайте наличия "флагов" в ваших таблицах.deleted
=0
Что-то, что я использую в проектах, - это столбец statusInd tinyint not null по умолчанию 0 использование statusInd в качестве битовой маски позволяет мне выполнять управление данными (удалять, архивировать, реплицировать, восстанавливать и т.д.).Используя это в представлениях, я могу затем выполнять распределение данных, публикацию и т.д. Для приложений-потребителей.Если производительность вызывает беспокойство в отношении представлений, используйте небольшие таблицы фактов для поддержки этой информации, отбрасывая факт, отбрасывая связь и допуская масштабируемые удаления.
Хорошо масштабируется и ориентирован на данные, сохраняя объем данных довольно небольшим - ключ для 350gb + dbs с функциями реального времени.Использование альтернатив, таблиц, триггеров сопряжено с некоторыми накладными расходами, которые в зависимости от необходимости могут работать, а могут и не работать для вас.
Для аудита, связанного с SOX, в вашем случае может потребоваться нечто большее, чем просто поле, но это может помочь.Наслаждайтесь
вы не упоминаете, какой продукт, но SQL Server 2008 и postgresql (и другие, я уверен) позволяют вам создавать отфильтрованные индексы, поэтому вы могли бы создать покрывающий индекс, где is_deleted= 0, смягчая некоторые недостатки этого конкретного подхода.
Я предпочитаю сохранять столбец состояния, чтобы я мог использовать его для нескольких разных конфигураций, т.е.опубликовано, закрыто, удалено, требует подтверждения...
используйте представление, функцию или процедуру, которая проверяет is_deleted=0, т.е.не выбирайте непосредственно в таблице на случай, если таблицу потребуется изменить позже по другим причинам
и проиндексируйте столбец is_deleted для таблиц большего размера
поскольку у вас уже есть журнал аудита, отслеживание даты удаления является излишним
Создайте другую схему и предоставьте все это вашей схеме данных.Внедрите VPD в вашу новую схему, чтобы каждый запрос имел предикат, разрешающий выбор только добавленной к нему не удаленной строки.http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/cmntopc.htm#CNCPT62345
@AdditionalCriteria("этот.status <> "удалено"")
поместите это поверх вашего @entity