在SQL Server中优化大型过程的理想方法是什么?

时间:2012-08-02 10:48:25

标签: sql-server sql-server-2008 query-optimization

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

这个程序非常庞大,需要许多不同的子程序和功能。

通常情况下,许多不同的人已经开展了很多年的工作,并且没有人希望对其进行优化。

我的问题是 - 什么是优化此程序的最佳方法 - 是否有最佳实践指南来处理这样的事情?

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

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

2 个答案:

答案 0 :(得分:2)

由于你的存储过程调用子过程和函数,我认为它是一个树(过程本身是根),从叶子开始,一次一个函数,进入根。 / p>

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

答案 1 :(得分:1)

如果您喜欢断言值的方式,我会详细说明我在嵌套存储过程中断言的做法。

免责声明:此方法不是生产系统中最佳性能的最佳方式。我建议你评论所有的debuging断言并在生产系统中选择。特别是当嵌套程序将表结果返回到父程序时,调试选择可以完全破坏功能!

示例第一:

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

我希望,这会对你有帮助。