我正在编写一个过程来删除n天内几张表中的所有行。
简单的简单查询很容易编写
DELETE FROM [myTable]
WHERE [Created] < GETDATE()-30
一个问题是日期字段上没有索引 - 我可以添加一个,但我正在通过做类似的事情来解决它:
SELECT @var = MAX([ID]) FROM myTable WHERE Created < GETDATE()-30;
DELETE FROM myTable WHERE ID < @var
这看起来像是一种可接受的方法吗?
问题是表格很大,而且每次运行时此查询可能会删除数十万行。
在(稍慢)测试服务器上运行它需要一个小时左右的时间,并从其他进程中读取/写入它来杀死该表。
我不介意它需要一段时间才能运行(虽然速度越快越好) - 但我不能让它在运行时锁定表一小时,因为有持续的读/写(主要写道。)
我的DB知识非常基础,因为我是编码员而不是dba。
有人可以以最有效的方式为我提供执行此任务的合适方法。
答案 0 :(得分:6)
您正在寻找的是基于分区的滑动窗口:How to Implement an Automatic Sliding Window in a Partitioned Table on SQL Server 2005。每天对表进行分区,您可以在午夜的单个分区切换操作中有效地停止一整天。分区开关基本上是瞬时的。
如果你想要一个开销略低的解决方案(分区会产生严重的后果并影响整个应用程序,特别是当索引必须对齐时,这是快速切换操作的要求),那么你必须设计你的模式按照这个操作。置信度为99.99%,我可以说myTable
最左边的群集密钥必须为Created
字段。这将允许有效的批量删除(delete top (2500) from myTable where Created < ...
)。您希望对其进行批处理有很多原因(一次最多2500个),最重要的是您必须避免锁定升级,并且必须将任何单个事务的大小保持在合理的限制范围内。
答案 1 :(得分:3)
您的方法将遭受与正常删除相同的疾病 - 您在[已创建]上没有索引。因此,您的方法更加复杂。
我建议您创建所述索引并在测试服务器上尝试正常删除。
另一个建议 - 通过调度程序在正常工作时间之外运行。
答案 2 :(得分:3)
要提高性能,您应该考虑在Created字段上创建索引,如果这是您想要经常做的事情。
然后你可以使用
DELETE FROM myTable
WHERE Created < GETDATE()-30
我已经看到,通过适当的索引和统计信息添加,多小时进程减少到几秒钟。
索引很容易创建,并且可以使用工具来建议索引并提供语法。示例:MS SQL 2005 Management Studio中的SQL Tuning Advisor。
答案 3 :(得分:2)
我将假设您无法索引Created列(因为这是另一个开始的逻辑位置)。基于该假设,您将遇到性能和锁定问题。但是,由于您使用的是SQL 2005,因此可以利用本文中指定的一些新功能: http://nayyeri.net/reduce-locks-for-delete-and-update-commands-in-sql-server-2005-with-top-clause
基本上,创建一个选择您想要影响的所有记录的查询。将行标识符(已编制索引)写入临时表。根据标识符将临时表链接到要删除的表。然后使用此处指定的批量删除一次删除组。
通过这种方式,您可以根据日期条件创建临时表(由于非索引而无效,但您可以设置NOLOCK,这样就不会锁定您)。然后批量删除表,以减少对实际删除的锁定。
答案 4 :(得分:0)
创建索引并在办公时间之外执行删除可能是最好的事情。但是,如果它们不是选项,您可以根据查询创建视图并删除该视图,因此只需要引用该表一次,而不是两次,从而加快IO操作。
create view v1 as (select * FROM myTable WHERE Created < GETDATE()-30;)
delete from v1