Làm cách nào để xóa bộ đệm IN trong TSQL?


220

Tôi có một quy trình được lưu trữ rất lâu trong SQL Server 2005 mà tôi đang cố gắng gỡ lỗi và tôi đang sử dụng lệnh 'print' để thực hiện. Vấn đề là, tôi chỉ nhận được các tin nhắn từ SQL Server ở cuối sproc của mình - tôi muốn có thể xóa bộ đệm tin nhắn và xem các tin nhắn này ngay lập tức trong thời gian chạy của sproc, chứ không phải ở chính kết thúc.


1
Chỉ cần một thông báo ngắn cho những người sẽ (như tôi) nghĩ rằng câu trả lời không phù hợp với họ: hãy chắc chắn chuyển sang tab "Tin nhắn" khi truy vấn đang chạy. Theo mặc định, bạn sẽ thấy tab "Kết quả".
Tomasz Gandor

Câu trả lời:


305

Sử dụng RAISERRORchức năng:

RAISERROR( 'This message will show up right away...',0,1) WITH NOWAIT

Bạn không nên thay thế hoàn toàn tất cả các bản in của bạn bằng raiserror. Nếu bạn có một vòng lặp hoặc con trỏ lớn ở đâu đó, chỉ cần thực hiện một hoặc hai lần mỗi lần lặp hoặc thậm chí chỉ vài lần lặp.

Ngoài ra: Lần đầu tiên tôi biết về RAISERROR tại liên kết này, giờ đây tôi đã xem xét nguồn chính xác về xử lý Lỗi Máy chủ SQL và chắc chắn đáng để đọc:
http://www.sommarskog.se/error-handling-I.html


41
Lưu ý rằng TRY / CATCH trong SQL sẽ chỉ bắt lỗi với mức độ nghiêm trọng> 10, vì vậy sử dụng RAISERROR theo cách này sẽ không nhảy vào câu lệnh CATCH của bạn. Điều này thật tuyệt, vì điều đó có nghĩa là bạn vẫn có thể sử dụng RAISERROR như thế này với TRY / CATCH. ref: msdn.microsoft.com/en-us/l Library / ms175976.aspx
Rory

13
Lưu ý rằng điều này không hoạt động sau 500 tin nhắn đầu tiên; một khi bạn in nhiều hơn nó đột nhiên bắt đầu đệm!
GendoIkari

@MahmoudMoravej Không, tôi vẫn đang chạy các quy trình chạy dài bằng RAISEERROR và chỉ xử lý thực tế là sau một thời gian, các tin nhắn bắt đầu được đệm. Có vẻ như giải pháp duy nhất là sử dụng một công cụ khác ngoài SSMS.
GendoIkari

1
Tôi nghĩ rằng đây là một cái gì đó đã thay đổi trong một phiên bản SS gần đây. Quay trở lại khi lần đầu tiên tôi viết bài này, chúng tôi đã sử dụng RAISERROR để ghi nhật ký rộng rãi các quy trình hàng loạt qua đêm với hơn 500 tin nhắn và đó không phải là vấn đề. Nhưng rất nhiều có thể thay đổi trong 7 năm.
Joel Coehoorn

1
Theo thông báo của @ GendoIkari. Tôi đã thử nó với ssms từ 2016SP1 với kịch bản này. Ở mức 500, nó chuyển sang đệm 50 dòng và ở mức 1k, nó chuyển sang 100 dòng mỗi dòng. Điều này tiếp tục ít nhất cho đến 2k, nhưng sau đó tôi đã dừng kịch bản. khai báo @i int set @i = 0 khai báo @t varchar (100) trong khi 1 = 1 bắt đầu tập @i = @i + 1 set @t = 'print' + convert (varchar, @i) RAISERROR (@t, 10 , 1) VỚI NGAY BÂY GIỜ chờ kết thúc '00: 00: 00.010 '
Zartag

28

Dựa trên câu trả lời của @JoelCoehoorn, cách tiếp cận của tôi là để lại tất cả các câu lệnh IN của tôi, và chỉ cần làm theo chúng với câu lệnh RAISERROR để gây ra sự lộn xộn.

Ví dụ:

PRINT 'MyVariableName: ' + @MyVariableName
RAISERROR(N'', 0, 1) WITH NOWAIT

Ưu điểm của phương pháp này là các câu lệnh PRINT có thể nối các chuỗi, trong khi RAISERROR thì không thể. (Vì vậy, dù bằng cách nào bạn cũng có cùng số dòng mã, vì bạn phải khai báo và đặt biến để sử dụng trong RAISERROR).

Nếu, giống như tôi, bạn sử dụng AutoHotKey hoặc SSMSBoost hoặc một công cụ tương đương, bạn có thể dễ dàng thiết lập một lối tắt như "] flush" để nhập dòng RAISERROR cho bạn. Điều này giúp bạn tiết kiệm thời gian nếu đó là cùng một dòng mã mỗi lần, tức là không cần phải tùy chỉnh để giữ văn bản cụ thể hoặc một biến.


6
Lưu ý rằng RAISERROR()không hỗ trợ printf()nội suy chuỗi kiểu. Ví dụ, nếu @MyVariableNamelà một loại stringish (ví dụ VARCHAR(MAX), NVARCHAR(MAX)vv), bạn có thể sử dụng RAISERROR()với một dòng: RAISERROR(N'MyVariableName: %s', 0, 1, @MyVariableName).
binki

Điều này thật tiện lợi! Tôi biết rằng RAISERROR có thể thực hiện một số thay thế đơn giản, nhưng hãy thử thay thế thời gian [ngày] hoặc gọi một hàm từ bên trong câu lệnh RAISERROR! Câu trả lời này cung cấp cho bạn một FLush đơn giản dưới dạng tăng lỗi trống (với chi phí của một dòng mới).
Tomasz Gandor

19

Có ... Tham số đầu tiên của hàm RAISERROR cần một biến NVARCHAR. Vì vậy, hãy thử những điều sau đây;

-- Replace PRINT function
DECLARE @strMsg NVARCHAR(100)
SELECT @strMsg = 'Here''s your message...'
RAISERROR (@strMsg, 0, 1) WITH NOWAIT

HOẶC LÀ

RAISERROR (n'Here''s your message...', 0, 1) WITH NOWAIT

10
Nhìn vào tab Tin nhắn ở phía dưới, bên cạnh tab Kết quả hoặc chuyển sang chế độ Kết quả thành Văn bản.
Mehmet Ergut

Để chuyển sang chế độ Kết quả sang Văn bản, trong SSMS, menu Công cụ -> Tùy chọn -> Kết quả truy vấn -> Máy chủ SQL -> Chung -> Đích mặc định cho kết quả và chọn "Kết quả thành văn bản" thay vì "Kết quả thành lưới", lại -open cửa sổ truy vấn và sau đó bạn sẽ không ngồi đó nhìn vào tab Kết quả trống như hình nộm trong khi đầu ra RAISERROR chuyển đến tab Tin nhắn.
Adam

12

Một tùy chọn khác tốt hơn là không phụ thuộc vào PRINT hoặc RAISERROR và chỉ cần tải các câu lệnh "in" của bạn vào bảng ## Temp trong TempDB hoặc một bảng cố định trong cơ sở dữ liệu của bạn, nó sẽ cung cấp cho bạn khả năng hiển thị dữ liệu ngay lập tức thông qua câu lệnh CHỌN từ một cửa sổ khác . Điều này làm việc tốt nhất cho tôi. Sử dụng một bảng vĩnh viễn sau đó cũng phục vụ như một bản ghi cho những gì đã xảy ra trong quá khứ. Các báo cáo in rất tiện cho các lỗi, nhưng sử dụng bảng nhật ký, bạn cũng có thể xác định điểm chính xác của lỗi dựa trên giá trị được ghi cuối cùng cho lần thực hiện cụ thể đó (giả sử bạn theo dõi thời gian bắt đầu thực hiện chung trong bảng nhật ký của mình.)


2
Đây có thể là một vấn đề nếu bạn đang viết một kịch bản giao dịch thực sự với cam kết và khôi phục. Tôi không tin rằng bạn sẽ có thể truy vấn bảng tạm thời của mình trực tiếp - và nó sẽ biến mất nếu giao dịch của bạn thất bại.
SteveJ

@SteveJ bạn có thể truy vấn trực tiếp bằng cách sử dụng SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;trong phiên giám sát của mình
TheConstructor

1
@ Người hướng dẫn; Đó là một mẹo hữu ích - Tôi sẽ sử dụng nó, cảm ơn. Tuy nhiên, không phải chúng ta vẫn còn lại với bảng tạm thời sẽ quay trở lại? Nếu làm phân tích thất bại, có vẻ như đó sẽ là một thiếu sót lớn.
SteveJ

1
@SteveJ vâng, chắc chắn là có cái này. Tất nhiên bạn có thể sao chép dữ liệu trong một READ UNCOMMITTEDgiao dịch sang một bảng khác, nhưng bạn có thể bỏ lỡ khoảnh khắc ngay trước đó ROLLBACK. Vì vậy, nó có thể giải quyết 'bao xa?' không phải là 'tại sao rollback?'
TheConstructor

4

Chỉ để tham khảo, nếu bạn làm việc trong các tập lệnh (xử lý hàng loạt), không phải trong quy trình được lưu trữ , đầu ra tuôn ra được kích hoạt bằng lệnh GO, ví dụ:

print 'test'
print 'test'
go

Nói chung, kết luận của tôi là như sau: đầu ra của việc thực thi tập lệnh mssql, thực thi trong SMS GUI hoặc với sqlcmd.exe, được chuyển sang tệp, stdoutput, cửa sổ gui trên câu lệnh GO đầu tiên hoặc cho đến khi kết thúc tập lệnh.

Xóa bên trong các chức năng thủ tục được lưu trữ khác nhau, vì bạn không thể đặt GO bên trong.

Tham khảo: tuyên bố tsql Go


2
gokhông chỉ tuôn ra đầu ra, nó kết thúc lô theo liên kết bạn cung cấp. Bất cứ thứ gì bạn declared đều bị loại bỏ, vì vậy không thể sử dụng để gỡ lỗi. declare @test int print "I want to read this!" go set @test=5mặc dù bạn @testsẽ không xác định được lỗi vì nó nằm trong một đợt mới.
asontu

1
Tôi đồng ý, đây không phải là câu trả lời thích hợp cho câu hỏi này, nhưng tôi đặt câu trả lời (xem từ chối trách nhiệm khi bắt đầu) vì nó có thể hữu ích cho người khác - ví dụ: người nào đó chạy đợt sql.
Robert Lujo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.