Soft Delete - Используйте Isdeleted Flag или отдельную таблицу столярец?
-
28-10-2019 - |
Вопрос
Должны ли мы использовать флаг для мягких удалений или отдельной столичной стола? Что более эффективно? База данных - SQL Server.
Исходная информация
Некоторое время назад у нас был консультант DB и посмотрел нашу схему базы данных. Когда мы мягким удаляем запись, мы бы обновили бы имещаемый флаг на соответствующей таблице. Было высказано предположение, что вместо использования флага храните удаленные записи в отдельной таблице и используйте соединение, так как это было бы лучше. Я проверил это предложение, но, по крайней мере, на поверхности, дополнительная таблица и соединение выглядит более дорогим, чем использовать флаг.
Первоначальное тестирование
Я настроил этот тест.
Две таблицы, пример и deletedExample. Я добавил некластеризированный индекс на столбце ISDELED.
Я сделал три теста, загрузив миллион записей со следующими удаленными/не удаленными соотношениями:
- Удален/не снлет
- 50/50
- 10/90
- 1/99
Результаты - 50/50
Результаты - 10/90
Результаты - 1/99
Сценарии базы данных, для справки, пример, deletedExample и индекс, например.
CREATE TABLE [dbo].[Example](
[ID] [int] NOT NULL,
[Column1] [nvarchar](50) NULL,
[IsDeleted] [bit] NOT NULL,
CONSTRAINT [PK_Example] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Example] ADD CONSTRAINT [DF_Example_IsDeleted] DEFAULT ((0)) FOR [IsDeleted]
GO
CREATE TABLE [dbo].[DeletedExample](
[ID] [int] NOT NULL,
CONSTRAINT [PK_DeletedExample] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
ALTER TABLE [dbo].[DeletedExample] WITH CHECK ADD CONSTRAINT [FK_DeletedExample_Example] FOREIGN KEY([ID])
REFERENCES [dbo].[Example] ([ID])
GO
ALTER TABLE [dbo].[DeletedExample] CHECK CONSTRAINT [FK_DeletedExample_Example]
GO
CREATE NONCLUSTERED INDEX [IX_IsDeleted] ON [dbo].[Example]
(
[IsDeleted] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
Решение
Числа, которые вы, кажется, указывают на то, что мое первоначальное впечатление был правильным: если ваш самый распространенный запрос по этой базе данных - фильтровать на IsDeleted = 0
, Тогда производительность будет лучше с простом битом, особенно если вы используете индексы.
Если вы часто запрашиваетесь на удаленные и неопределенные данные отдельно, то вы можете увидеть прирост производительности, имея таблицу для удаленных элементов, а другой - для неиспользованных предметов, с одинаковыми полями. Но денормализация ваших данных, подобных этим, редко бывает хорошей идеей, так как чаще всего это будет стоить вам гораздо дороже в затратах на обслуживание кода, чем при повышении производительности.
Другие советы
Я не эксперт SQL, но, на мой взгляд, все зависит от частоты использования базы данных. Если к базе данных доступно большое количество пользователей и должна быть эффективной, то использование отдельной таблицы Isledeted будет хорошим. Лучшим вариантом будет использование флага во время производства, и в рамках ежедневной/еженедельной/ежемесячной Maintanace вы можете перемещать все мягкие удаленные записи в таблицу Isdeled и очистить производственную таблицу мягких удаленных записей. Смесь обоих вариантов будет хорошей хорошей.