【问题标题】:Debugging long dynamic sql in SQL Server 2008在 SQL Server 2008 中调试长动态 sql
【发布时间】:2011-01-22 11:51:53
【问题描述】:

我有一些动态 sql 语句在某些条件下会爆炸,所以我正在尝试调试它。它是这样构建的:

declare @sql varchar(4000);
...
select @sql = '<part1>';
...
select @sql = @sql + '<part2>';
...
select @sql = @sql + '<part3>';
...
begin 
execute(@sql);
select @ec__errno = @@error
    if @ec__errno != 0
    begin
    if @@trancount != 0
    begin
    rollback;
    end
return @ec__errno;
end;
... 

正如我所说,它在循环的特定迭代中爆炸(不要问我为什么要这样实现,我只是在修复一个错误)并且我很难在其中显示字符串的内容一个观察窗口。我想我只得到前 255 个字符。关注substring(@sql, 0, 200) 的结果是'substring(@sql,0,200)' could not be evaluated。请帮忙。我希望能观察从 0 到 199、从 200 到 399 等等的子串,然后把这个东西拼凑起来,最后调试它。

非常感谢您的指点。谢谢!

【问题讨论】:

  • 我知道您发现了动态 SQl 往往是个坏主意的一个原因!
  • 我不是说它的可读性较差,只是调试起来很痛苦,而且在所有可能的条件下通常都无法调试。

标签: debugging sql-server-2008 dynamic-sql


【解决方案1】:

当强制在存储过程中使用动态 sql 时,我们执行以下操作。添加一个调试输入变量,它是一个位字段。如果为 0,则执行语句将继续,如果为 1,则您将得到一个打印语句。我建议你做一些类似的调试。不要执行,而是打印 SQL 的结果,或者可能将 SQl 插入到表中,因为它似乎是在循环中发生的。然后你可以查看构建的sql,看看哪里出错了。

Declare debug bit
set debug = 1

...
if debug = 1 Begin     Print @SQL End
Else 
Begin Exec (@sql) End

或者

创建一个名为 mydynamiccode_logging 的表(具有与最大 sql 语句长度相同的 sql 列、rundatecolumn 以及您可能认为必要的任何其他列(我会考虑用于构成 sql 语句的输入变量、用户, 如果有多个应用程序使用这段代码)

在运行 exec 语句之前,运行如下代码:

insert mydynamiccode_logging (sql, rundate)
values (@sql, getdate()) 

现在您还可以添加调试位字段,并且仅在您将其更改为调试模式时进行记录,或者您可以始终记录,这取决于系统以及这需要多少额外时间以及系统的其余部分如何猛击是。您不想通过记录显着减慢 prod。

【讨论】:

  • 啊,很酷!有没有机会检测到环境?有点像#if Debug ... #endif,或者如果 name == 'main' (Python)?如果我在“调试中”而不是“在生产中”,我希望在执行动态 sql 之前添加一个打印语句。有没有办法让这个工作?
  • PRINT 的问题是在生产环境中捕获它,这对于难以重现的问题至关重要。
  • 我不会在生产环境中运行打印。我不会尝试在产品中进行调试。您可以我想添加代码以始终将@ sql 发送到表(在运行 exec 之前使用输入变量和日期时间。然后您发送的所有内容都会自动记录下来,您可以查看表以在出现问题时找到问题错误。不过,您必须看看这会如何影响执行时间。
【解决方案2】:

做这样的事情,它只会记录失败:

BEGIN TRY

    DECLARE @LogString   varchar(max)

    --record input parameters
    SET @LogString='@Param1='+COALESCE(''''+@Param1+'''','null')
                   +@Param2='+COALESCE(''''+@Param2+'''','null')
                   +@ParamDate='+COALESCE(''''+CONVERT(varchar(23),@ParamDate,121)+'''','null')
                   +@ParamInt='+COALESCE(''''+CONVERT(varchar(10),@Paramint)+'''','null')

    --build @SQL_String String here
    --repeat as necessary
    SET @LogString=ISNULL(@LogString)+'; '+.... --every logic twist record what is going on

    EXEC (@SQL_String)

END TRY
BEGIN CATCH

    IF XACT_STATE()!=0
    BEGIN
        ROLLBACK TRANSACTION
    END

    SET @LogString=ISNULL(@LogString,'')+'; '
                 +CASE WHEN ERROR_NUMBER()     IS NOT NULL THEN 'Msg '         +CONVERT(varchar(30),   ERROR_NUMBER()     ) ELSE '' END
                 +CASE WHEN ERROR_SEVERITY()   IS NOT NULL THEN ', Level '     +CONVERT(varchar(30),   ERROR_SEVERITY()   ) ELSE '' END
                 +CASE WHEN ERROR_STATE()      IS NOT NULL THEN ', State '     +CONVERT(varchar(30),   ERROR_STATE()      ) ELSE '' END
                 +CASE WHEN ERROR_PROCEDURE()  IS NOT NULL THEN ', Procedure ' +                       ERROR_PROCEDURE()    ELSE '' END
                 +CASE WHEN ERROR_LINE()       IS NOT NULL THEN ', Line '      +CONVERT(varchar(30),   ERROR_LINE()       ) ELSE '' END
                 +CASE WHEN ERROR_MESSAGE()    IS NOT NULL THEN ', '           +                       ERROR_MESSAGE()      ELSE '' END

    INSERT INTO ErrorLog Values (@SQL_String)
    INSERT INTO ErrorLog Values (@LogString)

    --will echo back the complete original error message for the calling application
    DECLARE @ErrorMessage nvarchar(400), @ErrorNumber int, @ErrorSeverity int, @ErrorState int, @ErrorLine int
    SELECT @ErrorMessage = N'Error %d, Line %d, Message: '+ERROR_MESSAGE(),@ErrorNumber = ERROR_NUMBER(),@ErrorSeverity = ERROR_SEVERITY(),@ErrorState = ERROR_STATE(),@ErrorLine = ERROR_LINE()
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorNumber,@ErrorLine)

    RETURN 9999

END CATCH

【讨论】:

  • 有趣...我们尽量保持 sql 尽可能快。这种特殊修改有什么影响?
  • 只有几个字符串连接,只有在失败时才插入。我无法想象它会受到那么大的伤害。只需将其包含在正在轰炸的程序中,您将获得调试问题所需的所有信息,然后您可以将其注释掉。
猜你喜欢
  • 1970-01-01
  • 2012-08-11
  • 1970-01-01
  • 1970-01-01
  • 2014-03-30
  • 1970-01-01
  • 2011-04-26
  • 2013-07-22
  • 1970-01-01
相关资源
最近更新 更多