有些人在几年前做了这个UPDATE并且它工作,问题是它在一个进程中多次调用时需要花费近5个小时,这不是常规的UPDATE,表之间没有1到1个记录匹配,这会根据同一个表中的parituclar字段的累积(SUM)进行更新,事情变得更复杂,因为此SUM仅限于基于日期和其他字段的特殊条件。
我认为这类似于(隐式)内部连接,没有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
答案 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