Реализация обратимого удаления с минимальным влиянием на производительность и код

Есть некоторые похожие вопросы по теме, но они мне особо не помогают.

Я хочу реализовать функцию мягкого удаления, как в StackOverflow, где элементы на самом деле не удаляются, а просто скрываются. Я использую базу данных SQL. Вот 3 варианта:

  • Добавьте is_deleted логическое поле.

    • Advantages: Simple.
    • Недостатки: Нет записи даты. Заставляет меня добавлять is_deleted = 0 в каждый запрос.
  • Добавьте поле даты deleted_date. Это установлено на NULL, если оно не удалено.

    • Advantages: Has date.
    • Недостатки: Все еще загромождает мои запросы.

Для обоих вышеперечисленных

  • Это также повлияет на производительность, потому что есть все эти бесполезные строки. Их все еще нужно поддерживать в индексах. Также индекс в столбце deleted не поможет при извлечении неудаленных (большинства) строк. Необходимо полное сканирование таблицы.

Другой вариант — создать отдельную таблицу для хранения удаленных элементов:

  • Преимущества: повышена производительность при запросе неудаленных строк. Не нужно добавлять условия к моим запросам на неудаленные строки. Легче поддерживать индекс.
  • Недостатки: Сложность: требуется миграция данных как для удаления, так и для восстановления. Нужны новые таблицы. Со ссылочной целостностью сложнее справиться.

Есть ли лучший вариант?


person Aillyn    schedule 09.09.2011    source источник
comment
Какая СУБД? Могут быть трюки на уровне базы данных, которые могут помочь в ваших усилиях.   -  person billinkc    schedule 10.09.2011
comment
Я искал независимое решение, хотя Oracle, SQL Server и Postgres предпочтительнее - именно в таком порядке.   -  person Aillyn    schedule 10.09.2011


Ответы (5)


Если ключ числовой, я обрабатываю «мягкое удаление», отрицая ключ. (Конечно, это не сработает для идентификационных ключей). Вам вообще не нужно менять свой код, и вы можете легко восстановить запись, умножив на -1.

Просто еще один подход, чтобы подумать... Если ключ буквенно-цифровой, вы можете сделать что-то подобное, добавив перед ним уникальные "маркерные" символы. Так как все удаленные записи будут начинаться с этого маркера, то в индексе они окажутся сами по себе.

person Sparky    schedule 09.09.2011
comment
что вы имеете в виду, говоря, что вам вообще не нужно менять код? Разве вам не придется проверять знак ключа? - person Fowl; 24.09.2012
comment
Возможно, лучшим комментарием было бы то, что вам вообще не нужно менять структуру таблицы базы данных. Извините за путаницу - person Sparky; 24.09.2012
comment
Кроме того, это равносильно использованию логики типа магического числа, которая имеет уродливый дизайн - его нелегко документировать и поддерживать. - person Elemental; 16.05.2016

Лично я бы основывал свой ответ на том, как часто вы ожидаете, что ваши пользователи захотят получить доступ к этим удаленным данным или «восстановить» эти удаленные данные.

Если это часто, то я бы использовал поле «Date_Deleted» и поместил вычисленное «IsDeleted» в свой poco в коде.

Если это никогда (или почти никогда), то таблица истории или удаленная таблица хороша для преимуществ, которые вы объяснили.

Лично я почти никогда не использую удаленные таблицы (и выбираю isDeleted или date_deleted) из-за потенциального риска для ссылочной целостности. У вас есть A -> B, и вы удаляете запись из базы данных B... Теперь вам нужно управлять ссылочной целостностью из-за вашего выбора дизайна.

person Rikon    schedule 09.09.2011

На мой взгляд, лучший путь вперед, когда вы думаете о масштабировании и возможных размерах таблиц/баз данных, — это ваш третий вариант — отдельная таблица для удаленных элементов. Со временем такую ​​таблицу можно переместить в другую базу данных для поддержки масштабирования.

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

person Oded    schedule 09.09.2011

Предположим, мы создали поле с именем dead для отметки удаленных строк. Мы можем создать индекс, в котором поле dead ложно. Таким образом, мы ищем только неудаленные строки, используя индекс использования подсказки.

person Serginho    schedule 16.05.2016

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

Использование одной таблицы с удаленным флагом. Если все ваши индексы сначала содержат поле удаленного флага, а ваш запрос в основном содержит структуру типа where isdeleted=false, то это ДЕЙСТВИТЕЛЬНО решает ваши проблемы с производительностью, а индексы очень эффективно исключают удаленные строки. Аналогичная логика может быть использована для опции удаленной даты.

Использование двух таблиц Как правило, вам необходимо внести значительные изменения в отчеты, поскольку некоторые отчеты могут ссылаться на удаленные данные (например, старые данные о продажах могут относиться к удаленной категории продаж). Это можно преодолеть, создав представление, которое представляет собой объединение двух таблиц для чтения и записи только в таблицу активных записей.

person Elemental    schedule 16.05.2016