เหตุใดแบบสอบถามจึงทำงานช้าลงในกระบวนงานที่เก็บไว้กว่าในหน้าต่างแบบสอบถาม


14

ฉันมีแบบสอบถามที่ซับซ้อนซึ่งทำงานใน 2 วินาทีในหน้าต่างแบบสอบถาม แต่ประมาณ 5 นาทีเป็นกระบวนงานที่เก็บไว้ เหตุใดจึงใช้เวลานานกว่าจึงจะเรียกใช้เป็นกระบวนงานที่เก็บไว้ได้

นี่คือสิ่งที่แบบสอบถามของฉันดูเหมือน

ใช้ชุดระเบียนเฉพาะ (ระบุโดย@idและ@createdDate) และกรอบเวลาที่เฉพาะเจาะจง (1 ปีเริ่มต้นจาก@startDate) และส่งกลับรายการสรุปของตัวอักษรที่ส่งและการชำระเงินโดยประมาณที่ได้รับเป็นผลมาจากตัวอักษรเหล่านั้น

CREATE PROCEDURE MyStoredProcedure
    @id int,
    @createdDate varchar(20),
    @startDate varchar(20)

 AS
SET NOCOUNT ON

    -- Get the number of records * .7
    -- Only want to return records containing letters that were sent on 70% or more of the records
    DECLARE @limit int
    SET @limit = IsNull((SELECT Count(*) FROM RecordsTable WITH (NOLOCK) WHERE ForeignKeyId = @id AND Created = @createdDate), 0) * .07

    SELECT DateSent as [Date] 
        , LetterCode as [Letter Code]
        , Count(*) as [Letters Sent]
        , SUM(CASE WHEN IsNull(P.DatePaid, '1/1/1753') BETWEEN DateSent AND DateAdd(day, 30, DateSent) THEN IsNull(P.TotalPaid, 0) ELSE 0 END) as [Amount Paid]
    INTO #tmpTable
    FROM (

        -- Letters Table. Filter for specific letters
        SELECT DateAdd(day, datediff(day, 0, LR.DateProcessed), 0) as [DateSent] -- Drop time from datetime
            , LR.LetterCode -- Letter Id
            , M.RecordId -- Record Id
        FROM LetterRequest as LR WITH (NOLOCK)
        INNER JOIN RecordsTable as M WITH (NOLOCK) ON LR.RecordId = M.RecordId
        WHERE ForeignKeyId = @id AND Received = @createdDate
            AND LR.Deleted = 0 AND IsNull(LR.ErrorDescription, '') = ''
            AND LR.DateProcessed BETWEEN @startDate AND DateAdd(year, 1, @startDate)
            AND LR.LetterCode IN ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o')
    ) as T
    LEFT OUTER JOIN (

        -- Payment Table. Payments that bounce are entered as a negative payment and are accounted for
        SELECT PH.RecordId, PH.DatePaid, PH.TotalPaid
        FROM PaymentHistory as PH WITH (NOLOCK)
            INNER JOIN RecordsTable as M WITH (NOLOCK) ON PH.RecordId = M.RecordId
            LEFT OUTER JOIN PaymentHistory as PR WITH (NOLOCK) ON PR.ReverseOfUId = PH.UID
        WHERE PH.SomeString LIKE 'P_' 
            AND PR.UID is NULL 
            AND PH.DatePaid BETWEEN @startDate AND DateAdd(day, 30, DateAdd(year, 1, @startDate))
            AND M.ForeignKeyId = @id AND M.Created = @createdDate
    ) as P ON T.RecordId = P.RecordId

    GROUP BY DateSent, LetterCode
    --HAVING Count(*) > @limit
    ORDER BY DateSent, LetterCode

    SELECT *
    FROM #tmpTable
    WHERE [Letters Sent] > @limit

    DROP TABLE #tmpTable

ผลลัพธ์ที่ได้จะเป็นดังนี้:

วันที่ตัวอักษรรหัสตัวอักษรส่งจำนวนเงินที่จ่าย
1/1/2012 1245 12345.67
1/1/2012 b 2301 1234.56
1/1/2012 ค 1312 7894.45
1/1/2012 ที่ 1455 2345.65
1/1/2012 ค 3611 3213.21

ฉันมีปัญหาในการพิจารณาว่าการชะลอตัวอยู่ที่ใดเพราะทุกอย่างทำงานได้อย่างรวดเร็วมากในเครื่องมือแก้ไขแบบสอบถาม เฉพาะเมื่อฉันย้ายแบบสอบถามไปยังกระบวนงานที่เก็บไว้ซึ่งเริ่มใช้เวลานานมากในการเรียกใช้

ฉันแน่ใจว่ามีบางอย่างเกี่ยวกับแผนการสร้างการดำเนินการสืบค้น แต่ฉันไม่รู้ SQL เกี่ยวกับการระบุสิ่งที่อาจทำให้เกิดปัญหา

มันควรจะสังเกตว่าตารางทั้งหมดที่ใช้ในการสืบค้นมีล้านเรคคอร์ด

ใครสามารถอธิบายให้ฉันฟังได้ว่าเหตุใดการเรียกใช้โพรซีเดอร์ที่เก็บนานกว่าในเอดิเตอร์เคียวรีจึงใช้เวลานานกว่านี้และช่วยฉันระบุว่าส่วนใดของเคียวรีของฉันอาจทำให้เกิดปัญหาประสิทธิภาพเมื่อรันเป็นโพรซีเดอร์ที่จัดเก็บ


@MartinSmith ขอบคุณ ฉันต้องการหลีกเลี่ยงRECOMPILEคำใบ้เนื่องจากฉันไม่ต้องการคอมไพล์แบบสอบถามซ้ำทุกครั้งที่เรียกใช้และบทความที่คุณลิงก์ระบุว่าการคัดลอกพารามิเตอร์ไปยังตัวแปรโลคอลนั้นเทียบเท่ากับการใช้OPTIMIZE FOR UNKNOWNซึ่งดูเหมือนว่าจะมีให้เฉพาะใน 2551 และต่อมา ฉันคิดว่าตอนนี้ฉันจะติดกับการคัดลอกพารามิเตอร์ไปยังตัวแปรท้องถิ่นซึ่งทำให้เวลาดำเนินการแบบสอบถามของฉันลดลงเหลือ 1-2 วินาที
Rachel

คำตอบ:


5

ขณะที่มาร์ตินชี้ให้เห็นในความคิดเห็นปัญหาคือว่าแบบสอบถามใช้แผนการแคชซึ่งเป็นที่ไม่เหมาะสมสำหรับพารามิเตอร์ที่กำหนด

ลิงค์ที่เขาระบุในSlow ในแอปพลิเคชัน Fast in SSMS หรือไม่ การทำความเข้าใจเกี่ยวกับผลการปฏิบัติงานปริศนาให้ข้อมูลที่เป็นประโยชน์มากมายซึ่งนำฉันไปสู่การแก้ปัญหาบางอย่าง

โซลูชันที่ฉันใช้อยู่ในปัจจุบันคือการคัดลอกพารามิเตอร์ไปยังตัวแปรโลคัลในโพรซีเดอร์ซึ่งฉันคิดว่าทำให้ SQL ประเมินแผนการดำเนินการของแบบสอบถามใหม่ทุกครั้งที่เรียกใช้ดังนั้นจึงเลือกแผนการดำเนินการที่ดีที่สุดสำหรับพารามิเตอร์ที่กำหนดแทนที่จะใช้ แผนแคชที่ไม่เหมาะสมสำหรับแบบสอบถาม

โซลูชันอื่น ๆ ที่อาจใช้งานได้กำลังใช้คำแนะนำOPTIMIZE FORหรือRECOMPILEแบบสอบถาม


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.