16

SQL Server 2008 R2 のストアド プロシージャに非常に奇妙な問題があります。ときどき、月に 1 回程度、非常に遅くなる手順が 1 つあります。数ミリ秒ではなく、実行に約 6 秒かかります。しかし、何も変更せずに単純に再コンパイルすると、再び高速に実行されます。すべてのストアド プロシージャで発生するわけではなく、1 つだけです (サーバー上に数百あります)。

私の推測では、spがコンパイルされ、キャッシュされ、このキャッシュが呼び出されるたびに再利用され、このキャッシュされたバージョンが何らかの理由で破損します。

SQL Server または IIS のどの構成がストアド プロシージャ キャッシュに影響を与える可能性があるかなど、一部の人々が既にこの種の問題に直面しているか、少なくとも正しい方向に向けることができることを願っています。

コードは次のとおりです。

USE [MyBaseName]
GO
/****** Object:  StoredProcedure [dbo].[Publication_getByCriteria]    Script Date: 05/29/2013 12:11:07 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Publication_getByCriteria]
    @id_sousTheme As int = null,
    @id_theme As int = null,
    @nbPubli As int = 1000000,
    @bActuSite As bit = null,
    @bActuPerso As bit = null,
    @bActuNewsletter As bit = null,
    @bActuChronique As bit = null,
    @bActuVideo As bit = null,
    @bActuVideoBuzz As bit = null,
    @bActuOpportunite As bit = null,
    @id_contact As int = null,
    @bOnlyPublished As bit = 0,
    @bOnlyForHomePage as bit = 0,
    @id_contactForTheme As int = null,
    @id_newsletter As int = null,
    @ID_ActuChronique As int = null,
    @sMotClef As varchar(500) = null,
    @sMotClefForFullText as varchar(500) = '""',
    @dtPublication As datetime = null,  
    @bParlonsFinance As bit = null,
    @bPartenaires as bit = null,
    @bUne As bit = null,
    @bEditoParlonsFinance As bit = null,
    @bEditoQuestionFonds as bit = null,
    @dtDebPublication As datetime = null,
    @dtFinPublication As datetime = null,
    @bOnlyActuWithDroitReponse As bit = 0,
    @bActuDroitReponse As bit = null
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @dtNow As datetime
    SET @dtNow = GETDATE()

    SELECT TOP (@nbPubli) p.id_publication, p.sTitre, p.sTexte, p.sTexteHTML, p.dtPublication, p.id_linkedDroitReponse,
        si.id_actusite, pe.id_actuPerso, ne.id_actuNewsletter, ac.id_actuChronique, av.id_actuVideo, ap.id_actuOpportunite, ad.id_actuDroitReponse,
        c.ID_Contact, c.sPhotoCarre, NULL As sTypePubli, n.id_newsletter, 
        dbo.Publication_get1Theme(p.id_publication) As theme,
        CAST(CASE WHEN ad.id_actuDroitReponse IS NULL THEN 0 ELSE 1 END As bit) As bIsDroitReponse,
        coalesce(Personne.sNom, Societe.sNom) as sNom, Personne.sPrenom
    FROM Publication p
        LEFT OUTER JOIN ActuSite si ON p.id_publication = si.id_publication
        LEFT OUTER JOIN ActuPerso pe ON p.id_publication = pe.id_publication
        LEFT OUTER JOIN ActuNewsletter ne ON p.id_publication = ne.id_publication
        LEFT OUTER JOIN ActuChronique ac ON p.id_publication = ac.id_publication
        LEFT OUTER JOIN ActuVideo av ON p.id_publication = av.id_publication
        LEFT OUTER JOIN ActuOpportunite ap ON p.id_publication = ap.id_publication
        LEFT OUTER JOIN ActuDroitReponse ad ON p.id_publication = ad.id_publication
        LEFT OUTER JOIN Contact c ON p.id_contact = c.ID_Contact
        LEFT OUTER JOIN Personne ON Personne.id_contact = c.id_contact
        LEFT OUTER JOIN Societe ON Societe.id_contact = c.id_contact
        LEFT OUTER JOIN Newsletter n ON ne.id_actuNewsletter = n.id_actuNewsletter
    WHERE p.bSupp = 0
    AND (@bOnlyPublished = 0 Or (@bOnlyPublished = 1 AND p.dtPublication IS NOT NULL AND p.dtPublication < @dtNow))
    AND (@id_sousTheme IS NULL Or p.id_publication IN(SELECT id_publication FROM PubliSousTheme WHERE id_soustheme = @id_sousTheme))
    AND (@id_theme IS NULL Or p.id_publication IN(SELECT id_publication FROM PubliTheme WHERE id_theme = @id_theme))
    AND ((@bActuSite = 1 AND si.id_actusite IS NOT NULL)
            OR (@bActuPerso = 1 AND pe.id_actuPerso IS NOT NULL)
            OR (@bActuNewsletter = 1 AND ne.id_actuNewsletter IS NOT NULL)
            OR (@bActuChronique = 1 AND ac.id_actuChronique IS NOT NULL)
            OR (@bActuVideo = 1 AND av.id_actuVideo IS NOT NULL)
            OR (@bActuVideoBuzz = 1 AND av.id_actuVideo IS NOT NULL and coalesce(av.sBuzz, '') <> '' )
            OR (@bActuOpportunite = 1 AND ap.id_actuOpportunite IS NOT NULL)
            OR (@bActuDroitReponse = 1 AND ad.id_actuDroitReponse IS NOT NULL))
    AND (@id_contact IS NULL Or p.id_contact = @id_contact)
    AND (@id_contactForTheme IS NULL Or 
            (p.id_publication IN(SELECT id_publication FROM PubliSousTheme 
                WHERE id_soustheme IN(SELECT id_soustheme FROM ContactSousTheme WHERE id_contact = @id_contactForTheme)))
            Or (p.id_publication IN(SELECT id_publication FROM PubliTheme 
                WHERE id_theme IN(SELECT id_theme FROM ContactTheme WHERE id_contact = @id_contactForTheme)))
            )
    AND (@ID_ActuChronique is NULL or id_actuChronique = @ID_ActuChronique)
    AND (@id_newsletter IS NULL Or p.id_publication IN(SELECT id_publication FROM ListActuNewsletter WHERE id_newsletter = @id_newsletter))
    AND (@sMotClef IS NULL 
        or contains((p.sTexte, p.sTitre), @sMotClefForFullText)
        Or Personne.sNom LIKE '%' + @sMotClef + '%' COLLATE Latin1_General_CI_AI
        Or Personne.sPrenom LIKE '%' + @sMotClef + '%' COLLATE Latin1_General_CI_AI
        Or Societe.sNom LIKE '%' + @sMotClef + '%' COLLATE Latin1_General_CI_AI
        )
    AND (@dtPublication IS NULL Or p.dtPublication >= @dtPublication)
    AND (
        @bParlonsFinance IS NULL Or
        (@bParlonsFinance = 0 AND p.id_publication NOT IN(SELECT id_publication FROM PubliTheme 
                WHERE id_theme IN(SELECT id_theme FROM Theme WHERE bParlonsFinance = 1)))
        Or (@bParlonsFinance = 1 AND p.id_publication IN(SELECT id_publication FROM PubliTheme 
                WHERE id_theme IN(SELECT id_theme FROM Theme WHERE bParlonsFinance = 1))))
    AND (
        @bPartenaires IS NULL Or
        (@bPartenaires = 0 AND p.id_publication NOT IN(SELECT id_publication FROM PubliTheme 
                WHERE id_theme IN(SELECT id_theme FROM Theme WHERE 0 = 1)))
        Or (@bPartenaires = 1 AND p.id_publication IN(SELECT id_publication FROM PubliTheme 
                WHERE id_theme IN(SELECT id_theme FROM Theme WHERE 0 = 1))))
    AND (
        @bUne IS NULL
        Or p.bUne = @bUne)
    AND (@bEditoParlonsFinance IS NULL
        Or p.bEditoParlonsFinance = @bEditoParlonsFinance)
        AND (@bEditoQuestionFonds IS NULL
        Or p.bEditoQuestionFonds = @bEditoQuestionFonds)
    AND (@dtDebPublication IS NULL Or p.dtPublication >= @dtDebPublication)
    AND (@dtFinPublication IS NULL Or p.dtPublication <= @dtFinPublication)
    AND (@bOnlyActuWithDroitReponse = 0 Or (@bOnlyActuWithDroitReponse = 1 AND p.id_linkedDroitReponse IS NOT NULL))
    and (@bOnlyForHomePage = 0 or (@bOnlyForHomePage = 1 and ac.bHomePage = 1))
    ORDER BY coalesce(p.dtPublication, p.dtCreate) DESC, p.id_publication DESC
END
4

2 に答える 2

23

ストアド プロシージャを初めてコンパイルすると、その実行プランがキャッシュされます。

sproc に含まれるクエリの実行計画 (インデックス スキャンとシークなど) を大幅に変更できる定義を持つパラメーターがある場合、ストアド プロシージャのキャッシュされた計画は、すべてのパラメーター定義に対して最適に機能するとは限りません。

これを回避する 1 つの方法は、ステートメントにRECOMPILE節を含めることです。CREATE PROCEDURE

例:

CREATE PROCEDURE dbo.mySpro
@myParam
WITH RECOMPILE
AS
BEGIN
 -- INSERT WORKLOAD HERE
END
GO

これにより、プロシージャが呼び出されるたびに新しいプランが生成されます。recompile time<の場合time lost by its using the wrong cached plan、これは使用する価値がありWITH RECOMPILEます。あなたの場合、実行が遅いことに気付くたびに、このプロシージャを手動で再コンパイルするために必要な時間/計画も節約できます。

于 2013-07-09T20:39:17.550 に答える
2

多くのパラメーターを持つストアド プロシージャの場合OPTION(OPTIMIZE FOR UNKNOWN)は、クエリの最後に追加して、特定のパラメーターの実行プランを最適化しないようにコンパイラに指示することをお勧めします。

ストアド プロシージャを初めて実行するときに SQL Server が行うことは、渡されたパラメーターの実行プランを最適化することです。これは、 と呼ばれるプロセスで行われParameter Sniffingます。

通常、実行プランは SQL Server によってキャッシュされるため、SQL Server は同じクエリに対して毎回再コンパイルする必要はありません。次にプロシージャが実行されると、SQL Server はその中のクエリの実行計画を再利用します... ただし、異なるパラメータでストアド プロシージャを呼び出すと、実行計画が完全に非効率になる可能性があります。

前述のオプションを追加すると、実行計画を特定のパラメーターに対して最適化するのではなく、ストアド プロシージャに渡される任意のパラメーターに対して最適化する必要があることが SQL コンパイラに伝えられます。ドキュメントから:

未知の最適化

強制パラメーター化で作成されたパラメーターを含め、クエリがコンパイルおよび最適化されるときに、すべてのローカル変数の初期値の代わりに統計データを使用するようクエリ オプティマイザーに指示します。

@sion_corn による回答でWITH RECOMPILEは、ストアド プロシージャ定義に追加することを推奨していますが、これにより、ストアド プロシージャが実行されるたびにステートメント全体の再コンパイルが強制されます。プロシージャが非常に頻繁に呼び出される場合、許容できないオーバーヘッドが発生する可能性があります。

于 2016-02-05T14:53:46.550 に答える