在我们的一个应用程序中,我的公司有一个需要很长时间才能运行的程序。
这个过程非常庞大,并且调用了许多不同的子过程和函数。
通常它已经被许多不同的人研究了很多年,但没有人希望对其进行优化。
我的问题是 - 优化此过程的最佳方法是什么 - 是否有最佳实践指南来处理此类问题?
任务如此艰巨,我不知道从哪里开始。专家将如何开始/解决这个问题?
我已经知道基本的 SQL Server 优化,例如执行计划/索引/写得不好的查询
在我们的一个应用程序中,我的公司有一个需要很长时间才能运行的程序。
这个过程非常庞大,并且调用了许多不同的子过程和函数。
通常它已经被许多不同的人研究了很多年,但没有人希望对其进行优化。
我的问题是 - 优化此过程的最佳方法是什么 - 是否有最佳实践指南来处理此类问题?
任务如此艰巨,我不知道从哪里开始。专家将如何开始/解决这个问题?
我已经知道基本的 SQL Server 优化,例如执行计划/索引/写得不好的查询
由于您的存储过程调用子过程和函数,我认为它是一棵树(过程本身是根),从叶子开始,一次一个函数,前进到根。
这样,您可以专注于一次执行的单个任务,并且在任何给定时刻检查的代码更少。
如果您喜欢断言值的方式,我将详细说明我在嵌套存储过程中断言的一种做法。
免责声明:这种方法不是在生产系统中获得最佳性能的最佳方式。我建议您评论所有调试断言并在生产系统中选择。尤其是当嵌套过程将表结果返回给父过程时,调试选择会完全破坏功能!
先举例:
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
我希望这能帮到您。