我正在进行一些修改,以提高1000年前编写的旧报告查询的性能。在修改它以进行UNION ALL的过程中,我用NULL替换了其中一个列选择值。一旦我这样做,查询就会从执行1-2秒变为执行30秒。我看了两个版本的实际执行计划,它们看起来完全相同。对我来说,选择文字NULL可能比读取行值要慢。我也尝试过显式地将NULL转换为前一种类型(nvarchar),并选择''而不是NULL而没有区别。
查询和架构非常复杂,因此可能需要进行一些Q& A故障排除。选择NULL时将列减慢的列是底部附近的“OtherComments”。您可以看到原始版本,运行速度快,在其上方评论。为了让我们保持正轨,我只是想了解为什么更改该列会使其运行缓慢,而不是其他改进查询的方法(我知道有很多)。这是一个缩写版本:
SELECT @Date Parameter,
fml.FirstName + ' ' + fml.LastName ParentName,
(
SELECT TOP 1 p.PhoneNum
FROM tbl_Phone p, tbl_PhoneTypes pt, tbl_FamilyPhone fp
WHERE p.fk_PhoneTypeID = pt.pk_PhoneTypeID
AND p.pk_PhoneID = fp.fk_PhoneID
AND fp.fk_FamilyID = fml.pk_familyID
AND pt.Type = 'home'
AND fp.IsDeleted = 0
ORDER BY fp.CreatedDate DESC
) PhoneNo,
fml.Comments FamilyComments,
std.FirstName + ' ' + std.LastName StudentName,
(
SELECT
...
) ClassDescription,
(
SELECT
...
) TestClassDescription,
CASE
WHEN (sce.pk_StudentEnrollmentID IS NOT NULL) THEN
(
SELECT emp.FirstName + ' ' + emp.LastName
...
)
WHEN (st.pk_StudentTestID IS NOT NULL) THEN
(
SELECT emp.FirstName + ' ' + emp.LastName
...
)
ELSE
NULL
END InstructorName,
CASE
WHEN (st.pk_StudentTestID IS NOT NULL) THEN
(
SELECT emp.FirstName + ' ' + emp.LastName
...
)
ELSE
NULL
END TestInstructorName,
st.TestDate TestDate,
tr.Description TestResult,
CASE
WHEN (
SELECT COUNT(ClassDate) --Select absent attendances from yesterday
...
) >= 1
THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END
MissedYesterdaysClass,
CASE
WHEN (datediff(day, CONVERT(varchar(11),fml.InquiryDate,102), @Date) =3 and
(fml.CurrentMembershipDate IS NULL) AND ((fml.WebCreated = 0) OR (fml.WebCreated = NULL)) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0)) THEN
CAST(1 AS BIT)
WHEN (((fml.InquiryDate + 3) = @Date) AND (std.pk_StudentID IS NULL)) THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END InquiredButDidnotSchedule,
CASE
WHEN --(((st.TestDate + 2) = @Date) AND
(datediff(day, CONVERT(varchar(11),st.testdate,102), @Date) =2 and
(tr.Description = 'Not Enrolled') AND
(st.IsDeleted = 0) AND
(st.IsCancelled = 0)) THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END AttendedButHavenotEnrolled,
CASE
WHEN --(((st.TestDate + 1) = @Date) AND
(datediff(day, CONVERT(varchar(11),st.testdate,102), @Date) =1 and
(tr.Description = 'No Show') AND
(st.IsDeleted = 0) AND
(st.IsCancelled = 0)) THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END PeopleNoShowed,
CASE
WHEN ---(((st.TestDate - 1) = @Date) AND
(datediff(day, CONVERT(varchar(11),st.testdate,102), @Date) =-1 and
(tr.Description = 'Scheduled') AND
(st.IsDeleted = 0) AND
(st.IsCancelled = 0)) THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END PeopleHaveTest,
CAST(0 AS BIT) ShowOtherComments,
CASE
WHEN
((
SELECT count(*)
...
) > 0) AND
((
SELECT EventDate
...
)
BETWEEN
(
DateAdd(day, DateDiff(day, 0, @Date), 0)
)
AND
(
(DateAdd(day, DateDiff(day, 0, @Date), 0) + 6)
)
)
AND
datename(weekday, @Date) = 'Wednesday'
AND
bb.IsDeleted = 0
AND
bb.IsCancelled = 0 THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END ShowUpcomingBookingss,
(
SELECT EventDate
...
) BookingDate,
bb.ChildTurningAge Age,
std.pk_StudentID StudentID,
fml.pk_familyID FamilyID,
CASE
WHEN (datediff(day, CONVERT(varchar(11),fml.InquiryDate,102), @Date) =1 and
(fml.MembershipDate IS NULL) AND (fml.WebCreated = 1) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0) AND
((
SELECT count(*)
...
) <= 0)) THEN
CAST(1 AS BIT)
WHEN (((fml.InquiryDate + 1) = @Date) AND (std.pk_StudentID IS NULL)) THEN
CAST(1 AS BIT)
ELSE
CAST(0 AS BIT)
END InquiredButDidnotScheduleOnline,
-- Commenting this out and replacing with NULL slows it down from 2 sec to 30 sec
-- fml.OtherComment OtherComments,
NULL OtherComments,
FROM tbl_Family fml
LEFT OUTER JOIN tbl_Student std on fml.pk_FamilyID = std.fk_FamilyID
LEFT OUTER JOIN tbl_StudentEnrollment sce on std.pk_StudentID = sce.fk_StudentID
LEFT OUTER JOIN tbl_StudentTest st on std.pk_StudentID = st.fk_StudentID
LEFT OUTER JOIN tbl_Booking bb on std.pk_StudentID = bb.fk_StudentID
LEFT JOIN tbl_TestResult tr on st.fk_TestResultID = tr.pk_TestResultID
WHERE fml.fk_FacilityID = @FacilityID
AND (fml.IsDeleted = 0 OR fml.IsDeleted IS NULL)
AND (std.IsDeleted = 0 OR std.IsDeleted IS NULL)
答案 0 :(得分:1)
我比较了查询计划的实际XML,并注意到快速sproc的内存授权高于慢sproc。这在MS论坛中向我解释,可能是因为当fml.OtherComment在查询中时,它期望更大的行大小。我不知道一个解决方案,如果你用一个写得很好的查询遇到这个,但在我的情况下,这个spoc是如此低效(选择最后的记录在一个方向),我从头开始重写它,它的现在跑得快。