Ответ 1
Вы можете выполнить все ваши запросы против представления, содержащего предложение WHERE IS_DELETED='0'
.
В данный момент мы работаем над проектом, и мы должны реализовать мягкое удаление для большинства пользователей (пользовательских ролей). Мы решили добавить поле is_deleted='0'
для каждой таблицы в базе данных и установить его на '1'
, если определенные роли пользователя нажимают кнопку удаления в определенной записи.
Для будущего обслуживания сейчас каждый запрос SELECT
должен убедиться, что он не включает записи where 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 или IS NOT NULL, чем проверка значения, хранящегося в столбце.
Если у вас большой объем данных, вам нужно будет разглядеть разметку ваших данных либо через саму базу, либо через две отдельные таблицы (например, Продукты и ProductHistory) или через индексированное представление.
Я обычно избегаю полей флага, таких как is_deleted, is_archive и т.д., потому что они несут только один смысл. Поле nullable deleted_at, archived_at предоставляет дополнительный уровень значения самому себе и тому, кто наследует ваше приложение. И я избегаю полей битмаски, таких как чума, поскольку они требуют понимания того, как была построена битовая маска, чтобы понять смысл.
если таблица большая, а производительность - проблема, вы всегда можете переместить "удаленные" записи в другую таблицу, в которой есть дополнительная информация, например время удаления, которые удалили запись и т.д.
таким образом вам не нужно добавлять другой столбец в свою основную таблицу
Это зависит от того, какая информация вам нужна и какие рабочие процессы вы хотите поддерживать.
Вы хотите иметь возможность:
Если запись была удалена и не удалена четыре раза, достаточно ли вам знать, что она в настоящее время находится в состоянии без удаления, или вы хотите узнать, что произошло в промежуточный период (включая любые редактирование между последовательными удалениями!)?
Осторожно, записи с мягким удалением, вызывающие нарушения ограничений уникальности. Если в вашей базе данных есть столбцы с уникальными ограничениями, будьте осторожны, чтобы предыдущие записи с мягким удалением не препятствовали воссозданию записи.
Подумайте о цикле:
Вторые создают результаты в нарушении ограничений, потому что login = JOE уже находится в строке с мягким удалением.
Некоторые методы: 1. Переместите удаленную запись в новую таблицу. 2. Сделайте свое ограничение уникальности в столбце временной метки login и deleted_at
Мое собственное мнение - +1 для перехода на новый стол. Его много дисциплина для поддержания * И delete_at = NULL * во всех ваших запросов (для всех ваших разработчиков)
У вас будет определенная производительность, если вы переместите ваши удаленные данные в другую таблицу, как сказал Джим, а также записью о том, когда она была удалена, почему и кем.
Добавление where
ко всем вашим запросам значительно замедлит их и будет препятствовать использованию любых индексов, которые могут быть у вас в таблице. Избегайте наличия "флагов" в ваших таблицах, когда это возможно.deleted
= 0
вы не указываете, какой продукт, но SQL Server 2008 и postgresql (и другие, я уверен) позволяют создавать отфильтрованные индексы, поэтому вы можете создать индекс покрытия, где is_deleted = 0, смягчая некоторые из негативов этот конкретный подход.
Что-то, что я использую для проектов, - это statusInd tinyint, а не нулевой столбец по умолчанию 0 using statusInd как битовая маска позволяет мне управлять данными (удалять, архивировать, копировать, восстанавливать и т.д.). Используя это в представлениях, я могу затем выполнить распределение данных, публикацию и т.д. Для приложений-потребителей. Если производительность вызывает озабоченность в отношении представлений, используйте небольшие таблицы фактов, чтобы поддержать эту информацию, отбросив этот факт, отбросив связь и разрешив удаленные удаления.
Хорошо масштабируется и ориентирован на данные, сохраняя незначительный размер данных - ключ для 350 гб + dbs с проблемами в реальном времени. Использование альтернатив, таблиц, триггеров имеет некоторые накладные расходы, которые в зависимости от необходимости могут или не могут работать для вас.
Аудиты, связанные с SOX, могут потребовать больше, чем поле, чтобы помочь в вашем случае, но это может помочь. Наслаждайтесь
Я предпочитаю хранить столбец статуса, поэтому я могу использовать его для нескольких разных конфигураций, то есть опубликованных, частных, удаленных, needsAproval...
Используйте представление, функцию или процедуру, которая проверяет is_deleted = 0
; то есть не выбирайте непосредственно на таблицу, если таблица должна быть изменена позже по другим причинам.
И индексируйте столбец is_deleted
для больших таблиц.
Поскольку у вас уже есть контрольный журнал, отслеживание даты удаления является излишним.
Создайте другую схему и выделите ее на схеме данных. Implment VPD на вашей новой схеме, чтобы каждый запрос имел предикат, позволяющий выбирать только не удаленные строки, добавленные к нему. http://download.oracle.com/docs/cd/E11882_01/server.112/e16508/cmntopc.htm#CNCPT62345
@AdditionalCriteria("this.status <> 'deleted'")
положи это поверх своего @entity