这是一次冒险。我从位于上一个问题中的循环重复查询开始,但每个循环将覆盖所有 1700万条记录意味着需要数周(只需运行 * select count * from MyTable * 使用MSSQL 2005,我的服务器需要4:30分钟)。我从这个网站和这个帖子发现了信息。

已经到达下面的查询。问题是,对于任何类型的性能,这是在1700万条记录上运行的正确类型的查询吗?如果不是,那是什么?

SQL QUERY:

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    EXCEPT
    SELECT RecordID
    FROM (
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude,           Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
    FROM tl_acxiomimport.dbo.tblacxiomlistings
    ) al WHERE Rank = 1)
有帮助吗?

解决方案

查看QueryPlan会有所帮助。

这可行吗?

SELECT m.*
into #temp
FROM tl_acxiomimport.dbo.tblacxiomlistings m 
inner join (SELECT RecordID, 
                   Rank() over (Partition BY BusinessName, 
                                             latitude,  
                                             longitude,            
                                             Phone  
                                ORDER BY webaddress DESC,  
                                         caption1 DESC,  
                                         caption2 DESC ) AS Rank
              FROM tl_acxiomimport.dbo.tblacxiomlistings
           ) al on (al.RecordID = m.RecordID and al.Rank = 1)

truncate table tl_acxiomimport.dbo.tblacxiomlistings

insert into tl_acxiomimport.dbo.tblacxiomlistings
     select * from #temp

其他提示

您的数据库,服务器,存储或其某些组合可能会出现问题。 4:30选择计数*似乎非常高。

运行DBCC_SHOWCONTIG以查看表格的碎片程度,这可能会导致对大小的表格产生重大影响。

此外,要添加RyanKeeter的评论,请运行show plan,如果有任何表扫描,请在该表上为PK字段创建索引。

这样做不会更简单:

DELETE tl_acxiomimport.dbo.tblacxiomlistings
WHERE RecordID in 
(SELECT RecordID
   FROM (
        SELECT RecordID,
            Rank() over (Partition BY BusinessName,
                                  latitude,
                                  longitude,
                                  Phone
                         ORDER BY webaddress DESC,
                                  caption1 DESC,
                                  caption2 DESC) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        )
  WHERE Rank > 1
  )

在查询分析器中运行:

SET SHOWPLAN_TEXT ON

然后请求查询分析器运行您的查询。 SQL Server将生成查询计划并将其放入结果集中,而不是运行查询。

向我们展示查询计划。

1700万条记录什么都没有。如果只需要4:30进行选择计数(*),那么就会出现严重的问题,可能与服务器内存不足或者处理器老旧有关。

为了提高性能,请修理机器。将其泵送至2GB。 RAM现在非常便宜,其成本远远低于你的时间。

当查询进行时,处理器或磁盘是否会发生颠簸?如果没有,那么有些东西阻止了这些电话。在这种情况下,您可以考虑将数据库置于单用户模式中,以确定运行清理所需的时间。

所以你要删除所有未排名第一的记录?可能值得将连接与前1个子查询进行比较(这可能也适用于2000年,因为排名仅为2005及以上)

您是否需要在一次操作中删除所有重复项?我假设您正在执行某种内务管理任务,您可能可以分段执行。

基本上创建一个循环所有记录的游标(脏读)并删除每个记录的欺骗。总体来说它会慢得多,但每次操作都会相对最小。然后你的家务管理成为一个持续的后台任务而不是每晚一次。

首先选择临时表的建议是最好的选择。你也可以使用类似的东西:

set rowcount 1000

在运行删除之前。删除1000行后,它将停止运行。然后反复运行,直到删除0条记录。

如果我正确理解你的查询与

相同
DELETE tl_acxiomimport.dbo.tblacxiomlistings
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

我认为应该跑得更快,我倾向于避免使用“IN”。在可能的情况下支持JOIN的条款。

您可以通过简单地在FROM部分调用 SELECT * SELECT COUNT(*)来安全地测试速度和结果,例如

SELECT *
FROM
    tl_acxiomimport.dbo.tblacxiomlistings allRecords
    LEFT JOIN (   
        SELECT RecordID, Rank() over (Partition BY BusinessName, latitude, longitude, Phone ORDER BY webaddress DESC, caption1 DESC, caption2 DESC ) AS Rank
        FROM tl_acxiomimport.dbo.tblacxiomlistings
        WHERE Rank = 1) myExceptions
    ON allRecords.RecordID = myExceptions.RecordID
WHERE
    myExceptions.RecordID IS NULL

这是我更喜欢JOIN方法的另一个原因 我希望有帮助

这看起来很好,但您可以考虑将数据选择到临时表中并在删除语句中使用它。我注意到这样做会带来巨大的性能提升,而不是在一个查询中完成所有操作。

请记住,在进行大型删除时,最好先备份一个好的备份。(我通常也会将删除的记录复制到另一个表中以防万一,我需要立即恢复它们。)

除了建议使用truncate之外,我还有幸使用此模板从表中删除大量行。我不记得了,但我认为使用该事务有助于保持日志文件的增长 - 可能是另一个原因 - 不确定。在执行以下操作之前,我通常会将事务日志记录方法切换为简单:

SET ROWCOUNT 5000
WHILE 1 = 1
BEGIN
    begin tran
            DELETE FROM ??? WHERE ???
            IF @@rowcount = 0
            BEGIN
               COMMIT
               BREAK
            END
    COMMIT
END
SET ROWCOUNT 0
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top