优化复杂的SQL更新
几年前,有人在工作中进行了此更新,itt可以工作,问题是在一个进程中多次调用时需要将近5个小时,这不是一个定期更新,表之间没有1对1记录匹配,此更新基于同一表中parituclar字段的累计(总和)进行,事情变得更复杂了,因为这个总和被限制在基于日期和另一个字段的特殊条件下 我认为这有点像(隐式)内部连接,没有1对1的匹配,就像ALL VS ALL一样,所以当表中有7000条记录时,它将处理7000*7000条记录,超过5500万条,在我看来,这里应该使用游标,但现在我需要更高的速度,我不认为游标将使我达到目的 我的问题是:有没有办法重写它,让它更快??注意这个总数的条件,这不是一个容易看到的更新(至少对我来说) 更多信息: CoDctCorriente和CoDctCorrienteMon是这个表上的主键,但是,正如我之前所说,这里无意进行1对1的匹配,这就是为什么在查询中不使用这些键,CoDctCorrienteMon在条件中使用,而不是作为连接条件(on)优化复杂的SQL更新,sql,sql-server,sql-server-2005,group-by,sql-server-2000,Sql,Sql Server,Sql Server 2005,Group By,Sql Server 2000,几年前,有人在工作中进行了此更新,itt可以工作,问题是在一个进程中多次调用时需要将近5个小时,这不是一个定期更新,表之间没有1对1记录匹配,此更新基于同一表中parituclar字段的累计(总和)进行,事情变得更复杂了,因为这个总和被限制在基于日期和另一个字段的特殊条件下 我认为这有点像(隐式)内部连接,没有1对1的匹配,就像ALL VS ALL一样,所以当表中有7000条记录时,它将处理7000*7000条记录,超过5500万条,在我看来,这里应该使用游标,但现在我需要更高的速度,我不认为游
如果没有查询计划,很难有多大帮助,但我假设,如果FechaLiquidacion和codctcorrientemon列上还没有索引,那么只要数据库存储空间不是问题,就可以通过创建它们来提高性能。从您的查询计划来看,它似乎花费了大部分时间在索引滑阀之后过滤器中的时间 如果要多次运行此查询,我将在“Codcomiente”、“CodMoneda”、“Estaunolado”、“FechaLiquidacion”和“CodctCorrienteMon”列上创建索引 我对索引假脱机迭代器了解不多;但基本上从我对它的理解来看,它被用作在查询时创建的“临时”索引。因此,如果您多次运行此查询,我将创建该索引一次,然后根据需要多次运行查询 另外,我会尝试创建一个变量来存储求和操作的结果,这样您就可以尽可能避免运行该操作
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
找到解决方案后,这是一个常见问题:运行总计 这是为数不多的几种游标性能更好的情况之一,请参见此处的这一点和更多可用的解决方案(或浏览stackoverflow,有许多类似的情况):
您介意给出查询计划的图片吗?表中有哪些索引?如果您还添加了
CREATE TABLE
语句,这会有所帮助。我尝试为不同的字段添加索引,但没有太大的变化,有趣的是:当删除其中的这一行时,有一个巨大的变化(在小测试中从3分钟到3秒):#POS.CodCtaCorrienteMon>=ctate2.CodCtaCorrienteMon。CodctCorrientMon是一个数字和增量字段,当内部查询中的记录在该字段中的值高于外部查询中记录中的相应字段时,出现这种情况的原因不会影响记录(不求和)。表总共有多少行,更新了多少行(即通过测试#POS.EstaAnulado=0和#POS.essaldoainterior=0
)?我在上一次测试中使用了7000条记录(并不总是相同)这取决于临时表是如何创建的。几乎所有的行都会更新,该筛选器不会包含很多行。你知道,我开始认为没有更好的方法可以做到这一点。它是一个条件和,意味着它不仅是1个和,还有尽可能多的和()由于行位于表中,请参见内部查询中的日期条件和CodctCorrientMon条件,它们取决于外部查询记录上的值。这不是常见的更新,它的工作原理类似于游标中的代码,逐个记录应用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