Jawaban:
Untuk SQL Server, Anda dapat berargumen bahwa operasi komit tidak lebih dari menulis LOP_COMMIT_XACT ke file log dan melepaskan kunci, yang tentu saja akan lebih cepat daripada ROLLBACK dari setiap tindakan yang dilakukan transaksi Anda sejak BEGIN TRAN.
Jika Anda mempertimbangkan setiap tindakan transaksi, bukan hanya komitmen, saya masih berpendapat bahwa pernyataan Anda tidak benar. Tidak termasuk faktor eksternal, kecepatan log disk dibandingkan dengan kecepatan disk data misalnya, kemungkinan rollback dari setiap pekerjaan yang dilakukan oleh transaksi akan lebih cepat daripada melakukan pekerjaan di tempat pertama.
Kembalikan adalah membaca file perubahan berurutan dan menerapkannya ke halaman data dalam memori. "Karya" asli harus membuat rencana eksekusi, memperoleh halaman, bergabung dengan baris, dll.
Edit: Itu tergantung sedikit ...
@JackDouglas menunjuk ke artikel ini yang menjelaskan salah satu situasi di mana rollback dapat memakan waktu lebih lama dari operasi aslinya. Contohnya adalah transaksi 14 jam, mau tidak mau menggunakan paralelisme, yang membutuhkan 48+ jam untuk rollback karena rollback kebanyakan single threaded. Kemungkinan besar Anda juga akan mengaduk kumpulan buffer berulang kali, jadi Anda tidak lagi membalikkan perubahan pada halaman dalam memori.
Jadi, versi revisi dari jawaban saya sebelumnya. Berapa lambatnya rollback? Semua hal lain dipertimbangkan, untuk transaksi OLTP tipikal tidak. Di luar batas khas, mungkin perlu waktu lebih lama untuk "membatalkan" daripada "lakukan" tetapi (apakah ini potensi twister lidah?) Mengapa akan tergantung pada bagaimana "lakukan" itu dilakukan.
Sunting2: Sebagai lanjutan dari diskusi dalam komentar, berikut adalah contoh yang sangat dibuat untuk menunjukkan bahwa pekerjaan yang dilakukan adalah faktor utama dalam menentukan biaya relatif dari komitmen vs kembalikan sebagai operasi.
Buat dua tabel dan kemas dengan tidak efisien (ruang kosong per halaman):
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
Jalankan kueri pembaruan "buruk", mengukur waktu yang diperlukan untuk melakukan pekerjaan dan waktu yang dibutuhkan untuk mengeluarkan komit.
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
Lakukan hal yang sama lagi tetapi keluarkan dan ukur 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
Dengan @ Rows = 1 saya mendapatkan yang cukup konsisten:
Dengan @ Baris = 100:
Dengan @ Baris = 1000:
Kembali ke pertanyaan awal. Jika Anda mengukur waktu yang diperlukan untuk melakukan pekerjaan ditambah komit, rollback menang dengan mudah karena sebagian besar pekerjaan itu dihabiskan untuk menemukan baris yang akan diperbarui, tidak benar-benar mengubah data. Jika Anda melihat operasi komit dalam isolasi, harus jelas bahwa komit sangat sedikit "berfungsi" seperti itu. Komit adalah "Saya sudah selesai".
begin tran
hanya meningkatkan konter transaksi. Jika saya mengerti Anda, rdbms melakukan semua tugas (bergabung dengan baris, membuat rencana eksekusi ...) di COMMIT?
Untuk Oracle, rollback dapat memakan waktu beberapa kali lebih lama daripada waktu yang dibutuhkan untuk melakukan perubahan yang bergulir kembali. Ini sering tidak masalah karena
Untuk SQL Server saya tidak yakin apakah situasinya sama tetapi orang lain akan mengatakan jika tidak ...
Adapun "mengapa", saya akan mengatakan itu rollback
harus langka , biasanya hanya jika ada kesalahan, dan tentu saja commit
mungkin lebih umum - jadi masuk akal untuk mengoptimalkancommit
Kembalikan bukan hanya "oh, tidak apa-apa" - dalam banyak kasus itu benar-benar harus membatalkan apa yang sudah dilakukan. Tidak ada aturan bahwa operasi rollback akan selalu lebih lambat atau selalu lebih cepat dari operasi asli, meskipun bahkan jika transaksi asli berjalan secara paralel, rollback tersebut adalah single-threaded. Jika Anda menunggu, saya sarankan paling aman untuk tetap menunggu.
Ini semua berubah dengan SQL Server 2019, tentu saja, dan Pemulihan Basis Data yang Dipercepat (yang, pada penalti yang juga variabel, memungkinkan untuk mengembalikan secara instan terlepas dari ukuran data).
Tidak semua transaksi memiliki aktivitas komit yang berkinerja lebih baik daripada kemunduran mereka. Salah satu kasusnya adalah operasi hapus dalam SQL. Ketika transaksi menghapus baris, baris ini ditandai sebagai catatan hantu. Setelah komit dikeluarkan dan tugas pembersihan catatan hantu dimulai, maka hanya catatan ini yang 'dihapus'.
Jika rollback dikeluarkan sebagai gantinya, itu hanya menghilangkan tanda hantu dari catatan ini, dan bukan pernyataan menyisipkan intensif.
Tidak semuanya. PostgreSQL tidak membutuhkan waktu lebih lama untuk mundur daripada melakukan komitmen karena kedua operasi ini secara identik identik dalam hal disk I / O. Saya tidak benar-benar berpikir ini adalah pertanyaan tentang dioptimalkan untuk melakukan begitu banyak karena ini adalah pertanyaan tentang apa pertanyaan lain yang mengoptimalkan untuk.
Pertanyaan dasar adalah bagaimana Anda mengatasi tata letak pada-disk dan bagaimana ini mempengaruhi komit vs rollback. Db utama yang memutar kembali lebih lambat daripada melakukan cenderung memindahkan data, terutama dari tabel berkerumun, keluar dari struktur data utama dan memasukkannya ke dalam segmen rollback ketika memperbarui data. Ini berarti bahwa untuk mengkomit Anda hanya menjatuhkan segmen rollback tetapi untuk memutar kembali Anda harus menyalin semua data kembali.
Untuk PostgreSQL, semua tabel adalah heap tables dan indeks terpisah. Ini berarti bahwa ketika memutar kembali atau melakukan, tidak ada data yang harus diatur ulang. Ini membuat komit dan kembalikan keduanya cepat.
Namun, itu membuat beberapa hal lain sedikit lebih lambat. Pencarian kunci utama misalnya, harus melintasi file indeks dan kemudian harus mengenai tabel tumpukan (dengan asumsi tidak ada indeks penutup yang berlaku). Ini bukan masalah besar tetapi hal itu menambah pencarian halaman tambahan atau bahkan mungkin beberapa pencarian halaman acak (jika banyak pembaruan telah terjadi pada baris itu) untuk memeriksa informasi dan visibilitas lainnya.
Namun kecepatan di sini bukan masalah optimasi di PostgreSQL untuk operasi tulis vs yang dibaca. Ini adalah keengganan untuk mengistimewakan beberapa operasi baca di atas yang lain. Akibatnya PostgreSQL melakukan rata-rata tentang serta db lain. Hanya operasi tertentu yang mungkin lebih cepat atau lebih lambat.
Jadi saya pikir jawaban sebenarnya adalah bahwa db dioptimalkan untuk beban kerja tertentu di sisi baca dan ini mengarah pada tantangan di sisi tulis. Biasanya di mana ada pertanyaan, komit biasanya, meskipun tidak selalu, akan lebih disukai daripada kemunduran. Namun ini tergantung pada implikasi dari melakukan keduanya (pembaruan berbeda dari yang dihapus).