ROLLBACK có phải là một hoạt động nhanh chóng?


Câu trả lời:


14

Đối với SQL Server, bạn có thể lập luận rằng một thao tác cam kết không gì khác hơn là viết LOP_COMMIT_XACT vào tệp nhật ký và giải phóng các khóa, tất nhiên sẽ nhanh hơn ROLLBACK của mọi hành động mà giao dịch của bạn thực hiện kể từ BEGIN TRAN.

Nếu bạn đang xem xét mọi hành động của một giao dịch, không chỉ là cam kết, tôi vẫn cho rằng tuyên bố của bạn là không đúng sự thật. Ví dụ, không bao gồm các yếu tố bên ngoài, tốc độ của đĩa nhật ký so với tốc độ của đĩa dữ liệu, có thể việc khôi phục lại bất kỳ công việc nào được thực hiện bởi một giao dịch sẽ nhanh hơn so với thực hiện công việc ở nơi đầu tiên.

Một rollback đang đọc một tệp tuần tự các thay đổi và áp dụng chúng cho các trang dữ liệu trong bộ nhớ. "Công việc" ban đầu phải tạo ra một kế hoạch thực hiện, có được các trang, tham gia các hàng, v.v.

Chỉnh sửa: Nó phụ thuộc một chút ...

@JackDoumund đã chỉ ra bài viết này mô tả một trong những tình huống mà việc khôi phục có thể mất nhiều thời gian hơn so với hoạt động ban đầu. Ví dụ là một giao dịch 14 giờ, chắc chắn sử dụng song song, phải mất hơn 48 giờ để khôi phục vì rollback chủ yếu là một luồng. Rất có thể bạn cũng sẽ đảo lộn vùng đệm liên tục, do đó, bạn không còn đảo ngược các thay đổi đối với các trang trong bộ nhớ.

Vì vậy, một phiên bản sửa đổi của câu trả lời trước đó của tôi. Rollback chậm hơn bao nhiêu? Tất cả những thứ khác được xem xét, đối với một giao dịch OLTP điển hình thì không. Bên ngoài giới hạn điển hình, có thể mất nhiều thời gian để "hoàn tác" hơn "làm" nhưng (đây có phải là một twister lưỡi tiềm năng không?) Tại sao sẽ phụ thuộc vào cách "làm" được thực hiện.

Edit2: Sau khi thảo luận trong các bình luận, đây là một ví dụ rất dễ hiểu để chứng minh rằng công việc đang được thực hiện là yếu tố chính trong việc xác định chi phí tương đối của cam kết so với rollback khi hoạt động.

Tạo hai bảng và đóng gói chúng không hiệu quả (lãng phí không gian trên mỗi trang):

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
SET NOCOUNT ON;
GO

CREATE TABLE dbo.Foo
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)

CREATE TABLE dbo.Bar
(
    col1 INT IDENTITY(1,1) PRIMARY KEY CLUSTERED
    , col2 CHAR(4000) NOT NULL DEFAULT REPLICATE('A', 4000)
)
GO

INSERT dbo.Foo DEFAULT VALUES
GO 100000

INSERT dbo.Bar DEFAULT VALUES
GO 100000

Chạy một truy vấn cập nhật "xấu", đo thời gian thực hiện công việc và thời gian thực hiện cam kết.

DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

COMMIT TRANSACTION

SELECT 'Commit', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

Làm tương tự một lần nữa nhưng vấn đề và đo lường rollback.

    DECLARE 
    @StartTime DATETIME2
    , @Rows INT

SET @Rows = 1

CHECKPOINT
DBCC DROPCLEANBUFFERS

BEGIN TRANSACTION

SET @StartTime = SYSDATETIME()

UPDATE
    dbo.bar
SET
    col2 = REPLICATE('B', 4000)
FROM
    dbo.bar b
INNER JOIN
    (
    SELECT TOP(@Rows)
        col1
    FROM
        dbo.foo
    ORDER BY
        NEWID()
    ) f
ON  f.col1 = b.col1
OPTION (MAXDOP 1)

SELECT 'Find and update row', DATEDIFF(ms, @StartTime, SYSDATETIME())

SET @StartTime = SYSDATETIME()

ROLLBACK TRANSACTION

SELECT 'Rollback', DATEDIFF(ms, @StartTime, SYSDATETIME())
GO

Với @ Rows = 1 tôi có được sự nhất quán hợp lý:

  • 5500ms cho việc tìm / cập nhật
  • Cam kết 3ms
  • Quay lại 1ms

Với @ Hàng = 100:

  • 8500ms tìm / cập nhật
  • Cam kết 15ms
  • Phục hồi 15ms

Với @ Hàng = 1000:

  • Tìm kiếm / cập nhật 15000ms
  • Cam kết 10ms
  • Quay lại 500ms

Quay lại câu hỏi ban đầu. Nếu bạn đang đo thời gian thực hiện công việc cộng với cam kết, rollback sẽ chiến thắng vì phần lớn công việc đó được dành để tìm hàng để cập nhật, chứ không thực sự sửa đổi dữ liệu. Nếu bạn đang xem hoạt động cam kết một cách cô lập, thì rõ ràng cam kết thực hiện rất ít "công việc" như vậy. Cam kết là "Tôi đã hoàn thành".


2
'công việc ít hơn' không nhất thiết là 'nhanh hơn'
Jack Douglas

Tôi biết rằng begin tranchỉ cần tăng truy cập của các giao dịch. Nếu tôi hiểu bạn, rdbms đang thực hiện tất cả các nhiệm vụ (tham gia các hàng, tạo kế hoạch thực hiện ...) tại CAMIT?
garik

3
Không, tất cả các công việc được thực hiện trước khi cam kết. Các hoạt động cam kết bản thân nó tương đối ít.
Mark Storey-Smith

@Mark Tôi đã thực hiện một số thử nghiệm thô và sẵn sàng chèn 2m hàng và cam kết hoặc khôi phục. Tổng thời gian bao gồm cả rollback thay đổi từ 10 đến 30 giây, so với giữa 6s và 14 cho thời gian tổng thể bao gồm cả cam kết. YMMV tất nhiên nhưng điều này chỉ ra rằng rollback ballpark dài gần hoặc dài hơn giao dịch ban đầu ít nhất là trong môi trường của tôi.
Jack Douglas

2
Nếu bạn định đo thời gian để hoạt động cam kết hoàn thành, tôi sẽ mong đợi nó là tối thiểu trừ khi một điểm kiểm tra xảy ra cùng lúc (đó là riêng biệt và không liên quan). Đó là quan điểm của tôi, cam kết thực hiện rất ít trong khi rollback thực hiện mọi thứ xảy ra trước khi cam kết cộng thêm một chút. Sự khác biệt trong các bài kiểm tra của bạn có thể ảnh hưởng đến các yếu tố khác nhưng chắc chắn tôi sẽ thử và kết hợp một số tập lệnh sau.
Mark Storey-Smith

13

Đối với Oracle, rollback có thể mất nhiều thời gian hơn nhiều so với thời gian để thực hiện các thay đổi đang quay trở lại. Điều này thường không quan trọng bởi vì

  1. Không có khóa được giữ trong khi giao dịch được khôi phục
  2. Nó được xử lý bởi một quá trình nền ưu tiên thấp

Đối với SQL Server, tôi không chắc tình huống có giống như vậy không nhưng người khác sẽ nói nếu không ...

Đối với "tại sao", tôi muốn nói rằng điều rollbacknày rất hiếm , thường chỉ khi có sự cố xảy ra và tất nhiên commitcó thể phổ biến hơn nhiều - vì vậy sẽ rất hợp lý để tối ưu hóa chocommit


9

Rollback không chỉ là "oh, đừng bận tâm" - trong rất nhiều trường hợp, nó thực sự phải hoàn tác những gì nó đã làm. Không có quy tắc nào rằng hoạt động rollback sẽ luôn chậm hơn hoặc luôn luôn nhanh hơn hoạt động ban đầu, mặc dù ngay cả khi giao dịch ban đầu chạy song song, rollback chỉ là một luồng. Nếu bạn đang chờ đợi, tôi đề nghị an toàn nhất là cứ tiếp tục chờ đợi.

Tất cả điều này thay đổi với SQL Server 2019, tất nhiên và Phục hồi cơ sở dữ liệu được tăng tốc (với mức phạt cũng có thể thay đổi, cho phép khôi phục tức thời bất kể kích thước của dữ liệu).


2
Và tất cả chúng ta đều đã có cuộc trò chuyện "mất nhiều thời gian để quay lại, hãy khởi động lại nó" vào một lúc nào đó phải không?
Mark Storey-Smith

Tôi đã thấy nhiều khách hàng làm điều đó. Một số đi ra tương đối vô tư, những người khác kém may mắn hơn nhiều.
Aaron Bertrand

1
@ MarkStorey-Smith - Nếu bạn khởi động lại mid-rollback, SQL Server không phải tiếp tục khôi phục khi khởi động chứ?
Nick Chammas

2
@Nick điều đó phụ thuộc - ví dụ, nếu rollback bị chặn trước khi khởi động lại, chẳng hạn, nó có thể hoạt động nhanh hơn rất nhiều sau khi khởi động lại dịch vụ vì quá trình khác vừa bị giết. Có rất nhiều "chuyện gì xảy ra" trong kịch bản này - bất cứ khi nào bạn khởi động lại máy chủ hoặc khởi động lại dịch vụ để "khắc phục" sự cố, có thể có một số vấn đề nghiêm trọng hơn khi chơi.
Aaron Bertrand

2
@Nick, vâng, đó chính xác là những gì xảy ra. Nhận xét của tôi được dự định là "tặc lưỡi", đến mức chắc chắn cuối cùng bạn phải giải thích rằng với người dân vui mừng muốn kích hoạt lại bất cứ khi nào có hành vi như mong đợi.
Mark Storey-Smith

8

Không phải tất cả các giao dịch sẽ có hoạt động cam kết của họ thực hiện tốt hơn nhiều so với rollback của họ. Một trường hợp như vậy là thao tác xóa trong SQL. Khi một giao dịch xóa các hàng, các hàng này được đánh dấu là bản ghi ma. Khi một cam kết được ban hành và một nhiệm vụ dọn dẹp hồ sơ ma bắt đầu, thì chỉ những hồ sơ này mới bị 'xóa'.

Nếu một rollback được ban hành thay vào đó, nó chỉ xóa các dấu ma khỏi các bản ghi này, chứ không phải các câu lệnh chèn chuyên sâu.


Ví dụ tốt về cách các hoạt động nhất định được tối ưu hóa cho rollback.
Mark Storey-Smith

5

Không phải tất cả là. PostgreSQL không mất nhiều thời gian để quay lại hơn là cam kết vì hai hoạt động giống hệt nhau về mặt I / O của đĩa. Tôi thực sự không nghĩ rằng đây là một câu hỏi về việc được tối ưu hóa cho cam kết nhiều như vậy là câu hỏi về những truy vấn khác mà người ta đang tối ưu hóa.

Câu hỏi cơ bản là cách bạn giải quyết bố cục trên đĩa và cách điều này ảnh hưởng đến cam kết so với rollback. Các db chính quay trở lại chậm hơn so với cam kết có xu hướng di chuyển dữ liệu, đặc biệt là từ các bảng được nhóm, ra khỏi các cấu trúc dữ liệu chính và đưa nó vào phân đoạn rollback khi cập nhật dữ liệu. Điều này có nghĩa là để cam kết bạn chỉ cần bỏ phân đoạn rollback nhưng để quay lại, bạn phải sao chép tất cả dữ liệu trở lại.

Đối với PostgreSQL, tất cả các bảng là bảng heap và các chỉ mục là riêng biệt. Điều này có nghĩa là khi quay lại hoặc cam kết, không có dữ liệu nào phải được sắp xếp lại. Điều này làm cho cam kết và rollback cả nhanh.

Tuy nhiên, nó làm cho một số thứ khác chậm hơn một chút. Ví dụ, một tra cứu khóa chính phải duyệt qua một tệp chỉ mục và sau đó nó phải nhấn vào bảng heap (giả sử không có chỉ mục bao trùm nào được áp dụng). Đây không phải là một vấn đề lớn nhưng nó có thêm một tra cứu trang bổ sung hoặc thậm chí một vài lần tra cứu trang ngẫu nhiên (nếu có nhiều cập nhật xảy ra trên hàng đó) để kiểm tra thông tin và mức độ hiển thị khác.

Tuy nhiên, tốc độ ở đây không phải là một câu hỏi về tối ưu hóa trong PostgreSQL đối với các thao tác ghi so với các thao tác đọc. Đó là một sự không sẵn lòng để đặc quyền một số hoạt động đọc trên những người khác. Do đó, PostgreSQL hoạt động trung bình cũng như các db khác. Nó chỉ là hoạt động nhất định có thể nhanh hơn hoặc chậm hơn.

Vì vậy, tôi nghĩ rằng câu trả lời thực tế là db được tối ưu hóa cho khối lượng công việc nhất định ở phía đọc và điều này dẫn đến những thách thức ở phía viết. Thông thường, nơi có một câu hỏi, các cam kết thường, mặc dù không phải lúc nào cũng sẽ được ưa chuộng hơn các lần quay lại. Tuy nhiên, điều này phụ thuộc vào ý nghĩa của việc thực hiện một trong hai (cập nhật khác với xóa).


Câu trả lời hay, nhưng có một ngụy biện nhỏ: "Đối với PostgreSQL, tất cả các bảng là bảng heap và chỉ mục là riêng biệt. Điều này có nghĩa là khi quay lại hoặc cam kết, không có dữ liệu nào phải được sắp xếp lại" đây không phải là lý do mà không có dữ liệu nào phải được sắp xếp lại, thay vào đó là vì "Các db chính quay trở lại chậm hơn so với cam kết có xu hướng di chuyển dữ liệu" và pg thì không, như bạn đã đề cập. Oracle cũng mặc định để lưu trữ heap: sự khác biệt chính là Oracle sử dụng 'hoàn tác' và lấy lại tất cả không gian trên cam kết / rollback thay vì đi theo lộ trình 'chân không'.
Jack Douglas
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.