删除大量行非常慢 - SQL Server

时间:2016-03-09 06:54:53

标签: sql-server database nhibernate database-performance

我有数据库表包含大约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创建群集索引有助于略微删除性能

由于

3 个答案:

答案 0 :(得分:2)

让我开始:400.000记录很小。我碰巧经常删除6400万条记录。

  

如何更快地完成交易?

与一般情况下使SQL Server更快的方式相同:您提供的IO功能远远超出我的假设。

  • 拆分数据库,tempdb并登录到单独的硬盘。哦,把它变成SSD或至少带有备份缓冲区的东西。

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的帮助,请描述要删除哪些行的逻辑,也许我可以提供帮助。