我有数据库表包含大约3百万条记录。当我删除大量行,大约400,000条记录时,该事务将永远完成。
该表未分区,数据库正在Sql Server 2012 Standard Edition上运行。我使用Nhibernate作为ORM。
如何更快地完成交易?
这里是表格的创建脚本
/****** Object: Table [dbo].[ES_DirectorDataParameters] Script Date: 03/10/2016 4:10:30 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[ES_DirectorDataParameters](
[DDP_ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[DP_Name] [varchar](255) NOT NULL,
[D_ID] [numeric](18, 0) NOT NULL,
[DDP_DisplayName] [varchar](255) NULL,
[DDP_Visibility] [varchar](50) NULL,
[DDP_Replicable] [numeric](18, 0) NOT NULL CONSTRAINT [DF_ES_DirectorDataParameters_DD_Replicable] DEFAULT ((1)),
CONSTRAINT [PK_ES_DirectorDataParameters] PRIMARY KEY CLUSTERED
(
[DP_Name] ASC,
[D_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
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[ES_DirectorDataParameters] WITH CHECK ADD CONSTRAINT [FK_ES_DirectorDataParameters_ES_DataParameters] FOREIGN KEY([DP_Name])
REFERENCES [dbo].[ES_DataParameters] ([DP_Name])
GO
ALTER TABLE [dbo].[ES_DirectorDataParameters] CHECK CONSTRAINT [FK_ES_DirectorDataParameters_ES_DataParameters]
GO
ALTER TABLE [dbo].[ES_DirectorDataParameters] WITH CHECK ADD CONSTRAINT [FK_ES_DirectorDataParameters_ES_Directors] FOREIGN KEY([D_ID])
REFERENCES [dbo].[ES_Directors] ([D_ID])
GO
ALTER TABLE [dbo].[ES_DirectorDataParameters] CHECK CONSTRAINT [FK_ES_DirectorDataParameters_ES_Directors]
GO
这是我在执行删除时删除活动监视器中的删除语句(删除大约200000行)
DELETE FROM ES_DirectorDataParameters WHERE DDP_ID = @p0
注意:为列DDP_ID创建群集索引有助于略微删除性能
由于
答案 0 :(得分:2)
让我开始:400.000记录很小。我碰巧经常删除6400万条记录。
如何更快地完成交易?
与一般情况下使SQL Server更快的方式相同:您提供的IO功能远远超出我的假设。
SQL生存和死亡的IO能力,并且在过去15年左右的时间里,每个人都在抱怨我曾经谈过的“大型”数据操作(实际上很小)的性能总是在硬件上运行SQL Server布局完全不适合任何真正的数据库工作。我们谈到了一个滑稽的关卡,比如“我想用卡车赢得一级方程式”的差异。
为了让您了解我的布局(对于6400万行操作):2个Raid 5中的6个SSD用于数据,4个SSD用于raid 10用于tempdb,2个SSD用于日志镜像。
另外请确保您有足够的内存 - 通常您应该将有效的数据集保存在内存中,以避免撞到光盘。
显然检查是否存在正确的指数。
答案 1 :(得分:1)
如果您的硬件太慢,请参阅TomTom的回答。
否则...
如果每行的大小很大,那么事务日志可能就是问题所在。特别是如果您的行是10KB或更大,那么删除100,000行可以是多GB日志记录操作。
检查事务日志文件的自动增长大小是否合理(可能是100MB),以便它不需要过于频繁地自动增长。
检查数据库恢复模型。如果它不简单"然后日志将存储所有删除,直到您的下一次备份。如果它是简单的"然后它只需要存储删除直到您提交事务。
如果您不介意将删除分成几个交易,这可能有两个好处:
此脚本将任务拆分为1000个删除块。它假定您的表具有单列主键。
{{1}}
当我不得不删除包含上传文件blob的许多行时,我使用了类似的技术。
答案 2 :(得分:1)
您在活动监视器中找到的删除语句
DELETE FROM ES_DirectorDataParameters WHERE DDP_ID = @p0
并且你提到你使用NHibernate的一条评论表明NHibernate实际上发送了200000个单独的删除语句。
因此,您的问题不是SQL查询的性能,而只是单个查询的数量。
您需要在纯SQL中重写批量删除逻辑,以便删除可以表示为一个语句。
如果您需要有关SQL的帮助,请描述要删除哪些行的逻辑,也许我可以提供帮助。