0

1000年前に作成された古いレポートクエリのパフォーマンスを向上させるために、いくつかの変更を加えています。UNION ALLを実行するように変更する過程で、列選択値の1つをNULLに置き換えました。これを行うとすぐに、クエリは実行に1〜2秒かかるものから実行するのに30秒かかるものに変わります。2つのバージョンの実際の実行プランを確認しましたが、同じように見えます。リテラルNULLを選択すると、行の値を読み取るよりも遅くなる可能性があることは私には意味がありません。また、以前のタイプ(nvarchar)に明示的にNULLをキャストし、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)
4

1 に答える 1

1

クエリプランの実際のXMLを比較したところ、メモリの付与は低速のsprocよりも高速のsprocの方が高いことがわかりました。これはMSフォーラムで私に説明されました。おそらく、fml.OtherCommentがクエリに含まれていると、より大きな行サイズが予想されるためです。よく書かれたクエリでこれに遭遇した場合の解決策はわかりませんが、私の場合、このスポックは非常に非効率的であったため(ラウンドアラウンドで最終レコードを選択)、ゼロから書き直しました。今速く走っています。

于 2012-12-14T18:34:09.083 に答える