我有一个大约需要3分钟才能运行的查询。查询正用于报告,我希望它更有效。我认为瓶颈是内部连接,我可能错了,只是想知道你们是否有任何解决方案。
SELECT DISTINCT
SUBSTRING(T1.DateTime, 1, 4) AS Year,
SUBSTRING(T1.DateTime, 5, 2) AS Month,
SUBSTRING(T1.DateTime, 7, 2) AS Day,
T1.PipeNr, T1.SalesOrder, T1.JobNr, SIST.DefectCode AS DefectRef,
DEFCODES.DefectCode, DEFCODES.DefectDesc, SIST.ODYes, SIST.LocationWrap,
T1.OWS0601, T1.OWS0602, T1.OWS0603, T1.CrossWeld
FROM PIPEDB.dbo.SIST INNER JOIN PIPEDB.dbo.MPIPEID T1 ON PIPEDB.dbo.SIST.PipeNr = T1.PipeNr INNER JOIN
PIPEDB.dbo.DEFCODES ON PIPEDB.dbo.SIST.DefectCode = PIPEDB.dbo.DEFCODES.DefectRef
WHERE PIPEDB.dbo.SIST.DefectCode
IN (
SELECT Top (10) PIPEDB.dbo.SIST.DefectCode
FROM PIPEDB.dbo.SIST INNER JOIN PIPEDB.dbo.MPIPEID T2 ON PIPEDB.dbo.SIST.PipeNr = T2.PipeNr INNER JOIN
PIPEDB.dbo.DEFCODES ON PIPEDB.dbo.SIST.DefectCode = PIPEDB.dbo.DEFCODES.DefectRef
WHERE SUBSTRING(T2.DateTime, 1, 4) = SUBSTRING(T1.DateTime, 1, 4) AND SUBSTRING(T2.DateTime, 5, 2) = SUBSTRING(T1.DateTime, 5, 2) AND
SUBSTRING(T2.DateTime, 7, 2) = SUBSTRING(T1.DateTime, 7, 2)
GROUP BY PIPEDB.dbo.SIST.DefectCode
ORDER BY COUNT(PIPEDB.dbo.SIST.PipeNr) DESC)
AND (PIPEDB.dbo.DEFCODES.DefectDesc IN ("Cut To Remove Defect")) AND
((CASE WHEN T1.CrossWeld = 1 THEN 1 WHEN T1.CrossWeld = 0 THEN 2 END) = @Crossweld OR @Crossweld = 0)
答案 0 :(得分:1)
问题在于您将IN子查询作为相关子查询,这反过来导致性能问题。对于主子句(或外部)中的每一行,IN子查询正在执行,因此需要时间。内部子查询的每次执行都可能基于表的大小而且很可能在子查询中使用嵌套循环连接。此外,如果来自外部查询的行数非常高,则昂贵的 IN子查询正在执行大量时间,从而降低了查询的性能。我建议再次查看逻辑确保它提供正确的数据。
见下文。我试图重现你的问题。这个查询的成本是2045,这是非常巨大的,当然它需要时间。它的CPU占用时间约为1000万秒,经过了48秒。
那不是它。我预计只有10个productid(我相信你们期望只有10个缺陷代码)但我可以看到很多其他的产品只是因为相关的子查询。
set statistics io,time on
go
select * from Sales.SalesOrderHeader soh inner join sales.SalesOrderDetail sod
on sod.SalesOrderID=soh.SalesOrderID
where sod.ProductID in (
select top 10 ProductID
from Sales.SalesOrderHeader soh1 inner join sales.SalesOrderDetail sod
on sod.SalesOrderID=soh1.SalesOrderID
where datepart(yy,soh.OrderDate) = DATEPART(yy,soh1.OrderDate)
and datepart(mm,soh.OrderDate) = DATEPART(mm,soh1.OrderDate)
)
order by sod.ProductID
答案 1 :(得分:0)
按照以下说明查看SQL Server推荐的任何索引:
将查询放在Microsoft SQL Server Management Studio的查询窗口中。
而不是运行它,按CTRL + L(或从菜单中选择查询>显示估计执行计划)。
然后在执行计划选项卡中,您可能看到一些绿色文本并以“缺少索引(影响xx.xxxx%)...”开头,如果您这样做,请右键单击该文本并选择缺失索引详细信息。这将打开一个带有建议索引定义的新窗口(您必须提供索引名称)。例如:
/*
Missing Index Details from SQLQuery3.sql - (local).master (sa (55))
The Query Processor estimates that implementing the following index could improve the query cost by 99.3783%.
*/
/*
USE [DatabaseName]
GO
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Table] ([Column1])
INCLUDE ([Column2],[Column2])
GO
*/
替换'&lt;缺少索引的名称,sysname,&gt;'使用有效的索引名称并创建索引。
可以重复这些步骤,直到没有建议索引为止。
除此之外,在where子句中使用SubString可能是个问题。
此:
WHERE SUBSTRING(T2.DateTime, 1, 4) = SUBSTRING(T1.DateTime, 1, 4) AND SUBSTRING(T2.DateTime, 5, 2) = SUBSTRING(T1.DateTime, 5, 2) AND SUBSTRING(T2.DateTime, 7, 2) = SUBSTRING(T1.DateTime, 7, 2)
肯定是这样的:
WHERE SUBSTRING(T2.DateTime, 1, 8) = SUBSTRING(T1.DateTime, 1, 8)
甚至更好:
WHERE LEFT(T2.DateTime, 8) = Left(T1.DateTime, 1, 8)
甚至更好(可以允许更多的索引使用):
WHERE T2 LIKE Left(T1.DateTime, 1, 8) + '%'
如果这些日期字符串只有8个字符长,则可能是这样:
WHERE T2.DateTime = T1.DateTime
如果查询仍然没有在所需的时间内运行,那么重新构建数据将是一个很好的举措,这样在where子句中不需要SUBSTRING或LEFT ...即在它自己的列中打破日期。
答案 2 :(得分:0)
你必须拥有DISTINCT
吗?我宁愿使用GROUP BY
来返回一组独特的记录,例如
SELECT DISTINCT X
FROM Y
更改为
SELECT X
FROM Y
GROUP BY X
此外,我更倾向于使用EXISTS
在IN
条款中使用WHERE
,因为它们通常会稍微快一点。
我很想将以下部分放在CTE
中,并使用分区函数RANK() OVER
代替TOP(10)
/ ORDER BY
设置
IN (
SELECT Top (10) PIPEDB.dbo.SIST.DefectCode
FROM PIPEDB.dbo.SIST INNER JOIN PIPEDB.dbo.MPIPEID T2 ON PIPEDB.dbo.SIST.PipeNr = T2.PipeNr INNER JOIN
PIPEDB.dbo.DEFCODES ON PIPEDB.dbo.SIST.DefectCode = PIPEDB.dbo.DEFCODES.DefectRef
WHERE SUBSTRING(T2.DateTime, 1, 4) = SUBSTRING(T1.DateTime, 1, 4) AND SUBSTRING(T2.DateTime, 5, 2) = SUBSTRING(T1.DateTime, 5, 2) AND
SUBSTRING(T2.DateTime, 7, 2) = SUBSTRING(T1.DateTime, 7, 2)
GROUP BY PIPEDB.dbo.SIST.DefectCode
ORDER BY COUNT(PIPEDB.dbo.SIST.PipeNr) DESC)