我有一个大型SQL Server数据库,其中包含大约4500万条记录的表。我正在归档此表,并且需要删除两年多以前的所有条目。我插入到我的存档表工作正常,但我在删除时遇到效率问题。
我的问题在于当前表中的索引。我想在1000个记录块中删除(和存档插入)。为此,我需要确定满足要求的“最高”1000条记录(大于两年)。行上的DateTime标记是聚簇索引,因此这对于抓取行非常有用。但是SQL 2000不允许DELETE TOP 1000 ....所以我需要做类似的事情:
DELETE FROM <table> WHERE [UniqueID] IN
(SELECT TOP 1000 [UniqueID] FROM <table> WHERE [DateTime] < @TwoYearsAgo)
如果将UniqueID编入索引,这将非常有用。由于它不是,这需要很长时间(它扫描表中要删除的1000条记录中的每一条)。表上没有唯一标识记录的其他索引。我被告知在UniqueID上计算索引的成本太高,因为这是一个实时数据库。任何人都可以指出一种优化此查询的方法吗?
答案 0 :(得分:17)
如何重写查询?
SET ROWCOUNT 1000
DELETE FROM <table> WHERE [DateTime] < @TwoYearsAgo
请参阅SET ROWCOUNT (Transact-SQL)上的文档。
另请注意,根据DELETE的文档,它支持TOP
子句,但对于SQL Server 2005及更高版本来说这显然是新的。我这样说是因为它听起来像你的数据库服务器不支持,但你真的尝试过使用它吗?我无法访问SQL Server 2000文档,所以我不确定该版本是否支持它。很可能不是。
DELETE TOP (1000) FROM <table> WHERE [DateTime] < @TwoYearsAgo
请注意,与选择 中的TOP的方式不同,不带括号。对于UPDATE,DELETE和INSERT,表达式必须带括号,即使它只是上面的常数。
答案 1 :(得分:8)
您可以删除子查询:
DELETE <table> FROM (
SELECT TOP 1000 *
FROM <table>
WHERE [DateTime] < @TwoYearsAgo);
参见示例E:SQL 2000 DELETE Syntax。建议使用SET ROWCOUNT方法。在SQL 2005及更高版本中,您可以直接在DELETE中指定TOP。
答案 2 :(得分:3)
你也可以
DELETE TOP(1000) FROM <table> WHERE [DateTime] < @TwoYearsAgo
上帝只知道为什么他们使用top(x)进行删除而使用top x进行选择,大多数人似乎都不知道这个功能!
编辑:显然是它的2005+所以你应该忽略这一点。
答案 3 :(得分:2)
您可以使用SET ROWCOUNT:
SET ROWCOUNT 1000
DELETE FROM <table> WHERE [DateTime] < @TwoYearsAgo
答案 4 :(得分:1)
我不得不做一些类似的事情 - 使轻量级插入和删除将旧记录移动到存档表。虽然违反直觉,但我找到的最快且影响最小的解决方案是:
使用顶部(x)行的ID值创建一个小的#temp表。如果您的方案中确实无法为ID编制索引,则可以改为使用日期和ID,因此两者的组合可以使用索引。
begin tran
在(#temp)
从(#temp)
提交
截断#temp
重复
使用临时表来分级行标识符比直接删除更加完整,但是如果你想在不阻塞的情况下一次一点地消失,那么这个过程非常轻量级。
此外,我同意Lasse - 无法看到没有索引的唯一ID,因此没有约束来强制执行它。
答案 5 :(得分:0)
我想知道你是否必须坚持1000记录块的要求。如果由于服务器负载和任意类型的原因存在,您可能想尝试以下,因为您已经在[DateTime]上有一个聚集索引:
DELETE FROM <table>
WHERE [DateTime] < @TwoYearsAgo
and [DateTime] < (select dateadd(day, 1, min([DateTime])) from <table>)
答案 6 :(得分:0)
为了向后兼容,括号在SELECT语句中是可选的。我们建议您始终在SELECT语句中对TOP使用括号,以便与INSERT
,UPDATE
,MERGE
和DELETE
语句中的必需用法保持一致,其中括号是必需的
USE AdventureWorks;
GO
DELETE TOP (20)
FROM Purchasing.PurchaseOrderDetail
WHERE DueDate < '20120701';
GO