Delete Large Number of Rows Is Very Slow - SQL Server

我是研究僧i 提交于 2019-12-24 15:22:06

问题


I have database table contains around 3 millions records. When I delete large number of rows, around 400,000 records, the transaction takes forever to finish.

The table is not partitioned and the database is running on Sql Server 2012 Standard Edition. I'm using Nhibernate as ORM.

How do I make the transaction faster?

Here the creation script of the table

/****** 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

here is the delete statement I found in the Activity Monitor when executing the delete (deleting around 200000 rows)

DELETE FROM ES_DirectorDataParameters WHERE DDP_ID = @p0

Note: Creating Cluster Index for the column DDP_ID helped the deletion performance slightly

Thanks


回答1:


Let me start: 400.000 records is small. I happen to regularly delete batches of 64 million records.

How do I make the transaction faster?

The same way you make SQL Server faster in general: you provide a lot more IO capabilities than I assume you have.

  • Split database, tempdb and log into separate hard discs. Oh, and make this an SSD or at least something with a backed up buffer.

SQL lives and dies by IO capabilities, and somehoe in the last 15 years or so everyone complaining about the performance of "large" data operations (Which in reality are tiny) that I ever talked to always ran SQL Server on a hardware layout that was totally inadequate for any real database work. We talk of a comical levels like "I want to win formula one with a truck" type of discrepancies.

To give you an idea of my layout (for the 64 million row operations): 6 SSD in 2x Raid 5 for data, 4 SSD in a Raid 10 for tempdb and 2 SSD mirrored for logs.

Also make sure you have enough memory - generally you should keep the active set of your data in memory, to avoid hitting discs.

And obviously check whether the proper indices exist.




回答2:


The delete statement you found in the Activity Monitor

DELETE FROM ES_DirectorDataParameters WHERE DDP_ID = @p0

and one of your comments mentioning you use NHibernate indicate that NHibernate is actually sending 200000 separate delete statements.

So your problem is not the performance of a SQL query, but simply the volume of individual queries.

You need to rewrite the batch delete logic in pure SQL so that the deletion can be expressed as one statement.

If you need help with the SQL, please describe the logic about which rows are to be deleted and maybe I can help.




回答3:


If your hardware is just too slow then see TomTom's answer.

Otherwise....

If the size of each row is large, then transaction logs may be the problem. Particularly if your rows are 10KB or bigger then deleting 100,000 rows can be a multi GB logging operation.

Check whether the auto growth size of your Transaction Log file is reasonable (perhaps 100MB) so that it doesn't need to auto grow too frequently.

Check your database Recovery Model. If it is not "simple" then the log will be storing all deletes until your next backup. If it is "simple" then it only has to store deletes until you commit the transaction.

If you don't mind splitting the deletes into several transactions this can have two benefits:

  • You can interrupt (and restart) the deletion operation without the whole thing being rolled back.
  • If Recovery Model is simple then it keeps the size of the transaction log down.

This script splits the task into chunks of 1000 deletes. It assumes that your table has a single column primary key.

DECLARE @RC INT;
SET @RC = 1;

WHILE (@RC > 0)
BEGIN
    BEGIN TRAN
        DELETE FROM YOUR_TABLE
        WHERE ID IN (
            SELECT TOP(1000) ID 
            FROM YOUR_TABLE AS T
            WHERE {your criteria for deletion using alias T}
        );
        SET @RC = @@ROWCOUNT;
    COMMIT
END

I used a similar technique when I had to delete many rows that contained blobs of uploaded files.



来源:https://stackoverflow.com/questions/35884918/delete-large-number-of-rows-is-very-slow-sql-server

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!