2

这是一次冒险。我从上一个问题中的循环重复查询开始,但每个循环都会遍历所有1700 万条记录这意味着它需要数周时间(仅*select count * from MyTable*使用 MSSQL 2005 运行我的服务器需要 4:30 分钟)。我从这个网站和这篇文章中得到了一些信息。

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

SQL查询:

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)
4

11 回答 11

6

查看 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
于 2008-10-02T14:38:52.220 回答
2

您的数据库、服务器、存储或它们的某种组合出现问题。4:30 的选择计数 * 似乎非常高。

运行 DBCC_SHOWCONTIG 以查看您的表的碎片程度,这可能会导致该大小的表的性能受到重大影响。

此外,要添加到 RyanKeeter 的评论,运行显示计划,如果有任何表扫描,则为该表上的 PK 字段创建索引。

于 2008-10-02T14:10:17.453 回答
2

这样做不是更简单吗:

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
  )
于 2008-10-02T16:16:47.117 回答
1

在查询分析器中运行:

SET SHOWPLAN_TEXT ON

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

向我们展示查询计划。

于 2008-10-02T13:53:23.157 回答
1

1700 万条记录不算什么。如果仅执行一次 select count(*) 需要 4:30,则存在严重问题,可能与服务器内存不足或处理器非常旧有关。

为了性能,修理机器。将其泵送至 2GB。如今,RAM 是如此便宜,以至于它的成本远远低于您的时间。

查询进行时处理器或磁盘是否抖动?如果没有,那么某些东西正在阻止呼叫。在这种情况下,您可能会考虑将数据库置于单用户模式下运行清理所需的时间。

于 2008-10-02T14:04:26.827 回答
1

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

您是否需要在一次操作中删除所有重复项?我假设您正在执行某种家政任务,您也许可以分段完成。

基本上创建一个循环所有记录(脏读)并删除每个记录的游标。总体上会慢很多,但每个操作都相对较少。然后你的家务就变成了一个持续的后台任务,而不是每晚的批处理。

于 2008-10-02T14:06:09.880 回答
1

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

set rowcount 1000

在运行删除之前。它将在删除 1000 行后停止运行。然后一次又一次地运行它,直到删除 0 条记录。

于 2008-10-02T14:10:53.427 回答
1

如果我理解正确,您的查询与

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。

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

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 方法的另一个原因,我希望这会有所帮助

于 2008-10-02T15:06:37.753 回答
0

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

于 2008-10-02T14:03:32.507 回答
0

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

于 2009-07-24T14:48:26.710 回答
-1

除了按照建议使用 truncate 之外,我还很幸运地使用此模板从表中删除了许多行。我不记得了,但我认为使用事务有助于防止日志文件增长——尽管可能是另一个原因——不确定。在执行以下操作之前,我通常会将事务日志记录方法切换为简单方法:

设置行数 5000
而 1 = 1
开始
    开始翻译
            删除???在哪里 ???
            如果@@rowcount = 0
            开始
               犯罪
               休息
            结尾
    犯罪
结尾
设置行数 0
于 2008-10-02T19:28:48.967 回答