Dinamik SQL Yedekleme Komutları için Try / catch Kullanırken Hata Ayrıntılarını Kaydetme


10

Bir try catch ve dinamik sql kullanan bir saklı yordam içinde bir yedekleme komutu verilirken, hata mesajları doğrudan yedekleme komutunu çalıştırmayla karşılaştırıldığında çok geneldir.

SP içinde Dene / Yakala:

    begin try
        execute sp_executesql @sql;  -- a backup command
    end try
    begin catch  
        print ERROR_MESSAGE();  -- save to log, etc.
    end catch

Sonuçları

50000: usp_Backup: 117: YEDEKLEME VERİTABANI anormal olarak sona eriyor.

halbuki ham emri veren:

    backup DATABASE someDb to disk...

Sonuçlar daha ayrıntılı:

Arama Hatası - SQL Server Veritabanı Hatası: "H: \ FolderName \ Filename.bak:" 112 dosyasında kurtarılamayan bir G / Ç hatası oluştu. (Diskte yeterli alan yok.).

Bu ayrıntıları saklı yordamdaki değişkenlere kaydetmenin bir yolu var mı (günlüğe kaydetmek, arayan kişiye geri dönmek, yeniden deneme mantığı için)? Görünüşe göre detaylar mesaj kanalında geliyor ama SP'de mevcut olmasını istiyorum.


Bunu görmek isteyebilirsiniz: stackoverflow.com/questions/5966670/…
8kb

Yanıtlar:


13

Bir BACKUP DATABASEhata oluşturduğunda, aslında iki tane üretir. Ne yazık ki TRY/CATCHilk hatayı yakalayamıyor; yalnızca ikinci hatayı yakalar.

Ben başarısız bir yedekleme yoluyla yedekleri otomatik etmektir arkasında en iyi bahis gerçek sebebini yakalamak için şüpheli SQLCMD (ile -obir dosyaya çıktı göndermek için), SSIS, C #, PowerShell vb Bütün bunlar yakalama üzerinde size çok daha fazla kontrol sağlayan tüm hataların.

Yorumdaki SO cevabının kullanılması öneriliyor DBCC OUTPUTBUFFER- mümkün olsa da, bu hiç çocuk oyuncağı gibi görünmüyor. Erland Sommarskog'un sitesinden bu prosedürle eğlenmekten çekinmeyin , ancak bu hala birlikte iyi çalışmıyor gibi görünüyor TRY/CATCH.

Hata mesajını yakalayabildiğim tek yol spGET_LastErrorMessage, asıl hata atıldığında. Birini sararsanız TRY/CATCHhata yutulur ve saklı yordam hiçbir şey yapmaz:

BEGIN TRY
  EXEC sp_executesql N'backup that fails...';
END TRY
BEGIN CATCH
  EXEC dbo.spGet_LastErrorMessage;
END CATCH

SQL Server <2012'de hatayı kendiniz yeniden yükseltemezsiniz, ancak SQL Server 2012 ve daha yeni sürümlerde yapabilirsiniz. Yani bu iki varyasyon işe yarıyor:

CREATE PROCEDURE dbo.dothebackup
AS
BEGIN
  SET NOCOUNT ON;
  EXEC sp_executesql N'backup that fails...';
END
GO

EXEC dbo.dothebackup;
EXEC dbo.spGET_LastErrorMessage;

Veya 2012 ve sonrasında, bu işe yarıyor, ancak TRY/CATCHorijinal hata hala atıldığından, büyük ölçüde amacını bozuyor:

CREATE PROCEDURE dbo.dothebackup2
AS
BEGIN
  SET NOCOUNT ON;
  BEGIN TRY
    EXEC sp_executesql N'backup that fails...';
  END TRY
  BEGIN CATCH
    THROW;
  END CATCH
END
GO

EXEC dbo.dothebackup2;
EXEC dbo.spGET_LastErrorMessage;

Her iki durumda da, hata hala istemciye atılır. Bundan TRY/CATCHkaçınmak için kullanıyorsanız , düşünmediğim bazı boşluklar yoksa, bir seçim yapmanız gerekeceğinden korkuyorum ... ya kullanıcıya hata verin ve hakkında ayrıntılar yakalayın veya hatayı ve gerçek nedeni bastırın.


Oldukça saçma, Sommarskog yaklaşımı, sadece bir arayüzde arayan kişiye bir bağlam sağlamak istersem söz konusu değil. Ayrı bir işlem başlatmaktan daha iyidir. Bir TRY / CATCH içinde işe yaramayacağını mı söylüyorsun?
crokusek

@crokusek Bir varyasyon denedim ve sonuç boş çıktı. Bugün bir şans daha vereceğim.
Aaron Bertrand

Hata olmaması durumunda, LastErrorMessage () oturumdan önceki herhangi bir hatanın sonuçlarını alır mı? Sonra son iki exec komut dosyası olarak çalıştırılırsa, belki de ilk exec bir try / catch ve catch içine sarılabilir, bir değişken ayarlayabilir ve sonra tekrar atabilir. Ardından LastError yalnızca değişken ayarlanmışsa çağrılır. Yeniden atmanın, bir komut dosyası bağlamında genellikle doğru olduğunu düşündüğüm 2. çağrıyı atlamadığını varsayar. Sonunda hala bu yaklaşımı kullanamayabilirim, çünkü doğru anlarsam, hepsi bir SP içine yerleştirilemez. Yine de teşekkürler!
crokusek

2

Peki bu eski bir iş parçacığı olduğunu biliyorum ve ben önermek üzere olduğumu biliyorum kıvrık bir hack, ama sadece kimseye yardımcı olabilir durumda, işte gidiyor: Bu yedekleme hataları günlüğe alındığı için, yakalamak xp_readerrorlog kullanabilirsiniz ilgili iletinin günlüğünü kazımak için engelle (hata veya bilgi). Xp_readerrorlog parametreleri için google'ı kullanabilirsiniz, ancak kısaca bu durumda yararlı olan bir arama dizesi ve bir başlangıç ​​zamanı filtresi belirtebilirsiniz. Bunun yeniden deneme mantığınıza yardımcı olup olmayacağından emin değilim, ancak kayıt için bilgi veya hataları yakalamak için böyle bir şey buldum ...

IF OBJECT_ID('tempdb.dbo.#Results') IS NOT NULL DROP TABLE #Results
CREATE TABLE #Results (LogDate datetime,ProcessInfo nvarchar(100),LogText nvarchar(4000))
BEGIN TRY
SELECT @begintime = GETDATE()
EXEC sp_executesql @SQL --your backup statement string
INSERT #Results
EXEC  xp_readerrorlog 0, 1, N'backed up',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'Backup' order by logdate desc
END TRY
BEGIN CATCH
INSERT #Results
EXEC  xp_readerrorlog 0, 1, N'Backup',@databasename,@begintime
SELECT @result = LogText from #Results where ProcessInfo = 'spid'+cast(@@SPID as varchar(6)) order by logdate desc
END CATCH
PRINT @result

HTH


Bu, bazı yaygın hatalar için harika çalışır, ancak görünüşe göre yalnızca doğrudan istemciye atılan bazı hatalar vardır. Sp_readerrorlog günlüğü "uygulama günlüğüne" atıfta bulunacağını söyleyen bir mesaj içerecektir, burada "uygulama" ile komut veren harici işlem anlamına gelir. SO Link
crokusek

0

Hata ayrıntılarını bir tabloya kaydedebilirsiniz. Ayrıca bir günlük dosyası da oluşturabilirsiniz, ancak bunun için CLR veya xp_cmdshell gerekebilir. Veritabanı postası da gönderebilirsiniz; ancak bu, spam sorunlarına neden olabilir ve uygun bir günlük değildir.

Tablo en basit olanıdır.

  1. Hataları depolamak için bir tablo oluşturun
  2. Hata tablosuna eklenen saklı yordam oluşturma
  3. Yakalama bloğundaki saklı yordamı çağırın

Aşağıdaki bağlantıda verilen Jeremy Kadlec örneğine bakın:

http://www.mssqltips.com/sqlservertip/1152/standardized-sql-server-error-handling-and-centralized-logging/


3
Sorun, hatalarla ne yapılacağı ile ilgili değildir, içindeki bazı komutlar için uygun hata mesajının mevcut olmamasıdır CATCH. Bunun nedeni, yalnızca son hata mesajının geri döndürülmesidir ERROR_MESSAGE()...
Aaron Bertrand
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.