运行时sql过多。如何提高?

时间:2011-11-21 18:18:00

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

我在Sql Server MSSM中执行以下SQL查询,运行时间超过5秒。由内连接连接的表,只有几万条记录。为什么需要这么长时间?。

查询的成本较高: - 聚集索引扫描[MyDB]。[dbo]。[LinPresup]。[PK_LinPresup_Linea_IdPresupuesto_IdPedido] 78%。 - 聚集索引寻求[MyDB]。[dbo]。[Pedidos]。[PK_Pedidos_IdPedido] 19%

谢谢。

Declare @FILTROPAG bigint 
set @FILTROPAG = 1

Declare @FECHATRABAJO DATETIME
set @FECHATRABAJO = getDate()

Select * from(
SELECT distinct Linpresup.IdCliente, Linpresup.IdPedido, Linpresup.FSE, Linpresup.IdArticulo, 
        Linpresup.Des, ((Linpresup.can*linpresup.mca)-(linpresup.srv*linpresup.mca)) as Pendiente,
        Linpresup.IdAlmacen, linpresup.IdPista, articulos.Tip, linpresup.Linea,
        ROW_NUMBER() OVER(ORDER BY CONVERT(Char(19), Linpresup.FSE, 120) +
             Linpresup.IdPedido + CONVERT(char(2), linpresup.Linea) DESC) as NUM_REG
FROM Linpresup INNER JOIN Pedidos on LinPresup.IdPedido = Pedidos.IdPedido
               INNER JOIN Articulos ON Linpresup.IdArticulo = Articulos.IdArticulo
where  pedidos.Cerrado = 'false' and linpresup.IdPedido <> '' and linpresup.can <> linpresup.srv
        and Linpresup.FecAnulacion is null and Linpresup.Fse <= @FECHATRABAJO 
        and LinPresup.IdCliente not in (Select IdCliente from Clientes where Ctd = '4')
        and Substring(LinPresup.IdPedido, 5, 2) LIKE '11' or Substring(LinPresup.IdPedido, 5, 2) LIKE '10' 
) as TablaTemp
WHERE NUM_REG BETWEEN @FILTROPAG AND 1500   
order by NUM_REG ASC

----------

这是应用了更改的新查询:

CHECKPOINT;
go
dbcc freeproccache
go
dbcc dropcleanbuffers
go

Declare @FILTROPAG bigint
set @FILTROPAG = 1
Declare @FECHATRABAJO DATETIME
set @FECHATRABAJO = getDate()

SELECT  Linpresup.IdCliente, Linpresup.IdPedido, Linpresup.FSE, Linpresup.IdArticulo, 
        Linpresup.Des, Linpresup.can, linpresup.mca, linpresup.srv,
        Linpresup.IdAlmacen, linpresup.IdPista, linpresup.Linea
into #TEMPREP
FROM Linpresup
where Linpresup.FecAnulacion is null and linpresup.IdPedido <> ''
    and (linpresup.can <> linpresup.srv) and Linpresup.Fse <= @FECHATRABAJO 

Select *, ((can*mca)-(srv*mca)) as Pendiente
From(
    Select tablaTemp.*, ROW_NUMBER() OVER(ORDER BY FSECONVERT + IDPedido + LINCONVERT DESC) as NUM_REG, Articulos.Tip
    From(
            Select #TEMPREP.*, 
                    Substring(#TEMPREP.IdPedido, 5, 2) as NewCol,
                    CONVERT(Char(19), #TEMPREP.FSE, 120) as FSECONVERT, CONVERT(char(2), #TEMPREP.Linea) as LINCONVERT
            from #TEMPREP INNER JOIN Pedidos on #TEMPREP.IdPedido = Pedidos.IdPedido
            where Pedidos.Cerrado = 'false' 
                   and #TEMPREP.IdCliente not in (Select IdCliente from Clientes where Ctd = '4')) as tablaTemp
    inner join Articulos on tablaTemp.IDArticulo = Articulos.IdArticulo
    where (NewCol = '10' or NewCol = '11')) as TablaTemp2
where NUM_REG BETWEEN @FILTROPAG AND 1500   
order by NUM_REG ASC

DROP TABLE #TEMPREP

总执行时间从5336减少到3978,服务器响应的等待时间从5309减少到2730.这是事情。

3 个答案:

答案 0 :(得分:5)

您的查询的这部分不是SARGable,将执行索引扫描而不是搜索

and Substring(LinPresup.IdPedido, 5, 2) LIKE '11' 
or Substring(LinPresup.IdPedido, 5, 2) LIKE '10'
一般来说,

列名称周围的函数会导致索引扫描

答案 1 :(得分:2)

没有看到你的执行计划,很难说。那说以下是我的潜在危险点:

and Substring(LinPresup.IdPedido, 5, 2) LIKE '11' 
or Substring(LinPresup.IdPedido, 5, 2) LIKE '10' 

我怀疑在这里使用substring函数会导致不使用任何可能有用的索引。另外,你为什么在这里使用LIKE?我猜它可能会被优化掉,但似乎标准的=会起作用......

答案 2 :(得分:1)

我无法想象为什么你会认为这样的查询会很快运行。你是:

  • 对记录集进行两次排序(对于您使用的位置进行一次排序) 连接和功能),
  • 你的where子句有函数(不是sargable)和OR 这几乎总是很慢,
  • 你没有在不存在的地方使用可能会更快。
  • 你有数学计算

您还没有提到您的索引(可能有用也可能没有用)或执行计划显示的影响性能最高的点。

我可能会开始将不同的数据拉到CTE或临时表(您可以索引临时表)而不进行计算(以确保何时进行计算,以后它与最小的数据集相对)。然后我会将子串转换为LinPresup.IdPedido LIKE'1 [0-1]%'。我将woudl转换为not in to not exists。我会把数学放在外部查询中,这样才能在最小的数据集上完成。