Каков наилучший способ реализовать мягкое удаление? - PullRequest
41 голосов
/ 16 сентября 2008

В данный момент мы работаем над проектом, и мы должны реализовать мягкое удаление для большинства пользователей (пользовательских ролей). Мы решили добавить поле «is_deleted = '0'» для каждой таблицы в базе данных и установить его в «1», если определенные роли пользователя нажимают кнопку удаления в определенной записи.

Для будущего обслуживания сейчас каждый запрос SELECT должен убедиться, что он не включает записи, где is_deleted = '1'.

Есть ли лучшее решение для реализации мягкого удаления?

Обновление: я должен также отметить, что у нас есть база данных аудита, которая отслеживает изменения (поле, старое значение, новое значение, время, пользователь, ip) для всех таблиц / полей в базе данных приложения.

Ответы [ 14 ]

81 голосов
/ 16 сентября 2008

Я бы склонился к «Пути рельсов» со столбцом deleted_at, который содержит дату и время, когда произошло удаление . Затем вы получите немного бесплатных метаданных об удалении. Для вашего SELECT просто получите строки WHERE deleted_at IS NULL

45 голосов
/ 16 сентября 2008

Вы можете выполнить все свои запросы к представлению, содержащему предложение WHERE IS_DELETED='0'.

20 голосов
/ 16 сентября 2008

Наличие столбца 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 строк (оба раздела).

13 голосов
/ 16 сентября 2008

К сожалению, наилучший ответ зависит от того, чего вы пытаетесь достичь с помощью программных удалений, и от базы данных, в которой вы реализуете это.

В SQL Server лучшим решением было бы использование столбца dele_on / dele_at с типом SMALLDATETIME или DATETIME (в зависимости от необходимой детализации) и сделать этот столбец пустым. В SQL Server данные заголовка строки содержат битовую маску NULL для каждого из столбцов таблицы, поэтому выполнение IS NULL или IS NOT NULL немного быстрее, чем проверка значения, хранящегося в столбце.

Если у вас большой объем данных, вы можете захотеть разбить данные на части либо через саму базу данных, либо через две отдельные таблицы (например, Products и ProductHistory), либо через индексированное представление.

Я обычно избегаю полей флагов, таких как is_deleted, is_archive и т. Д., Потому что они несут только одну часть значения. Обнуляемое поле delete_at, archived_at обеспечивает дополнительный уровень значимости для вас и любого, кто наследует ваше приложение. И я избегаю таких полей битовой маски, как чума, поскольку они требуют понимания того, как была создана битовая маска, чтобы понять любой смысл.

13 голосов
/ 16 сентября 2008

если таблица большая и производительность является проблемой, вы всегда можете переместить «удаленные» записи в другую таблицу, в которой есть дополнительная информация, например время удаления, кто удалил запись и т. Д.

таким образом вам не нужно добавлять другой столбец в основную таблицу

10 голосов
/ 16 сентября 2008

Это зависит от того, какая информация вам нужна и какие рабочие процессы вы хотите поддерживать.

Хотите ли вы иметь возможность:

  • знаете, какая информация была (до того, как она была удалена)?
  • знаете, когда оно было удалено?
  • знаете кто это удалил?
  • знаете, в каком качестве они действовали, когда удалили его?
  • удастся ли удалить запись?
  • быть в состоянии сказать, когда он был удален?
  • и т.д.

Если запись была удалена и удалена четыре раза, достаточно ли вам знать, что она в данный момент находится в не удаленном состоянии, или вы хотите иметь возможность рассказать о том, что произошло за это время (включая любые редактирование между последовательными удалениями!)?

6 голосов
/ 04 мая 2011

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

Подумайте о цикле:

  1. создать пользователя (логин = JOE)
  2. soft-delete (установить удаленный столбец в ненулевое значение.)
  3. (заново) создать пользователя (логин = JOE). ОШИБКА. ВХОД = ДЖО уже занят

Во-вторых, создание приводит к нарушению ограничения, поскольку login = JOE уже находится в строке мягкого удаления.

Некоторые приемы: 1. Переместите удаленную запись в новую таблицу. 2. Установите ограничение уникальности для столбца времени входа и отметки времени удаленного_состояния

Мое собственное мнение - +1 за переход к новому столу. Это займет много дисциплина для поддержания * AND delete_at = NULL * во всех ваших запросы (для всех ваших разработчиков)

3 голосов
/ 16 сентября 2008

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

Добавление where <code>deleted = 0 ко всем вашим запросам значительно замедлит их и затруднит использование любого из индексов, которые вы можете иметь в таблице. Старайтесь не иметь «флагов» в своих таблицах, когда это возможно.

1 голос
/ 16 сентября 2008

вы не упоминаете, какой продукт, но SQL Server 2008 и postgresql (и другие, я уверен) позволяют создавать фильтрованные индексы, чтобы вы могли создать покрывающий индекс, где is_deleted = 0, смягчая некоторые из этот конкретный подход.

1 голос
/ 16 сентября 2008

Что-то, что я использую в проектах, это statusInd tinyint, а не null, столбец по умолчанию 0 использование statusInd в качестве битовой маски позволяет мне управлять данными (удалять, архивировать, реплицировать, восстанавливать и т. д.). Используя это в представлениях, я могу затем распределять данные, публиковать и т. Д. Для приложений-потребителей. Если производительность связана с представлениями, используйте небольшие таблицы фактов для поддержки этой информации, отбрасывая факты, отбрасывая отношения и допуская масштабированные удаления.

Хорошо масштабируется и ориентирован на данные, сохраняя объем данных довольно маленьким - ключ для 350 ГБ + дБ с проблемами реального времени. Использование альтернатив, таблиц, триггеров имеет некоторые накладные расходы, которые в зависимости от необходимости могут работать, а могут и не работать.

Аудит, связанный с SOX, может потребовать больше, чем поле, чтобы помочь в вашем случае, но это может помочь. Наслаждайтесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...