Hai rollback SQL Server này khác nhau như thế nào?


13

Trong SQL Server 2008 R2, hai rollback này khác nhau như thế nào:

  1. Chạy một ALTERcâu lệnh, trong vài phút, rồi nhấn 'Hủy thực thi'. Phải mất một vài phút để hoàn nguyên.

  2. Chạy cùng một ALTERcâu lệnh, nhưng điều này đảm bảo rằng LDFtệp không đủ lớn để hoàn thành thành công. Khi LDFgiới hạn được đáp ứng và không cho phép 'tự động phát triển', việc thực hiện truy vấn sẽ dừng ngay lập tức (hoặc xảy ra sự quay ngược lại) với thông báo lỗi này:

The statement has been terminated.
Msg 9002, Level 17, State 4, Line 1
The transaction log for database 'SampleDB' is full. 
To find out why space in the log cannot be reused, see the 
log_reuse_wait_desc column in sys.databases

Làm thế nào là hai khác nhau về các điểm sau đây?

  1. Tại sao 'rollback' thứ hai tức thời? Tôi không hoàn toàn chắc chắn nếu nó có thể được gọi là rollback. Tôi đoán là, nhật ký giao dịch được viết khi quá trình thực thi diễn ra và một khi nhận ra rằng không có đủ không gian để hoàn thành nhiệm vụ, nó chỉ dừng lại với một số thông báo 'kết thúc', không có cam kết.

  2. Điều gì xảy ra khi rollback đầu tiên mất quá nhiều thời gian (là một rollback đơn luồng)?
    2.1. SQL Server có quay lại và hoàn tác các mục được tạo trong LDFtệp không?
    2.2. Các LDFkích thước tập tin được nhỏ hơn ở phần cuối của rollback (từ DBCC SQLPERF(LOGSPACE))

  3. Thêm một câu hỏi: Trong kịch bản thứ hai, SQL Server bắt đầu tiêu thụ LDFtệp khá nhanh. Trong trường hợp của tôi, nó đã tăng từ mức sử dụng 18% lên 90% trong vài phút đầu (<4 phút). Nhưng một khi nó đạt 99%, nó ở đó thêm 8 phút nữa, trong khi dao động sử dụng từ 99,1% đến 99,8%. Nó tăng (99,8%) và xuống (99,2%) và tăng trở lại (99,7%) và giảm (99,5%) một vài lần trước khi lỗi được đưa ra. Điều gì đang xảy ra đằng sau hậu trường?

Bất kỳ liên kết MSDN nào có thể giúp giải thích điều này nhiều hơn đều được đánh giá cao.

Theo đề nghị của Ali Razeghi, tôi đang thêm perfmon: Disk Bytes/sec

Cảnh 1:

cảnh 1

Kịch bản 2:

Kịch bản 2


Chỉ cần một nhận xét nhanh: kích thước tệp! = Không gian được sử dụng trong một tệp.
Aaron Bertrand

@Aaron Vâng, tôi quen với điều đó. Tôi đã sử dụng DBCC SQLPERF (LOGSPACE) để đo lường mức độ sử dụng. Tệp LDF giữ nguyên trong toàn bộ thời lượng, vì tôi đã giới hạn kích thước tệp ở mức 10 GB. Việc sử dụng nội bộ khác nhau.
ToC

1
Tôi nghi ngờ rằng rollback thứ hai xuất hiện tức thời, bởi vì lỗi được báo cáo sau khi rollback hoàn thành. Đây có lẽ là 8 phút mà bạn quan sát được trong 3., trong đó việc sử dụng LDF vẫn không đổi.
mustaccio

@mustaccio Tôi đồng ý với bạn nhưng các hiện vật đang chỉ theo hướng khác nhau. Nếu trong thực tế, việc khôi phục đã xảy ra, thì việc sử dụng tệp nhật ký phải trở lại một số nhỏ hơn; và không giữ ở mức 99,3% khi thông báo lỗi được ném.
ToC

1
Tôi tin rằng rollback mất không gian đăng nhập. Khi nhật ký đầy đủ trong quá trình khôi phục, DB trở nên nghi ngờ. Nó không được chạm vào nữa. Điều này trông giống như rollback tức thời nhưng rollback đã bị hoãn lại cho đến khi bạn có thể đưa cơ sở dữ liệu trở lại trực tuyến (khi có sẵn dung lượng đĩa).; Ngoài ra, khi nhật ký đầy đủ, SQL Server có thể cố gắng tạo khoảng trống bằng cách kiểm tra điểm có thể giải thích các đột biến trong hoạt động IO.
usr

Câu trả lời:


1

Như đã chỉ ra ở trên, sau khi chạy thử nghiệm nhiều hơn, tôi đã đi đến một kết luận được tính toán. Tôi đã tóm tắt tất cả chúng vào một bài đăng trên blog ở đây , nhưng tôi sẽ sao chép một số nội dung sang bài đăng này cho hậu thế.

Phỏng đoán (dựa trên một số bài kiểm tra)

Đến bây giờ, tôi không có một lời giải thích rõ ràng về lý do tại sao điều này là. Nhưng sau đây là những ước tính của tôi dựa trên những cổ vật thu thập được trong các bài kiểm tra.

Rollback xảy ra trong cả hai kịch bản. Một là rollback rõ ràng (người dùng nhấn nút Hủy), cái còn lại là ẩn (Máy chủ Sql đưa ra quyết định đó trong nội bộ).

Trong cả hai trường hợp, lưu lượng truy cập vào tệp nhật ký là nhất quán. Xem hình ảnh dưới đây:

Cảnh 1:

Cảnh 1:

Kịch bản 2:

Kịch bản 2

  • Một vật phẩm đã củng cố dòng suy nghĩ này là bắt giữ Sql Trace trong cả hai kịch bản.

    • Kịch bản 1 là hiển nhiên aka khi chúng ta nhấn 'Hủy', nó quay lại.
    • Trong Kịch bản 2, thông báo lỗi được hiển thị sau khi thực hiện 'rollback' hoàn toàn. Trong Sql Trace, chúng ta thấy thông báo lỗi. Nhật ký giao dịch cho cơ sở dữ liệu 'SampleDB' đã đầy đủ một thời gian dài trước khi thông báo được hiển thị trên màn hình. Vì vậy, tôi đoán là việc rollback xảy ra trong cả hai trường hợp, nhưng thông báo lỗi là Kịch bản 2 được hiển thị sau khi thực hiện thành công và hoàn thành việc khôi phục.
  • Kịch bản 2 dường như mất nhiều thời gian hơn vì nó tiến triển xa hơn nhiều, do đó, việc quay lại mất nhiều thời gian hơn.

Hành vi không giải thích được:

  • Tại sao việc sử dụng tệp nhật ký khác nhau rất nhiều?
    • Nó tăng lên 90%, sau đó giảm xuống 85%, sau đó lên tới 99% và dao động ở đó trong một thời gian dài. Tôi thấy nó đi lên và xuống như thế này nhiều lần: 99,2%, 99,8%, 99,1%, 99,7%. Lý do tại sao điều này xảy ra?
    • Một lời giải thích có thể là, có thể có một quá trình nền (giống như Log Flush) để dọn sạch tệp nhật ký cứ sau vài phút. Và mỗi khi nó khởi động, một số mục sẽ bị xóa, dẫn đến có nhiều không gian trống hơn.

Mọi ý tưởng để giúp giải thích hành vi này theo cách tốt hơn đều được hoan nghênh.


2
Kiểm tra với Paul Randal, ông xác nhận rằng bạn đã đi đến kết luận chính xác - rollback là như nhau trong cả hai trường hợp.
Paul White 9

0

Tôi đã thử thí nghiệm sau và nhận được kết quả tương tự. Trong cả hai trường hợp, fn_dblog () hiển thị rollback xảy ra và dường như xảy ra nhanh hơn trong Kịch bản 2 so với Kịch bản 1.

Nhân tiện, tôi đã đặt cả MDF và LDF trên cùng một đĩa ngoài (USB 2.0).

Kết luận ban đầu của tôi là không có sự khác biệt trong hoạt động của rollback trong trường hợp này và có lẽ bất kỳ sự khác biệt tốc độ rõ ràng nào là liên quan đến hệ thống con I / O. Đó chỉ là giả thuyết làm việc của tôi vào lúc này.

Cảnh 1:

  • Tạo cơ sở dữ liệu với tệp nhật ký bắt đầu ở mức 1MB, tăng theo 4 MB và có kích thước tối đa 100 MB.
  • Mở một giao dịch rõ ràng, chạy nó trong 10 giây và sau đó hủy thủ công trong SSMS
  • Nhìn vào số lượng fn_dblog () và kích thước dự trữ nhật ký và kiểm tra DBCC SQLPERF (LOGSPACE)

Kịch bản 2:

  • Tạo cơ sở dữ liệu với tệp nhật ký bắt đầu ở mức 1MB, tăng theo 4 MB và có kích thước tối đa 100 MB.
  • Mở một giao dịch rõ ràng, chạy nó cho đến khi nhật ký đầy lỗi xuất hiện
  • Nhìn vào số lượng fn_dblog () và kích thước dự trữ nhật ký và kiểm tra DBCC SQLPERF (LOGSPACE)

Kết quả giám sát hiệu suất:

Cảnh 1: ***Cảnh 1***

Kịch bản 2: *** Kịch bản 2 ***

Mã số:

SỬ DỤNG [chủ];
ĐI

NẾU DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
BẮT ĐẦU
    THAY ĐỔI CƠ SỞ [SampleDB] SET SINGLE_USER
        VỚI ROLLBACK NGAY LẬP TỨC;
    DROP DATABASE [SampleDB];
KẾT THÚC;
ĐI

TẠO cơ sở dữ liệu [SampleDB] TRÊN CHÍNH 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , KÍCH THƯỚC = 3MB 
    , TÀI LIỆU = 1MB 
)
ĐĂNG NHẬP 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , KÍCH THƯỚC = 1MB 
    , TỐI ĐA = 100MB 
    , TÀI KHOẢN = 4MB 
);
ĐI

SỬ DỤNG [SampleDB];
ĐI

- Thêm một bảng
TẠO BẢNG dbo.test
(
    c1 CHAR (8000) KHÔNG PHẢI TRẢ LẠI ('a', 8000)
) TRÊN [CHÍNH HÃNG];
ĐI

- Đảm bảo rằng chúng tôi không phải là mô hình phục hồi giả đơn giản
BACKUP DATABASE SampleDB
ĐẾN DISK = 'NUL';
ĐI

- Sao lưu tệp nhật ký
BACKUP LOG SampleDB
ĐẾN DISK = 'NUL';
ĐI

- Kiểm tra không gian nhật ký đã sử dụng
DBCC SQLPERF (LOGSPACE);
ĐI

- Có bao nhiêu bản ghi được hiển thị với fn_dblog ()?
CHỌN * TỪ fn_dblog (NULL, NULL); - Khoảng 9 trong trường hợp của tôi

/ ****** / 4/8/4/4/4
             CẢNH 1
****** / TÌM KIẾM
- Mở một giao dịch mới và sau đó cuộn lại
BEGIN GIAO DỊCH

    XÁC NHẬN VÀO GIÁ TRỊ DEFAULT Dbo.test;
    GO 10000 - Hãy chạy trong 10 giây và sau đó nhấn hủy trong cửa sổ truy vấn SSMS

    - Hủy giao dịch
    - Sẽ mất vài giây để hoàn thành


- Không cần phải quay lại giao dịch, vì việc hủy đã làm điều đó cho bạn.
-- Hãy thử nó. Bạn sẽ gặp lỗi này
- Msg 3903, Cấp 16, Bang 1, Dòng 1
- Yêu cầu GIAO DỊCH ROLLBACK không có GIAO DỊCH BEGIN tương ứng.
GIAO DỊCH ROLLBACK;

- Không gian đăng nhập được sử dụng là gì? Trên 100%.
DBCC SQLPERF (LOGSPACE);
ĐI

- Có bao nhiêu bản ghi được hiển thị với fn_dblog ()?
LỰA CHỌN * 
TỪ fn_dblog (NULL, NULL); - Khoảng 91.926 trong trường hợp của tôi

- Tổng dự trữ nhật ký được hiển thị bởi fn_dblog ()?
CHỌN SUM ([Dự trữ nhật ký]) NHƯ [Tổng dự trữ nhật ký]
TỪ fn_dblog (NULL, NULL); - Khoảng 88,72MB


/ ****** / 4/8/4/4/4
             PHONG CÁCH 2
****** / TÌM KIẾM
- Thổi bay DB và bắt đầu lại
SỬ DỤNG [chủ];
ĐI

NẾU DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
BẮT ĐẦU
    THAY ĐỔI CƠ SỞ [SampleDB] SET SINGLE_USER
        VỚI ROLLBACK NGAY LẬP TỨC;
    DROP DATABASE [SampleDB];
KẾT THÚC;
ĐI

TẠO cơ sở dữ liệu [SampleDB] TRÊN CHÍNH 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , KÍCH THƯỚC = 3MB 
    , TÀI LIỆU = 1MB 
)
ĐĂNG NHẬP 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , KÍCH THƯỚC = 1MB 
    , TỐI ĐA = 100MB 
    , TÀI KHOẢN = 4MB 
);
ĐI

SỬ DỤNG [SampleDB];
ĐI

- Thêm một bảng
TẠO BẢNG dbo.test
(
    c1 CHAR (8000) KHÔNG PHẢI TRẢ LẠI ('a', 8000)
) TRÊN [CHÍNH HÃNG];
ĐI

- Đảm bảo rằng chúng tôi không phải là mô hình phục hồi giả đơn giản
BACKUP DATABASE SampleDB
ĐẾN DISK = 'NUL';
ĐI

- Sao lưu tệp nhật ký
BACKUP LOG SampleDB
ĐẾN DISK = 'NUL';
ĐI

- Bây giờ, hãy làm nổ tung tệp nhật ký trong giao dịch của chúng tôi
BEGIN GIAO DỊCH
    XÁC NHẬN VÀO GIÁ TRỊ DEFAULT Dbo.test;
    ĐI 10000

- Các rollback không bao giờ cháy. Thử nó. Bạn sẽ nhận được một lỗi.
- Msg 3903, Cấp 16, Bang 1, Dòng 1
- Yêu cầu GIAO DỊCH ROLLBACK không có GIAO DỊCH BEGIN tương ứng.
GIAO DỊCH ROLLBACK;

- Tệp nhật ký đã đầy đủ 100% chưa? 
DBCC SQLPERF (LOGSPACE);

- Có bao nhiêu bản ghi được hiển thị với fn_dblog ()?
LỰA CHỌN * 
TỪ fn_dblog (NULL, NULL); - Khoảng 91.926 trong trường hợp của tôi
ĐI

- Tổng dự trữ nhật ký được hiển thị bởi fn_dblog ()?
CHỌN SUM ([Dự trữ nhật ký]) NHƯ [Tổng dự trữ nhật ký]
TỪ fn_dblog (NULL, NULL); - 88,72 MB
ĐI

Cảm ơn bạn đã kiểm tra chi tiết. Sau khi chạy thử nghiệm nhiều hơn, tôi đã đi đến một kết luận tương tự. Vì vậy, tôi đã viết một bài đăng trên blog . Đối với tôi Kịch bản 2 mất nhiều thời gian hơn để quay lại vì số lượng công việc được thực hiện trong Kịch bản 2, trước khi Sql Server nhận ra nhu cầu quay lại nhiều hơn Kịch bản 1.
ToC
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.