优化复杂的SQL更新

时间:2013-11-08 18:08:26

标签: sql sql-server sql-server-2005 group-by sql-server-2000

有些人在几年前做了这个UPDATE并且它工作,问题是它在一个进程中多次调用时需要花费近5个小时,这不是常规的UPDATE,表之间没有1到1个记录匹配,这会根据同一个表中的parituclar字段的累积(SUM)进行更新,事情变得更复杂,因为此SU​​M仅限于基于日期和其他字段的特殊条件。

我认为这类似于(隐式)内部连接,没有1到1的匹配,比如ALL VS ALL,所以当表中有7000条记录时,这个东西会处理7000 * 7000条记录,超过5500万条,在我看来,游标应该在这里使用,但现在我需要更快的速度,我不认为游标会让我在那里。

我的问题是:有没有办法重写这个并让它更快?注意那个SUM的条件,这不是一个容易看到的更新(至少对我而言)。

更多信息: CodCtaCorriente和CodCtaCorrienteMon是这个表的主键,但正如我之前所说的那样,无意在这里进行1比1的匹配,这就是为什么在查询中不使用这些键,CodCtaCorrienteMon用于条件而不是连接条件(上)。

UPDATE #POS SET SaldoDespuesEvento = 
     (SELECT SUM(Importe) 
        FROM #POS CTACTE2
       WHERE CTACTE2.CodComitente = #POS.CodComitente  
         AND CTACTE2.CodMoneda = #POS.CodMoneda
         AND CTACTE2.EstaAnulado = 0 
         AND (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) > 0 
              OR
             (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) = 0 
              AND (#POS.CodCtaCorrienteMon >= CTACTE2.CodCtaCorrienteMon)))) 
WHERE #POS.EstaAnulado = 0 AND #POS.EsSaldoAnterior = 0

ScreenShot - Execution Plan

3 个答案:

答案 0 :(得分:1)

从您的查询计划看,它大部分时间都在索引假脱机后的过滤器中消费。

如果你打算多次运行这个查询,我会在'CodComitente','CodMoneda','EstaAnulado','FechaLiquidacion'和'CodCtaCorrienteMon'栏目上创建一个索引。

我对Index Spool迭代器了解不多;但基本上从我对它的理解,它被用作在查询时创建的“临时”索引。因此,如果您多次运行此查询,我将创建该索引一次,然后根据需要多次运行查询。

另外,我会尝试创建一个变量来存储sum操作的结果,这样你就可以避免尽可能多地运行它。

DECLARE @sumVal AS INT

SET @sumVal = SELECT SUM(Importe) 
        FROM #POS CTACTE2
       WHERE CTACTE2.CodComitente = #POS.CodComitente  
         AND CTACTE2.CodMoneda = #POS.CodMoneda
         AND CTACTE2.EstaAnulado = 0 
         AND (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) > 0 
              OR
             (DATEDIFF(day, CTACTE2.FechaLiquidacion, #POS.FechaLiquidacion) = 0 
              AND (#POS.CodCtaCorrienteMon >= CTACTE2.CodCtaCorrienteMon)))

UPDATE #POS SET SaldoDespuesEvento = @sumVal
WHERE #POS.EstaAnulado = 0 AND #POS.EsSaldoAnterior = 0

答案 1 :(得分:0)

如果没有查询计划,很难提供帮助,但我会假设如果FechaLiquidacion和CodCtaCorrienteMon列上还没有索引,只要数据库存储空间不是,就可以通过创建它们来提高性能。问题。

答案 2 :(得分:0)

找到解决方案,这是一个常见问题:运行总计

这是CURSORS表现更好的少数情况之一,请参阅此处和更多可用解决方案(或浏览stackoverflow,有很多这样的情况):

http://weblogs.sqlteam.com/mladenp/archive/2009/07/28/SQL-Server-2005-Fast-Running-Totals.aspx