4

私は2つのことを行うストアドプロシージャを本番環境に持っています。1 つのテーブルを更新してから、レコードを別のテーブルに挿入します。最初のステップ (更新) は発生しているように見えますが、データを調べると、2 番目のステップが発生しなかったインスタンスが見つかりました。データを見て、データの問題ではないことを確認しました。クエリが完了し、通常の状況では両方が実行されることを確認するために、クエリが適切なデータを返すことを確認しました。おそらく何らかのパフォーマンスの問題があるかどうかはわかりません...または2番目のステップで発生しているブロックの問題が、そのステップの発生を妨げています。

ストアド プロシージャのエラー処理は次のとおりです。

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 プロファイラーから始めるのがよいでしょうが、廃止される予定です。

拡張イベントははるかに能力が高く、何が起こっているかを監視することに本当に興味がある場合は、それらについて読むことをお勧めします。

考えとして、プロシージャ コードが同じデータを使用して行を更新し、他のテーブルに挿入する場合は、OUTPUT の使用を検討してください。

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

OUTPUT および OUTPUT INTO

または、これがある種の監査またはログ テーブル用である場合は、DELETED.col1 を使用できます。これは、更新される前の元の値になります。INSERTED は、更新または挿入している値を返すことに注意してください。両方に対して INSERTED と呼ばれています。

于 2012-06-22T07:04:08.733 に答える
0

Visual Studio のコピーがある場合は、試してみてください。これにより、ストアド プロシージャをステップ実行できます。

于 2012-05-18T19:57:35.197 に答える
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

論理的に考えると、これら 2 つのステップの前にトランザクションを宣言するため、エラーが発生すると両方のトランザクションがロールバックされます。したがって、ほとんどの場合、ここにはエラーはまったくありません。問題は他の場所ではなくクエリにある可能性があるため、クエリをもう一度調べることをお勧めします。さらに提案が必要な場合は、コード全体を投稿してください。

よろしく

ローマン

于 2012-06-12T03:18:51.567 に答える