Câu trả lời:
Đố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ý:
Với @ Hàng = 100:
Với @ Hàng = 1000:
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".
begin tran
chỉ 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?
Đố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ì
Đố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 rollback
này rất hiếm , thường chỉ khi có sự cố xảy ra và tất nhiên commit
có thể phổ biến hơn nhiều - vì vậy sẽ rất hợp lý để tối ưu hóa chocommit
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).
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.
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).