0

私の会社には、アプリケーションの 1 つで、実行に時間がかかる手順があります。

このプロシージャは巨大で、多くの異なるサブプロシージャと関数を呼び出します。

通常、これは何年にもわたって多くの異なる人々によって取り組まれてきましたが、誰もそれを最適化しようとはしませんでした。

私の質問は-この手順を最適化するための最良の方法は何ですか-このようなものにアプローチするためのベストプラクティスガイドはありますか?

その仕事はとても大変で、どこから手を付けていいのかわからない. 専門家はどのようにこれを開始/取り組みますか?

基本的な SQL Server の最適化 (実行計画 / インデックス作成 / 不十分なクエリの記述など) は既に知っています

4

2 に答える 2

2

ストアド プロシージャはサブプロシージャと関数を呼び出すので、ツリー (プロシージャ自体がルート) と見なし、リーフから開始して、一度に 1 つの関数でルートに進みます。

これにより、一度に実行される 1 つのタスクに集中でき、特定の瞬間にチェックするコードが少なくなります。

于 2012-08-02T10:54:22.690 に答える
1

値をアサートする方法が気に入った場合は、入れ子になったストアド プロシージャでアサートする方法について詳しく説明します。

免責事項:このアプローチは、実稼働システムで最高のパフォーマンスを得るための最良の方法ではありません。すべてのデバッグ アサーションにコメントを付けて、運用システムで選択することをお勧めします。特に、デバッグ選択は、ネストされたテーブル結果が親プロシージャに返されるプロシージャである場合、機能を完全に壊す可能性があります!

最初の例:

ALTER PROC [dbo].[MyTopLevelProc]
    @SomeText nvarchar(50),
    @SomeNumber bigint

    /* >>> parameters only for debug >>> */
    /* debug parameters should have always default values and should be last parameters of procedure. it is goog practice because of usage during development/production phase */
    , @EnableDebugSelects bit = NULL -- if 1, then table-results will be used for asserting table data for debuging
    , @LogIndent int = NULL -- determines indentation of text asserts
    /* <<< parameters only for debug <<< */
BEGIN
    IF @EnableDebugSelects IS NULL SET @EnableDebugSelects = 0
    IF @LogIndent IS NULL OR @LogIndent < 0 SET @LogIndent = 0

    /* @SubLogIndent = indentation for nested procedures */
    DECLARE @SubLogIndent int = @LogIndent + 1

    DECLARE @_CurrentProcName_ nvarchar(255) = '[dbo].[MyTopLevelProc]'
    EXEC x.LogStr @LogIndent, 'PROC: ', @_CurrentProcName_, ' >>>' -- asserts start of procedure

    EXEC x.LogStr @LogIndent, 'INSERT INTO _some_table_'
    INSERT INTO _some_table_ ( ... columns ... )
        SELECT ... columns ... FROM _other_table_
    EXEC x.LogRowCount @LogIndent, @@ROWCOUNT

    EXEC x.LogStr @LogIndent, 'Getting product names ...'
    DECLARE @TblProductName TABLE (
        ProductID int,
        ProductName nvarchar(50)
    )
    INSERT INTO @TblProductName (ProductID, ProductName)
        SELECT ProductID, ProductName FROM _some_product_table_
    EXEC x.LogRowcount @LogIndent, @@ROWCOUNT

    IF @EnableDebugSelects = 1 BEGIN
        -- using the name of table-variable (@TblProductName) as column name is good practise for cases when the table variable has no rows. even from column names you can see which table-variable was selected
        SELECT '' AS [@TblProductName], * FROM @TblProductName
    END

    EXEC x.LogStr @LogIndent, 'Calling nested procedure ...'
    DECLARE @Result int
    EXEC @Result = [dbo].[AnotherProcedure]
                     @SomeTextParameter = 'Hello world!',
                     @SomeNumberParameter = 42,
                     /* we want pass debug parameters into nested procedures */
                     @EnableDebugSelects = @EnableDebugSelects,
                     @LogIndent = @SubLogIndent -- passing increased indentation for text asserts
    EXEC x.LogInt @LogIndent, '@Result: ', @Result

    EXEC x.LogStr @LogIndent, 'PROC: <<< ', @_CurrentProcName_ -- asserts end of procedure
END

プロシージャx.Log*は、カスタム スキーマ内のカスタム ストアド プロシージャxです。ストアド プロシージャの本体は次のようになります。

ALTER PROCEDURE [x].[Log]
    @LogIndent int = 0,
    @Str nvarchar(max),
    @Str2 nvarchar(max) = NULL,
    @Str3 nvarchar(max) = NULL,
    @Str4 nvarchar(max) = NULL,
    @Str5 nvarchar(max) = NULL
AS
BEGIN
DECLARE @Msg nvarchar(max) = ''

IF @LogIndent IS NULL SET @LogIndent = 0
IF @LogIndent > 0 BEGIN
    DECLARE @i int = 0
    WHILE @i < @LogIndent BEGIN
        SET @i = @i + 1
        SET @Msg = @Msg + '    '
    END
END

IF NOT @Str IS NULL SET @Msg = @Msg + @Str
IF NOT @Str2 IS NULL SET @Msg = @Msg + @Str2
IF NOT @Str3 IS NULL SET @Msg = @Msg + @Str3
IF NOT @Str4 IS NULL SET @Msg = @Msg + @Str4
IF NOT @Str5 IS NULL SET @Msg = @Msg + @Str5

PRINT @Msg
END

他のx.Log*プロシージャは、次のようなヘルパー プロシージャです。

ALTER PROCEDURE [dbo].[LogInt]
    @LogIndent int = 0,
    @Num int,
    @Prefix nvarchar(max) = NULL,
    @Suffix nvarchar(max) = NULL
AS
BEGIN
    DECLARE @Result int = 0

    DECLARE @Msg nvarchar(max) = ISNULL(CAST(@Num as nvarchar(max)), 'NULL')

    EXEC @Result = Log @LogIndent = @LogIndent
                , @Str = @Prefix
                , @Str2 = @Msg

    RETURN @Result
END

これが役立つことを願っています。

于 2012-08-02T11:46:59.873 に答える