Bel*_*igh 3 sql-server optimization cte t-sql sql-server-2008-r2
我的查询返回大约 590 行和 8 列。我遇到的问题是从开始到结束查询需要 2 分 30 秒才能完成。这里的一群人教会了我很多如何编写更有效的查询,所以这里是另一个!
我使用的是date
变量而不是变量,datetime
因为我的变量只包含一个日期 - 我还使用Aaron Bertrand - Bad Habits To Kickyyyymmdd
建议的格式存储我的日期。
我可以做些什么来优化此查询并使结果返回得更快?
DECLARE @Startdate date = '20170101',
@Enddate date = '20170131';
WITH fc As
(
Select
Teacher
,Team
,fc
FROM [Helper].[dbo].[fc]
)
,ia As
(
Select
Teacher
,tia
FROM dbo.ia
WHERE [hiredate] >= @Startdate
AND [hiredate] < DATEADD(DAY,1,@Enddate)
)
,inb As
(
Select
Teacher
,tinb
FROM inb
),
ripcord As
(
Select
Teacher
,pit
FROM [homebase].[dbo].[rip]
)
,YRTR As
(
Select
Teacher
,totamt
FROM totamt
WHERE CAST([begindate] As DATE) BETWEEN CAST(DateAdd(yy, -1, @startdate) As Date)
AND CAST(DateAdd(yy, -1, @enddate) As Date)
)
Select
DISTINCT rost.[Teacher] As Teacher
,[Team Name] = fc.team
,[TIA] = ROUND(SUM(ISNULL(ia.tia,0)),0)
,[SUM] = CAST(ROUND(SUM(ISNULL(inb.tinb,0))+SUM(ISNULL(rip.pit,0)),0) As INT)
,[YR] = ROUND(SUM(ISNULL(tr.totamt,0)),0)
,[fc] = ISNULL(fc,0)
,[1st Count] = COALESCE(b.[students],0)
,[2nd Count] = COALESCE(c.[potstudents],0)
FROM dbo.roster rost
LEFT JOIN fc fc
ON rost.Teacher = fc.Teacher
LEFT JOIN ia ia
ON ia.Teacher = rost.Teacher
LEFT JOIN inb inb
ON rost.Teacher = inb.Teacher
LEFT JOIN ripcord rip
ON rost.Teacher = rip.Teacher
LEFT JOIN YRTR tr
ON rost.Teacher = tr.Teacher
OUTER APPLY
( SELECT
DISTINCT Teacher [Teacher]
, COUNT(students) AS students
FROM students
WHERE Teacher = rost.Teacher
AND regdate >= @Startdate
AND regdate < DATEADD(DAY,1,@Enddate)
GROUP BY Teacher
) AS b
OUTER APPLY
(
Select
DISTINCT Teacher Teacher
,COUNT(potstudents) As potstudents
FROM dbo.potstudents
WHERE Teacher = rost.Teacher
AND returndate >= @Startdate
AND returndate < DATEADD(DAY,1,@Enddate)
GROUP BY Teacher
) AS c
GROUP BY rost.[Teacher],fc.TEAM, fc.fc,b.[students],c.[potstudents]
ORDER BY rost.[Teacher] ASC
Run Code Online (Sandbox Code Playgroud)
编辑
(忘记链接,抱歉)在@sabin bio 的请求下 - 这里是查询执行计划的链接
此外,CTE 的查询视图上没有索引。
首先了解查询优化器由您的查询生成的计划。在您的问题中,您说查询返回大约 590 行,但包含的查询计划仅返回 18 行。您是否附上了正确的计划?无论如何,我都会走过它。从右到左阅读:
进行全表扫描roster
并取回 18 行。此结果集用作所有以下嵌套循环连接的外部部分。对于外部结果集中的每一行:
ia
桌子进行全面扫描inb
桌子进行全面扫描ripcord
桌子进行全面扫描YRTR
桌子进行全面扫描students
桌子进行全面扫描potstudents
桌子进行全面扫描在某些时候,行数会增加到 19。GROUP BY
实现为SORT
节点 id 为 4 的 。DISTINCT
实现为Sort (Distinct Sort)
节点 id 为 0 的 。
作为程序员,您无法直接控制查询计划,但您可以做很多事情来影响它。你说查询执行时间太慢了。上述计划对您来说是否有效?如果您可以选择查询优化器的操作,您会怎么做?您正在执行大约 140 次表扫描,只是为了返回 18 行。对于极少数行,这可能没问题,但听起来您在生产中拥有更多数据。
优化查询的一种方法是减少该查询的 IO 要求。在这里,您将进行大量表扫描,因此实施起来应该很简单。创建索引,以便查询优化器可以更有效地获取相关数据。即使您正在引用视图,您也可以在视图使用的表上创建索引以提高性能。举个例子,这里是表访问的谓词fc
:
[Test].[dbo].[roster].[Teacher] as [rost].[Teacher]=[Test].[dbo].[fc].[Teacher]
Run Code Online (Sandbox Code Playgroud)
如果在该Teacher
列上创建索引fc
可能会导致对该表的表访问方法不同,并且可能更有效。或者,您可以将教师表使用的所有列添加为INCLUDE
列。
仅查看您的代码,您应该了解在查询中使用局部变量的影响。创建查询计划时,查询优化器将不知道这些局部变量的值。它将根据硬编码规则进行默认基数估计。对于某些查询,添加OPTION (RECOMPILE)
提示或用硬编码值替换局部变量可以产生更好的查询计划,因为查询优化器在创建计划之前就知道变量的值。
此外,不要随意添加DISTINCT
和添加GROUP BY
到您的查询中。看起来查询优化器优化了其中的一些,但大多数时候,如果您同时拥有这两个查询GROUP BY
并且DISTINCT
在同一个查询中您做错了。目前尚不清楚进行该更改会对这个查询产生多大的性能影响。
归档时间: |
|
查看次数: |
2469 次 |
最近记录: |