2012-07-06 65 views
0

我有一个庞大的数据库,它每天处理电子邮件流量。在系统中,就需要删除一些旧的邮件日常:提高sql删除性能并减少日志文件和tempDB的大小?

Delete from EmailList(nolock) 
WHERE EmailId IN ( 
    SELECT EmailId 
    FROM Emails 
    WHERE EmailDate < DATEADD([days], -60, GETDATE()) 
) 

它的工作原理,但问题是:它需要很长的时间来完成和日志文件变得因为这个庞大无比。日志文件大小每天增加超过100GB。

我想我们可以把它改成

Delete from EmailList(nolock) 
WHERE EXISTS ( 
    SELECT EmailId 
    FROM Emails 
    WHERE (Emails.EmailId = EmailList.EmailId) AND 
     (EmailDate < DATEADD([days], -60, GETDATE())) 
) 

但除了这一点,是有什么我们可以做些什么来提高性能。最重要的是,减少日志文件大小?

  • EmailId被索引。
+4

在DELETE上使用NOLOCK绝对没有意义。 NOLOCK不是DML操作的有效提示。 – 2012-07-06 19:19:07

+0

“EmailId已编入索引。”在哪个表格中?你可以发布查询计划吗? – 2012-07-06 19:19:51

+1

你的db的恢复模式是什么?你的减少日志大小的策略是什么? – tschmit007 2012-07-06 19:30:44

回答

0

我见过

GetDate()-60 

风格的语法进行MUCH优于

DATEADD([days], -60, GETDATE())) 

尤其是如果有日期列的索引。一些数据库管理员和我花了相当多的时间试图理解它为什么会更好,但结果是布丁。

考虑到我认为您必须删除的记录量,您可能需要考虑的另一件事是批量删除1000或10000条记录。这可能会加快删除过程。

+0

[代码] WHILE EXISTS(SELECT TOP 1 * FROM表WHERE <条件删除>) BEGIN SET ROWCOUNT 1000 DELETE表WHERE SET ROWCOUNT 0 END 将这项工作细? 我相信批量删除会截断日志,但它会减慢系统(因为它需要在每批中截断)? 我开发的C#代码,从来没有想过它会被用来处理大量的数据。 感谢您的任何建议。 – urlreader 2012-07-06 20:32:26

+0

如果我批量删除,我需要手动截断批次之间?或者数据库会自动执行它? – urlreader 2012-07-06 21:22:05

+0

截断什么?当你删除你的enver截断表。 – TomTom 2012-07-07 07:09:28

0

[编辑]:

关于@ TomTom的评论: 如果有可用的SQL Server企业版,你应该使用表分区

如果不是这种情况,我原来的职位可能是有益的:


[原帖]

删除大量的数据是很困难的。我遇到了同样的问题,我采取了以下解决方案:

根据您的要求,这不起作用,但也许你可以从中得到一些想法。

而不是使用1表,使用2表,具有相同的模式。创建一个同义词(我假设你使用的是MS SQL服务器),它指向两个表的活动表(活动的意思是,这是你当前写入的表),在你的应用程序中使用这个synyonym作为插入,或者而不是使用同义词,应用程序可以每隔x天更改一次表格

每x天你可以截断旧/使用synonnym解决方案),因此有效地划分每次的数据。

您必须同步活动表的开关。我通过使用应用程序的共享应用程序锁来完全自动化,并在更改同义词(==在切换过程中阻止写入应用程序)时使用独占Applock。

如果更改您的应用程序的代码不是一个选项,请考虑使用相同的原则,而不是写入同义词,您可以创建一个视图而不是触发器(插入操作将插入“活动”分区)。如上所述,触发器代码需要使用类似Applock的syhcnronize(以便在切换过程中工作)。

我的解决方案比较复杂,所以我目前不能在这里发布代码,但它对高负载应用程序没有问题,并且swithcingt/cleanup过程完全自动化。

+0

?在像这样的scnario中按日期删除大的字体是微不足道的,并且在第二时间内没有任何问题。这是为此开发的特殊技术,即表格分区。任何处理休数据量的人都应该知道他的解决方法。 – TomTom 2012-07-06 20:18:28

+0

谢谢。这听起来像是一个上帝的想法。稍后会检查它。现在,我想知道是否有更简单的方法来实现这个目标,所以不必更改太多的c#代码。 还是,感谢您指出一个有前途的解决方案。再次感谢。 – urlreader 2012-07-06 20:28:23

+0

@TomTom是的,有技术,但如果你使用的MS Sql这个所需的企业版,这是不适用于我的情况(其他数据库系统也有类似的conepts,但我认为这是MSSQL服务器,而不是企业版 - whci可能会错的)。但这是一个很好的观点 - 如果有技术可用,请使用它们。 – 2012-07-06 20:41:24

0

你有没有尝试按日期划分,那么你可以放弃表格版本的日子哟你不再感兴趣了。给定一个“休”数据库你肯定会运行SQL Server的企业版(毕竟,休是大于非常大),并有表分区。

+0

感谢提到表分区。会检查它。然而,该程序是由不同的用户使用,我不能假设他们都使用企业版。也许必须先检查C#代码中的数据大小和sql版本,然后用不同的方式删除。但它似乎应该有一个更好/直接的方式来做到这一点,虽然我可能是错的。谢谢。 – urlreader 2012-07-06 20:45:06

+0

啊 - 没有。站起来说你不会“拥有大量的数据”。 Hugh听起来比VLDB更大,现在的数据量就是几百GB - 我的最后一个db是21000GB;)您不会使用普通标准版运行它。 – TomTom 2012-07-06 21:10:12

+0

好吧,够公平的。因此,对于非休数据数据库,有什么建议?批量删除?我需要手动在批次之间做些什么吗?即截断?或者,让sql服务器自动执行它? 谢谢 – urlreader 2012-07-06 21:23:48