是否可以优化此查询?

时间:2010-11-14 11:59:13

标签: sql sql-server sql-server-2008

我尝试执行以下查询:

update ms
    set user_B_total_duration = amc.total_duration
    from monthly_statistics ms
        inner join aggregate_monthly_conversations amc
            on ms.user_B = amc.user_B

但查询已执行超过10个小时。每个表中有大约23M条记录(monthly_statistics和aggregate_monthly_conversations)。数据库引擎是SQL Server 2008,PC是四核2.66 GHz,4GB RAM。

是否有人知道是否可以通过任何变通方法优化上述查询或执行相同的任务?

5 个答案:

答案 0 :(得分:1)

如果我要对此进行故障排除,这些是我要注意的事项:

  1. 如果可行,请确保没有人垄断该表(即锁定它)
  2. 确保对连接列编制索引(即ms.user_Bamc.user_B
  3. 使用UPDATE TOP (100) ms SET ...
  4. 批量更新列

    在进行大型插入/更新/删除时,第3项实际上非常重要。如果SQL Server部分失败,则会生成日志以撤消此操作,这会变得越来越昂贵。如果你必须更新1米宽的行,那么在20批50k行上操作可能要快得多。我见过建议声称这会产生巨大的差异(而且它确实是AFAICT)。另外,这可以防止对表的排队请求排队等。

    但有两点需要注意:1。您将分别提交每个批次,因此您需要确保您的操作可以容忍“部分完成”。 (我猜这个可以重新启动。)2。你需要知道哪些列已更新。

    所以,在你的情况下,也许:

    declare @update_date datetime;
    set @update_date = getdate();
    
    while 1 = 1
    begin
        update top(10000) ms set
            user_B_total_duration = amc.total_duration,
            last_updated = @update_date
        from
            monthly_statistics ms
            inner join aggregate_monthly_conversations amc
            on ms.user_B = amc.user_B
        where
            ms.last_updated < @update_date;
    
        if @@rowcount = 0 break;
    end
    

    你也可以打印出来告诉你你走了多远。

答案 1 :(得分:0)

例如,您可以在ad-hoc表中插入除ms之外的表中的所有数据,因此您的更新将更容易处理:不再需要连接,也可以使用较少量的数据。

答案 2 :(得分:0)

monthly_statistics.User_Baggregate_monthly_conversations.User_B上的索引是一个很好的开始,可能是total_duration aggregate_monthly_conversations.User_B索引上的including {{1}}。

答案 3 :(得分:0)

看起来你已经完全消除了这台机器上的内存,而SQL Server正在将内存交换到磁盘。 4GB Ram不是那么多。

运行此查询需要多长时间?返回多少行?

select 
'update monthly_statistics set user_B = ' +
CAST(amc.total_duration as varchar) + ' ' +
'where user_B = ' + 
CAST(ms.user_B as varchar) + ' GO' 
from monthly_statistics ms 
inner join aggregate_monthly_conversations amc 
on ms.user_B = amc.user_B 

您可以使用此输出更新表格。

答案 4 :(得分:0)

一个更基本的问题:为什么你甚至可以在这个昂贵的月末非规范化批处理中占据首位,当你可以通过即席查询获得任何用户的total_duration时?采用这种非RDBMS方法的特定原理是什么?通常,当临时查询过于昂贵且对于临时报告目的而言较慢时,人们会采用批量处理月末数据。在你的情况下是这样吗?

对于连接列上的索引,ms.user_b和amc.user_b,您应该能够通过两个表的简单连接获得任何用户的total_duration。 23M记录中有多少个不同的用户?如果ms.user_b列的基数较低,那么复合索引(例如(ms.user_b,timeperiod)或类似的东西(我们不知道您的架构)可能会产生所需的临时性能,而不会在插入/更新时出现不可接受的性能下降?

如果你必须保留原样,你可以尝试一个存储过程,在其中选择一组不同的AMC.user_ids到一个游标中,并一次处理一个id的表MS的更新:

 ...
 from monthly_statistics ms 
 inner join aggregate_monthly_conversations amc 
 on ms.user_B = amc.user_B  and ms.user_b = @currentuserid

这也需要至少一个简单索引:在ms.user_b列上,或复合索引上(ms.user_b,{some some(s)})。