Tsql 选择文字而不是列值时,查询速度会减慢
我正在进行一些修改,以改进1000年前编写的旧报表查询的性能。在将其修改为UNION ALL的过程中,我将其中一个列选择值替换为NULL。一旦我这样做,查询的执行时间就从1-2秒变为30秒。我看过这两个版本的实际执行计划,它们看起来完全相同。选择文本NULL可能比读取行值慢,这对我来说毫无意义。我还尝试显式地将NULL强制转换为前一种类型nvarchar,并选择而不是NULL,没有任何区别 查询和模式非常复杂,因此这可能需要一些问答疑难解答。选择NULL时减慢速度的列是底部附近的OtherComments。你可以看到运行速度很快的原始版本,上面有评论。为了让我们跟上进度,我只是想了解为什么更改该列会使其运行缓慢,而不是通过其他方法来改进查询,我知道还有很多方法。以下是一个缩写版本:Tsql 选择文字而不是列值时,查询速度会减慢,tsql,sql-server-2005,optimization,Tsql,Sql Server 2005,Optimization,我正在进行一些修改,以改进1000年前编写的旧报表查询的性能。在将其修改为UNION ALL的过程中,我将其中一个列选择值替换为NULL。一旦我这样做,查询的执行时间就从1-2秒变为30秒。我看过这两个版本的实际执行计划,它们看起来完全相同。选择文本NULL可能比读取行值慢,这对我来说毫无意义。我还尝试显式地将NULL强制转换为前一种类型nvarchar,并选择而不是NULL,没有任何区别 查询和模式非常复杂,因此这可能需要一些问答疑难解答。选择NULL时减慢速度的列是底部附近的OtherCom
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)
我比较了查询计划的实际XML,发现快速存储过程的内存分配比慢速存储过程高。这是在MS论坛中向我解释的,可能是因为当fml.OtherComment出现在查询中时,它需要更大的行大小。我不知道一个解决方案,如果你遇到这样一个写得很好的查询,但是在我的例子中,这个spoc在循环选择最终记录时效率太低,以至于我从头重写了它,现在它运行得很快。这可能是个愚蠢的问题,但它本身运行慢吗?或者仅当您尝试将所有查询与另一个查询合并时?如果没有输出列,它如何运行?为什么列别名后面的逗号是其他注释?这不是From之前Select子句中的最后一个输出吗?谢谢@CharlesBretana。它自己运行;我只是指上面的问题。在粘贴其他评论后,我将其从中间移到了底部,以便于你们查找。忘了去掉逗号,但我确实验证了移动逗号后它仍然运行缓慢。有趣的是,完全删除OtherComments列也是一个缓慢的好主意&似乎我把这个问题命名错了。这对你有什么意义吗?