Tsql 选择文字而不是列值时,查询速度会减慢

Tsql 选择文字而不是列值时,查询速度会减慢,tsql,sql-server-2005,optimization,Tsql,Sql Server 2005,Optimization,我正在进行一些修改,以改进1000年前编写的旧报表查询的性能。在将其修改为UNION ALL的过程中,我将其中一个列选择值替换为NULL。一旦我这样做,查询的执行时间就从1-2秒变为30秒。我看过这两个版本的实际执行计划,它们看起来完全相同。选择文本NULL可能比读取行值慢,这对我来说毫无意义。我还尝试显式地将NULL强制转换为前一种类型nvarchar,并选择而不是NULL,没有任何区别 查询和模式非常复杂,因此这可能需要一些问答疑难解答。选择NULL时减慢速度的列是底部附近的OtherCom

我正在进行一些修改,以改进1000年前编写的旧报表查询的性能。在将其修改为UNION ALL的过程中,我将其中一个列选择值替换为NULL。一旦我这样做,查询的执行时间就从1-2秒变为30秒。我看过这两个版本的实际执行计划,它们看起来完全相同。选择文本NULL可能比读取行值慢,这对我来说毫无意义。我还尝试显式地将NULL强制转换为前一种类型nvarchar,并选择而不是NULL,没有任何区别

查询和模式非常复杂,因此这可能需要一些问答疑难解答。选择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)

我比较了查询计划的实际XML,发现快速存储过程的内存分配比慢速存储过程高。这是在MS论坛中向我解释的,可能是因为当fml.OtherComment出现在查询中时,它需要更大的行大小。我不知道一个解决方案,如果你遇到这样一个写得很好的查询,但是在我的例子中,这个spoc在循环选择最终记录时效率太低,以至于我从头重写了它,现在它运行得很快。

这可能是个愚蠢的问题,但它本身运行慢吗?或者仅当您尝试将所有查询与另一个查询合并时?如果没有输出列,它如何运行?为什么列别名后面的逗号是其他注释?这不是From之前Select子句中的最后一个输出吗?谢谢@CharlesBretana。它自己运行;我只是指上面的问题。在粘贴其他评论后,我将其从中间移到了底部,以便于你们查找。忘了去掉逗号,但我确实验证了移动逗号后它仍然运行缓慢。有趣的是,完全删除OtherComments列也是一个缓慢的好主意&似乎我把这个问题命名错了。这对你有什么意义吗?