Saklı Yordamda bir sorgu neden Sorgu penceresinde olduğundan daha yavaş çalışıyor?


14

Sorgu penceresinde, ancak bir saklı yordam olarak yaklaşık 5 dakika içinde çalışan karmaşık bir sorgu var. Saklı yordam olarak çalışmak neden bu kadar uzun sürüyor?

İşte benim sorgu böyle görünüyor.

Belirli bir kayıt kümesini ( @idve ile tanımlanır @createdDate) ve belirli bir zaman çerçevesini (1 yıl başlayarak @startDate) alır ve bu mektupların sonucu olarak gönderilen ve alınan tahmini ödemelerin özet listesini döndürür.

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

Sonuç şöyle görünür:

Tarih Mektup Kod Gönderilen Ücretler Ödenen Tutar
1/1/2012 1245 12345,67
1/1/2012 b 2301 1234.56
1/1/2012 c 1312 7894,45
1/1/2012 1455 2345,65
1/1/2012 c 3611 3213.21

Her şey sorgu düzenleyicide son derece hızlı çalıştığından, yavaşlamanın nerede olduğunu bulmakta sorun yaşıyorum. Sadece sorguyu çalıştırmak için çok uzun sürmeye başlayan bir saklı yordam taşıdığınızda.

Sorgu yürütme planı oluşturulan ile ilgili bir şey var eminim, ama ne soruna neden olabilir belirlemek için SQL hakkında yeterli bilmiyorum.

Muhtemelen sorguda kullanılan tüm tabloların milyonlarca kaydı olduğu unutulmamalıdır.

Birisi bana bunun neden saklı yordam olarak sorgusu düzenleyiciden daha uzun sürdüğünü açıklayabilir ve saklı yordam olarak çalıştırıldığında sorgumun hangi kısmının performans sorunlarına neden olabileceğini belirlememe yardımcı olabilir mi?


@MartinSmith Teşekkürler. RECOMPILEGerçekten her çalıştığında sorguyu yeniden derlemek istemiyorum çünkü ipucu önlemek için tercih ediyorum ve bağlantı makalesi, yerel bir değişkene parametreleri kopyalamak OPTIMIZE FOR UNKNOWN, yalnızca kullanılabilir gibi görünüyor kullanarak , eşdeğer olduğunu belirtti 2008 ve sonrası. Şimdilik, sorgu yürütme süremi 1-2 saniyeye düşüren yerel bir değişkene parametreleri kopyalayarak yapışacağımı düşünüyorum.
Rachel

Yanıtlar:


5

Martin'in açıklamalarda belirttiği gibi , sorun, sorgunun verilen parametreler için uygun olmayan önbelleğe alınmış bir plan kullanmasıdır.

O sağlanan bağlantı Hızlı SSMS Uygulamasında Yavaş? Performans Gizemlerini Anlamak , beni bazı çözümlere götüren birçok yararlı bilgi sağladı.

Şu anda kullandığım çözüm, SQL çalıştırıldığında sorgu yürütme planını yeniden değerlendirmek yapar, bu nedenle kullanmak yerine verilen parametreler için en iyi yürütme planı alır yapar yordamda parametreleri yerel değişkenlere kopyalamak için sorgu için uygun olmayan bir önbellek planı.

Çalışabilecek diğer çözümler OPTIMIZE FORveya RECOMPILEsorgu ipuçlarını kullanmaktır.


0

Stackoverflow'daki benzer bir sorudan ( daha fazla yanıtla ), saklı yordamınızı kontrol edin.

  • KÖTÜ :SET ANSI_NULLS OFF (5 dakika, 6M istekli makara)
  • İYİ :SET ANSI_NULLS ON (0.5 saniye)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.