我们应该使用标记进行软删除还是使用单独的连接表?哪个更有效率?数据库是SQL Server。
背景资料
前段时间我们有一位DB顾问进来查看我们的数据库架构。当我们软删除记录时,我们将更新相应表上的IsDeleted标志。有人建议,不要使用标志,而是将已删除的记录存储在单独的表中,并使用连接,因为这样会更好。我已经把这个建议付诸实践,但至少在表面上,额外的表和连接看起来比使用标志更昂贵。
初步测试
我已经设置了这个测试。
两个表,Example和DeletedExample。我在IsDeleted列上添加了一个非聚集索引。
我做了三次测试,加载了一百万条记录,其中包含以下已删除/未删除的比率:
结果 - 50/50
结果 - 10/90
结果 - 1/99
数据库脚本,供参考,示例,DeletedExample和示例索引.IsDeleted
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
答案 0 :(得分:8)
您所拥有的数字似乎表明my initial impression是正确的:如果针对此数据库的最常见查询是对IsDeleted = 0
进行过滤,那么使用简单的位标记会提高性能,尤其是你明智地使用索引。
如果您经常单独查询已删除和未删除的数据,则可以通过为已删除的项目设置表格以及使用相同字段的未删除项目的另一个表格来查看性能提升。但是,像这样对数据进行非规范化很少是一个好主意,因为在代码维护成本中,通常会花费更多的成本,而不是在性能提升中获得成本。
答案 1 :(得分:1)
我不是SQL专家,但在我看来,这一切都取决于数据库的使用频率。如果数据库被大量用户访问并且需要高效,则使用单独的isDeleted表将是好的。更好的选择是在生产期间使用标志,并且作为每日/每周/每月maintanace的一部分,您可以将所有软删除的记录移动到isDeleted表并清除软删除记录的生产表。两种选择的混合都是好的。