Domanda

Ho una domanda complessa che viene eseguito in 2 secondi nella finestra di query, ma circa 5 minuti come una stored procedure. Perché ci mette così tanto più tempo per eseguire una stored procedure?

Ecco quello che il mio aspetto di query piace.

Ci vuole un insieme specifico di record (identificato da @id e @createdDate), e un arco di tempo determinato (1 anno a partire dalla @startDate) e restituisce un elenco riepilogativo delle lettere inviate e acconti ricevuti a seguito di quelle lettere.

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

Gli sguardi risultato finale come questo:

Date        Letter Code     Letters Sent    Amount Paid
1/1/2012    a               1245            12345.67
1/1/2012    b               2301            1234.56
1/1/2012    c               1312            7894.45
1/1/2012    a               1455            2345.65
1/1/2012    c               3611            3213.21

Ho problemi a capire dove il rallentamento è, perché tutto fili estremamente veloce nell'editor di query. E 'solo quando mi muovo la query per una stored procedure che si inizia a prendere così tanto tempo per l'esecuzione.

Sono sicuro che abbia qualcosa a che fare con il piano di esecuzione di query sempre generato, ma io non ne so abbastanza su SQL per individuare quello che potrebbe essere la causa del problema.

Si dovrebbe probabilmente essere notato che tutte le tabelle utilizzate nella query hanno milioni di record.

Can qualcuno mi spieghi perché questo sta prendendo molto più tempo per essere eseguito come stored procedure che in l'editor di query, e mi aiuta a identificare quale parte della mia domanda potrebbe essere la causa dei problemi di prestazioni quando viene eseguito come una stored procedure?

È stato utile?

Soluzione

Come Martin ha sottolineato nei commenti , il problema è che la query utilizza un piano memorizzato nella cache che è inappropriato per i parametri indicati.

Il collegamento ha fornito su lento nella Domanda, veloce in SSMS? La comprensione delle prestazioni Misteri fornito un sacco di informazioni utili, che mi ha portato ad alcune soluzioni.

La soluzione Attualmente sto usando è quello di copiare i parametri alle variabili locali nella procedura, che credo rende SQL rivalutare il piano di esecuzione per la query in qualsiasi momento è gestito, in modo che raccoglie il miglior piano di esecuzione per i parametri indicati invece di utilizzare una cache piano inadeguato per la query.

Altre soluzioni che potrebbero funzionare utilizzano i OPTIMIZE FOR o RECOMPILE hint per la query.

Altri suggerimenti

Da una domanda simile su StackOverflow ( con più risposte ), controllare la stored procedure.

  • BAD : SET ANSI_NULLS OFF (5 minuti, 6M spool desiderosi)
  • BUONA : SET ANSI_NULLS ON (0,5 secondi)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a dba.stackexchange
scroll top