2012-05-16 25 views
4

我有一個存儲過程在生產中做了2件事情。它更新一個表格,然後將記錄插入另一個表格。第一步(更新)似乎發生,但我們通過檢查第二步未發生的數據找到了實例。我查看了數據並確認它不是數據問題。我已確認查詢返回適當的數據以確保查詢完成,並且在正常情況下兩者都應該執行。我不知道是否可能存在某種性能問題......或阻止第二步發生的問題阻止該步驟的發生。如何調試我無法在任何測試環境中重現的SQL Server數據問題?

存儲過程的錯誤處理如下。

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 [email protected] --- 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功能,我不知道?

+2

不要混合和匹配您的錯誤處理過程。如果你使用'TRY ... CATCH',那麼你不需要'@@ ERROR'和'@@ TRANCOUNT'的'IF'檢查 - 如果有錯誤,它會直接跳到你的'CATCH'。 – JNK

+1

如果是我,我會開始記錄開始和停止更新並單獨插入步驟。然後,您可以輕鬆比較,看看您是否曾經開始但並未停止,或跳過一步。 – JNK

+0

記錄開始和停止實際上不是一個壞主意... –

回答

0

如果您擁有Visual Studio的副本,請嘗試使用它。它允許您逐步執行存儲過程。

+0

謝謝...我有,但問題是沒有通過存儲過程步進它試圖重現錯誤...或試圖找出錯誤..在調試器中,如果我不能在任何環境中重現它,但在生產中我看不到錯誤。 –

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,所以你可以看看它

最後我會創造一些代碼來調用持續的過程,直到錯誤聲明。然後,您可以檢查錯誤表,看看是否會引發您的問題。

希望這會有所幫助。 Jude

0

邏輯思考 - 因爲您在這兩個步驟之前聲明瞭事務,所以任何錯誤都會導致兩個事務的回滾。所以這裏最有可能沒有錯誤。我會建議再次檢查你的問題,因爲看起來問題可能在他們而不是其他任何地方。如果您需要更多建議,請發佈整個代碼。

問候

羅馬

1

如果你想要監控的數據庫,SQL Profiler是一個良好的開端,但它會被棄用。

擴展事件更有能力,如果您真的有興趣監視正在發生的事情,我會建議您閱讀這些內容。

作爲一個想法,如果您的過程代碼使用相同的數據更新行,因爲它插入到另一個表中,請考慮使用OUTPUT。

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

OUTPUT and OUTPUT INTO

或者,如果這是某種形式的審計或日誌表,你可以使用DELETED.col1 這將是它被更新之前的原始值。請注意,INSERTED將返回您正在更新或插入的值,對於兩者都只是稱爲INSERTED。

相關問題