4

我在生产中有一个存储过程,它做两件事。它更新一个表,然后将一条记录插入到另一个表中。第一步(更新)似乎发生了,但我们通过检查没有发生第二步的数据发现了实例。我查看了数据并确认这不是数据问题。我已经确认查询返回了适当的数据,以确保查询完成并且在正常情况下都应该执行。我不知道是否可能存在某种性能问题......或阻止该步骤发生的第二步发生的阻塞问题。

存储过程的错误处理如下。

BEGIN TRY  

BEGIN TRANSACTION;  

 -- perform update to data

 -- insert record into second table. 


 IF ( @@ERROR = 0 AND @@TRANCOUNT > 0 )  
    COMMIT TRANSACTION;  

 END TRY  
 BEGIN CATCH  

   IF ( @@TRANCOUNT > 0 )  
   BEGIN   
      ROLLBACK TRANSACTION;  
   END  

   DECLARE @WebSafeErrorId INT;  
   EXEC dbo.spErrorInsert @WebSafeErrorId OUTPUT, 'Proc';  

   -- Reraise the error back to the client.  
   IF ( @WebSafeErrorId != 0 )   
   BEGIN   
      DECLARE @Error VARCHAR(20);  
      SET @Error = CAST( @WebSafeErrorId AS VARCHAR(20) );  
      RAISERROR( @Error, 11, 1 );  
   END  
   ELSE  
   BEGIN  
      RAISERROR( 'An error has occurred but there is no error to log.', 11, 1 );  
   END   

END CATCH;

当然,如果此过程中发生导致插入不发生的错误,它将被记录然后引发。spErrorInsert 的代码如下...

CREATE PROCEDURE [dbo].[spErrorInsert]  
@ReturnErrorId INT OUTPUT  
, @ErrorSourceType VARCHAR(4) = NULL  
, @ParentErrorId INT = NULL  
, @StackTrace VARCHAR(MAX) = NULL  
AS  

SET NOCOUNT ON;  
--SET XACT_ABORT ON;  

-- Will indicate an error was not logged.  
SET @ReturnErrorID = 0;   

DECLARE  
  @ErrorSource VARCHAR(200)  
  , @ErrorMessage VARCHAR(MAX)  
  , @ComposedErrorMessage VARCHAR(MAX)  
  , @ErrorLine INT  
  , @ErrorSeverity INT  
  , @ErrorState INT  
  , @ErrorNumber INT;  

 SET @ErrorSource = ERROR_PROCEDURE();  
 SET @ErrorMessage = ERROR_MESSAGE();  
 SET @ErrorLine = ERROR_LINE();  
 SET @ErrorSeverity = ERROR_SEVERITY();  
 SET @ErrorState = ERROR_STATE();  
 SET @ErrorNumber = ERROR_NUMBER();  
 SET @ComposedErrorMessage = 'Message: Error occurred in procedure ' + CAST( @ErrorSource AS VARCHAR(MAX) )  
  + ' on line ' + CAST( @ErrorLine AS VARCHAR(MAX) )   
  + '. Error: ' + @ErrorMessage;  

BEGIN TRY  

   INSERT INTO Errors(  
      ParentId  
      , ErrorSourceType  
      , ErrorSource  
      , [Message]  
      , [LineNo]  
      , Severity  
      , Stacktrace  
      , ts)  
   VALUES (@ParentErrorId  
      , @ErrorSourceType --@ErrorSourceType --- NOTE: move this into a parameter ...   
      , @ErrorSource  
      , @ComposedErrorMessage  
      , @ErrorLine  
      , @ErrorState  
      , @Stacktrace  
      , GETDATE()  
      );  

  SET @ReturnErrorId = SCOPE_IDENTITY();  

END TRY  
BEGIN CATCH  

   RAISERROR( 'An error has occurred but there is no error to log.', 11, 1 );  

END CATCH;  

我不知道是否有办法在调用某个过程的特定时间获取数据库正在发生的事情的快照......我不确定如何确定它是否没有发生应该?有没有我可以使用的工具或我不知道的 sql 功能???

4

4 回答 4

1

如果您想监视数据库,SQL Profiler 是一个不错的起点,但它将被弃用。

扩展事件的功能要强大得多,如果您真的对监控正在发生的事情感兴趣,我建议您阅读这些内容。

作为一个想法,如果您的过程代码使用相同的数据来更新行,因为它要插入到另一个表中,请考虑使用 OUTPUT。

Update table set col1 = 'value'
OUTPUT inserted.col INTO othertable
Where col3 = stuff

输出和输出到

或者,如果这是针对某种审计或日志表,您可以使用 DELETED.col1 这将是更新之前的原始值。请注意, INSERTED 将返回您正在更新或插入的值,这两者都称为 INSERTED。

于 2012-06-22T07:04:08.733 回答
0

我会尝试的方法是首先复制此过程并注释掉 try/catch。我发现如果生成错误的代码在 try/catch 块内,tsql 不会引发错误——我猜这是由 catch 子句处理的异常的 sql 等价物。

我在我的数据库中使用一个表来永久记录错误发生时(我在嵌入式编程中学到的一个技巧)错误表创建代码是:

CREATE TABLE dbo.errors (
id smallint NOT NULL IDENTITY(1, 1) PRIMARY KEY,
errordesc nvarchar (max) NOT NULL,
dateandtime smalldatetime NOT NULL, -- Date and time of last occurance
errorcount int NOT NULL) ;

我将记录添加到错误表中的存储过程是:

CREATE PROCEDURE jc_diagnostics.jpwsp0005_adderrordescription( 
    @Errordescription nvarchar( max ))
AS 
    BEGIN
    DECLARE
       @Id smallint = 0 ,
       @Currentcount int = 0;
    IF((@Errordescription IS NULL) OR ( @Errordescription = ''))
        BEGIN
            SET @Errordescription = 'Error description missing';
        END;

    SELECT @Id = ( SELECT TOP ( 1 ) id
                 FROM jc_diagnostics.errors
                 WHERE errordesc = @Errordescription );
    IF(@Id IS NOT NULL)
    BEGIN
        SELECT @Currentcount = (SELECT errorcount
                                   FROM jc_diagnostics.errors
                                   WHERE id = @Id );
        SET @Currentcount = @Currentcount + 1;
        UPDATE jc_diagnostics.errors
        SET errorcount = @Currentcount 
          WHERE id = @Id;

        UPDATE jc_diagnostics.errors
        SET dateandtime = CONVERT(smalldatetime , GETDATE())
          WHERE id = @Id;
    END;
ELSE
    BEGIN
        --new entry
        INSERT INTO jc_diagnostics.errors( errordesc ,
                                           dateandtime ,
                                           errorcount )
        VALUES( @Errordescription ,
                CONVERT(smalldatetime , GETDATE()) ,
                1 );
    END;
IF(@Id IS NULL)
    BEGIN
        SET @Id = SCOPE_IDENTITY( );
    END;

RETURN @Id;
END;

发生错误时的调用代码是:

Declare @Failuredesc nvarchar(max) = 'Description of error';
EXEC @Retval = jc_diagnostics.jpwsp0005_adderrordescription @Failuredesc; 

返回值@Retval 包含错误表中记录的id,以便您查找

最后,我将创建一些代码来不断调用您的过程,直到声明错误为止。然后,您可以检查错误表,看看这是否能说明您的问题。

希望这可以帮助。裘德

于 2012-06-11T09:50:33.683 回答
0

如果您有 Visual Studio 的副本,请尝试一下。它允许您逐步执行存储过程。

于 2012-05-18T19:57:35.197 回答
0

从逻辑上思考 - 因为您在这两个步骤之前声明了事务,所以任何错误都会导致两个事务的回滚。所以很可能这里根本没有错误。我建议再次检查您的查询,因为似乎问题可能出在它们而不是其他任何地方。如果您需要更多建议,请发布整个代码。

问候

罗马

于 2012-06-12T03:18:51.567 回答