Việc ngắt kết nối mạng có dừng truy vấn không?


13

Gần đây tôi đã thực hiện một truy vấn cập nhật đối với 100.000 hồ sơ. Tôi nhận ra mình đã mắc lỗi trong khi truy vấn đang chạy và nhanh chóng rút cáp mạng.

Có truy vấn cập nhật không

  1. ngừng xử lý và hoàn toàn rollback?
  2. Tiếp tục xử lý để hoàn thành và cam kết?
  3. dừng xử lý và chỉ để lại một phần của các hàng đích được cập nhật?

2
một khi truy vấn đến máy chủ, nó sẽ tiếp tục trừ khi bạn hủy truy vấn trên máy chủ.
JP Chauhan


1
Nhận xét của Martin cung cấp câu trả lời trực tiếp cho câu hỏi của bạn, robocop. Nếu mạng thông báo cho SQL Server về việc ngắt kết nối trước khi truy vấn của bạn chạy xong, thì SQL Server sẽ khôi phục lại. Mặt khác, nếu truy vấn hoàn thành trước khi SQL Server được thông báo có ngắt kết nối mạng, thì nó sẽ được cam kết. Trong mọi trường hợp (giả sử bạn đã viết một truy vấn cập nhật), SQL Server sẽ thực hiện cập nhật một phần.
Nick Chammas

Câu trả lời:


22

Như Nick và Martin đã đề cập, trạng thái cuối cùng của truy vấn của bạn phụ thuộc vào việc SQL Server có biết về việc kéo cáp mạng của bạn hay không trước khi truy vấn hoàn thành. Từ Sách trực tuyến (mặc dù tôi thấy thú vị rằng có các chủ đề tương đương cho điều này vào năm 2000 , 2005 , 20082008 R2 , nhưng không phải là 2012 hay 2014):

Nếu một lỗi ngăn cản việc hoàn thành giao dịch thành công, SQL Server sẽ tự động khôi phục giao dịch và giải phóng tất cả các tài nguyên do giao dịch nắm giữ. Nếu kết nối mạng của máy khách với một phiên bản của Công cụ cơ sở dữ liệu bị hỏng, mọi giao dịch chưa xử lý cho kết nối sẽ được khôi phục khi mạng thông báo về trường hợp bị hỏng. Nếu ứng dụng khách bị lỗi hoặc nếu máy khách bị hỏng hoặc khởi động lại, điều này cũng sẽ phá vỡ kết nối và trường hợp của Công cụ cơ sở dữ liệu sẽ khôi phục mọi kết nối chưa xử lý khi mạng thông báo về sự cố. Nếu khách hàng đăng xuất khỏi ứng dụng, mọi giao dịch chưa xử lý sẽ được khôi phục.

(Bên cạnh đó, các kết nối từ đó trong câu cuối cùng thứ 2 có lẽ là các giao dịch . Tôi không biết làm thế nào một kết nối lại kết nối.)

Theo cách tương tự, SQL Server có thể hoàn tác hoặc thực hiện lại các giao dịch trong quá trình khôi phục sau khi máy chủ bị tắt đột ngột và điều này sẽ phụ thuộc vào trạng thái của giao dịch tại thời điểm tắt máy. Tôi đã thấy mọi người sử dụng chiến thuật này để đạt được những gì bạn đang cố gắng (hủy (các) giao dịch) và khi máy chủ khởi động lại, phần lớn công việc chỉ đơn giản là làm lại (vì vậy hiệu ứng ròng của phản ứng giật đầu gối của họ gần hơn rất nhiều đến không hơn họ mong đợi).

Vì vậy, thay vì phải chịu điều này, thay vì làm những việc quyết liệt trong hoảng loạn, như giật cáp mạng hoặc tắt máy, tôi đề nghị trong tương lai bạn nên có kỷ luật tốt hơn về việc chạy các truy vấn ad hoc đối với các hệ thống quan trọng. Ví dụ: thay vì:

UPDATE dbo.sometable 
-- where *oops* I forgot this part

Có cái này:

BEGIN TRANSACTION;

UPDATE dbo.sometable
-- where *oops* I forgot this part

-- COMMIT TRANSACTION;
-- ROLLBACK TRANSACTION;

Sau đó, nếu bản cập nhật thực sự chính xác, bạn có thể đánh dấu COMMITphần đó và chạy nó. Nếu không, bạn có thể bình tĩnh làm nổi bật ROLLBACKphần đó và chạy phần đó. Bạn thậm chí có thể sử dụng các bổ trợ như Gói công cụ SSMS để chỉnh sửa New Querymẫu của mình để bao gồm bản tóm tắt đó.

Bây giờ nó vẫn có thể khiến bạn gặp rắc rối trong trường hợp bạn chạy truy vấn và sau đó không cam kết hoặc quay lại, vì bây giờ giao dịch của bạn đang chặn người dùng khác. Nhưng điều này là tốt hơn sau đó sửa đổi dữ liệu không thể thay đổi.

Và tất nhiên, như mọi khi, có một bản sao lưu mà bạn có thể dựa vào.


5
Đây là lời khuyên tuyệt vời và giải quyết tận gốc vấn đề của OP, nhưng nó không thực sự trả lời câu hỏi liệu truy vấn có tiếp tục chạy hay không.
Nick Chammas

3
Cảm ơn @Nick, động lực của tôi là giải quyết nguyên nhân (gây ra câu hỏi), không phải là triệu chứng, nhưng tôi đã cập nhật câu trả lời của mình.
Aaron Bertrand

8

@Aaron đúng rồi. Tạo một giao dịch trước các lệnh của bạn là đặt cược tốt nhất của bạn. Nếu bạn không thể nhớ làm điều đó thì một tùy chọn là vào phần Tools-Optionscài đặt và bật SET IMPLICIT_TRANSACTIONS. Điều này sẽ tự động bắt đầu một giao dịch ngay khi các lệnh nhất định được chạy. Điều này bao gồm UPDATE, DELETEv.v ... Đây dường như là một danh sách khá đầy đủ của bất kỳ lệnh nào "change". SELECTcũng được bao gồm trong danh sách và willbắt đầu một giao dịch. Bạn có thể thấy một danh sách đầy đủ các lệnh bắt đầu giao dịch sẽ cài đặt này ở đây . Nó sẽ không tạo ra một giao dịch nếu một giao dịch đã được bắt đầu. Bây giờ mặt trái của vấn đề này là bạn sẽ phải nhớ COMMITsau khi có bất kỳ thay đổi nào.

LƯU Ý: Dựa trên đề xuất của @ Aaron, tôi sẽ nhấn mạnh lại điều này.

This is very important!  You will have to remember to COMMIT after any change made!

Về cơ bản, bạn đang giao dịch mà quên mất BEGINmột giao dịch và làm hỏng một cái gì đó, vì đã quên COMMITmột giao dịch và bị treo nếu bạn để nó mở và sau đó để lại trong ngày. Tôi đã kiểm tra chỉ đóng một cửa sổ truy vấn với suy nghĩ nó sẽ phục hồi giao dịch của tôi, tuy nhiên nó đã nhắc tôi nếu tôi muốn cam kết hoặc phục hồi giao dịch.

nhập mô tả hình ảnh ở đây


Trên thực tế: SELECT sẽ bắt đầu một giao dịch (cũng được ghi lại trong liên kết bạn đã đăng)
a_horse_with_no_name

Cảm ơn @a_horse_with_no_name vì đã nắm bắt được điều đó! Tôi đã không đọc đủ cẩn thận và đã hết một ký ức cũ (điều đó rõ ràng là sai).
Kenneth Fisher

1
Đây là một bài viết hữu ích, nhưng nó không thực sự trả lời câu hỏi của OP về việc liệu truy vấn có tiếp tục chạy hay không.
Nick Chammas

2
Nó có nghĩa như là một bổ sung cho câu trả lời của @ Aaron. Nó chỉ là nhiều để đưa vào một bình luận.
Kenneth Fisher

2

tôi nghĩ rằng nó thực sự phụ thuộc:

nếu lệnh đã đến máy chủ trước khi bạn rút cáp mạng, lệnh vẫn sẽ tiếp tục thực thi bình thường.

nếu bạn có một Giao dịch viên (được sử dụng trong .Net, không chắc chắn các ngôn ngữ khác) để đóng gói tất cả các lệnh cập nhật, bạn có thể chỉ dừng giao dịch được cam kết nếu giao dịchScope.Complete () chưa được thực thi, nhưng không đảm bảo .. .


2
Bạn nói "nếu lệnh đã đến máy chủ trước khi bạn rút cáp mạng, lệnh vẫn sẽ tiếp tục thực thi bình thường." Điều này mâu thuẫn với trang BOL của SQL Server mà Martin đã liên kết ở trên. Xem "Lỗi trong quá trình xử lý giao dịch" .
Nick Chammas

bạn đúng rồi. với một giao dịch được chỉ định, lệnh sẽ tự động quay lại. nhưng như chúng tôi đã trải nghiệm, khi không có giao dịch nào được chỉ định rõ ràng, lệnh (cập nhật hàng loạt không có giao dịch) đã được thực thi hoàn toàn ngay cả khi chúng tôi dừng ứng dụng của mình ở giữa, điều này thực sự đã phá vỡ kết nối - nhưng đó không thực sự là một ví dụ tốt như thời gian có lẽ không đúng có lẽ thật tốt khi thực hiện một số thử nghiệm cho điều đó
Rex
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.