软删除 - 使用IsDeleted标志还是单独的连接表?

Jon*_*nor 8 indexing soft-delete sql-server-2008-r2

我们应该使用标志进行软删除还是单独的连接表?哪个更有效率?数据库是SQL Server.

背景资料

前一阵子,我们有一位DB顾问进来查看我们的数据库架构.当我们软删除记录时,我们将更新相应表上的IsDeleted标志.有人建议,不要使用标志,而是将已删除的记录存储在单独的表中,并使用连接,因为这样会更好.我已经把这个建议付诸实践,但至少在表面上,额外的表和连接看起来比使用标志更昂贵.

初步测试

我已经设置了这个测试.

两个表,Example和DeletedExample.我在IsDeleted列上添加了一个非聚集索引.

我做了三次测试,加载了一百万条记录,其中包含以下已删除/未删除的比率:

  • 删除/ NonDeleted
  • 50/50
  • 10/90
  • 1/99

结果 - 50/50 50 50

结果 - 10/90 10 90

结果 - 1/99 在此输入图像描述

数据库脚本,供参考,示例,DeletedExample和Example.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
Run Code Online (Sandbox Code Playgroud)

Str*_*ior 8

您所拥有的数字似乎表明我的初始印象是正确的:如果针对此数据库的最常见查询是要过滤IsDeleted = 0,那么使用简单的位标志性能会更好,特别是如果您明智地使用索引.

如果您经常单独查询已删除和未删除的数据,则可以通过为已删除的项目设置表格来获得性能提升,而对于未删除的项目,可以看到具有相同字段的另一个表格.但是,像这样对数据进行非规范化很少是一个好主意,因为在代码维护成本方面,通常会花费更多,而不是在性能提升方面.

  • 好答案.还要考虑使用筛选索引.如果仅在未删除记录时按列1查询Example表,则索引Column1"WHERE IsDelete = 0". (2认同)