0

在我们的一个应用程序中,我的公司有一个需要很长时间才能运行的程序。

这个过程非常庞大,并且调用了许多不同的子过程和函数。

通常它已经被许多不同的人研究了很多年,但没有人希望对其进行优化。

我的问题是 - 优化此过程的最佳方法是什么 - 是否有最佳实践指南来处理此类问题?

任务如此艰巨,我不知道从哪里开始。专家将如何开始/解决这个问题?

我已经知道基本的 SQL Server 优化,例如执行计划/索引/写得不好的查询

4

2 回答 2

2

由于您的存储过程调用子过程和函数,我认为它是一棵树(过程本身是根),从叶子开始,一次一个函数,前进到根。

这样,您可以专注于一次执行的单个任务,并且在任何给定时刻检查的代码更少。

于 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 回答