Yanıtlar:
SQL Server için, bir taahhüt işleminin günlük dosyasına LOP_COMMIT_XACT yazmak ve kilitleri serbest bırakmaktan başka bir şey olmadığını iddia edebilirsiniz, bu da elbette işleminizin BEGIN TRAN'dan bu yana gerçekleştirdiği her eylemin ROLLBACK'inden daha hızlı olacaktır.
Sadece bir işlemin değil, bir işlemin her eylemini düşünüyorsanız, beyanınızın hala doğru olmadığını iddia ediyorum. Harici faktörler hariç tutulursa, örneğin günlük diskinin veri disk hızına kıyasla hızı, bir işlem tarafından yapılan herhangi bir işin geri alınması, işi ilk etapta yapmaktan daha hızlı olacaktır.
Geri alma, değişikliklerin sıralı bir dosyasını okumak ve bunları bellek içi veri sayfalarına uygulamaktır. Orijinal "iş" bir yürütme planı oluşturmak, sayfaları edinmek, satırları birleştirmek vb.
Düzenleme: Biraz bağlıdır ...
@JackDouglas , geri almanın orijinal işlemden önemli ölçüde daha uzun sürebileceği durumlardan birini açıklayan bu makaleye dikkat çekti . Örnek, 14 saatlik bir işlemdir, kaçınılmaz olarak paralellik kullanarak geri dönüş çoğunlukla tek iş parçacıklı olduğundan 48 saatten fazla zaman alır. Büyük olasılıkla arabellek havuzunu tekrar tekrar çalkalayacaksınız, bu yüzden artık bellek içi sayfalarda değişiklikleri tersine çevirmiyorsunuz.
Yani, önceki cevabımın gözden geçirilmiş bir versiyonu. Geri alma ne kadar yavaştır? Tüm diğer şeyler dikkate alınır, tipik bir OLTP işlemi için değildir. Tipik sınırların dışında, "do" dan "geri almak" daha uzun sürebilir, ancak (bu potansiyel bir dil bükücüdür?) Neden "do" nun nasıl yapıldığına bağlı olacaktır.
Edit2: Yorumlarda tartışmanın ardından, burada yapılan işin işlem olarak geri alma ve geri alma göreceli masrafını belirlemede ana faktör olduğunu göstermek için çok tartışmalı bir örnek.
İki tablo oluşturun ve bunları yetersiz bir şekilde paketleyin (sayfa başına boşa harcanan alan):
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
"Kötü" bir güncelleştirme sorgusu çalıştırın ve işi yapmak için gereken zamanı ve taahhüdü yayınlamak için geçen zamanı ölçün.
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
Aynı şeyi tekrarlayın ama geri alma sorununu ölçün.
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
@ Rows = 1 ile oldukça tutarlı:
@ Satır = 100 ile:
@ Satır = 1000 ile:
Orijinal soruya geri dön. İşi yapmak için harcanan zamanı ve taahhüdü ölçüyorsanız geri alma eller aşağı kazanıyor çünkü bu işin büyük kısmı verileri değiştirmek için değil, güncellenecek satırı bulmak için harcanıyor. Taahhüt işlemine ayrı bir şekilde bakarsanız, taahhüdün çok az "işe yaradığı" açıktır. Taahhüt "işim bitti".
begin tran
işlem sayacını artırdığını biliyordum . Seni anladıysam, rdbms COMMIT'de tüm görevleri yapıyor (satırları birleştiriyor, yürütme planları oluşturuyor ...)?
Oracle için geri alma, geri dönen değişiklikleri yapmak için geçen süreden çok daha uzun sürebilir. Bu çoğu zaman önemli değil çünkü
SQL Server için durumun aynı olup olmadığından emin değilim ama başkası değilse ...
Gelince "neden", diyorum ki rollback
olmalı nadir bir şey gitti yanlış vardır ve tabii ki genellikle sadece eğer, commit
onun için optimize etmek mantıklı - çok daha yaygın olması muhtemeldircommit
Geri alma sadece "ah, boş ver" değildir - birçok durumda zaten yaptıklarını geri almak zorunda kalır. Geri alma işleminin her zaman orijinal işlemden daha yavaş veya her zaman daha hızlı olacağına dair bir kural yoktur, ancak orijinal işlem paralel koşsa bile, geri alma tek iş parçacıklıdır. Eğer bekliyorsanız, beklemeye devam etmenin en güvenli yol olduğunu öneririm.
Tüm bunlar SQL Server 2019 ve elbette Hızlandırılmış Veritabanı Kurtarma ile değişir (bu da değişken olan bir ceza ile veri boyutundan bağımsız olarak anında geri dönüşe izin verir).
Tüm işlemlerin taahhüt faaliyetlerinin geri dönüşlerinden çok daha iyi performans göstermesine neden olmaz. Böyle bir durum SQL'deki silme işlemidir. Bir işlem satırları sildiğinde, bu satırlar hayalet kayıtları olarak işaretlenir. Bir taahhüt verildiğinde ve bir hayalet kaydı temizleme görevi başladığında, yalnızca bu kayıtlar 'silinir'.
Bunun yerine bir geri alma yayınlandıysa, yoğun ekleme ifadelerini değil, yalnızca bu kayıtlardaki hayalet işaretlerini kaldırır.
Hepsi değil. İki işlemin disk G / Ç açısından etkili bir şekilde aynı olması nedeniyle PostgreSQL'in geri alınması daha fazla zaman almaz. Aslında bu bir diğer optimizasyon sorguları için bir soru olduğu gibi taahhüt için optimize edilmiş bir soru olduğunu sanmıyorum.
Temel soru, disk üzerindeki düzeni nasıl ele alacağınız ve bunun, kesin ve geri almayı nasıl etkilediğidir. İşlemeden daha yavaş geri dönen büyük db'ler, verileri özellikle kümelenmiş tablolardan ana veri yapılarının dışına taşıma ve verileri güncellerken geri alma segmentine koyma eğilimindedir. Bu, geri alma segmentini düşürmenizi sağlamak için geri dönmek için tüm verileri geri kopyalamanız gerektiği anlamına gelir.
PostgreSQL için tüm tablolar yığın tablolarıdır ve dizinler ayrıdır. Bu, geri dönerken veya işlem yaparken hiçbir verinin yeniden düzenlenmemesi gerektiği anlamına gelir. Bu, hem hızlı hem de geri alma işlemini kolaylaştırır.
Ancak, diğer bazı şeyleri biraz daha yavaş hale getirir. Birincil anahtar araması, örneğin, bir dizin dosyasını çaprazlamak zorundadır ve daha sonra yığın tablosuna (geçerli örtme dizinleri olmadığı varsayılarak) vurmak zorundadır. Bu büyük bir anlaşma değil, ancak başka bir bilgi ve görünürlük kontrol etmek için fazladan bir sayfa araması veya belki de birkaç rastgele sayfa araması (bu satırda çok sayıda güncelleme gerçekleşmişse) ekler.
Ancak buradaki hız, yazma işlemleri ve okuma işlemleri için PostgreSQL'de bir optimizasyon sorunu değildir. Bazı okuma işlemlerini diğerlerinden daha üstün kılmak istemez. Sonuç olarak PostgreSQL ortalama olarak diğer db'ler kadar iyi performans gösterir. Daha hızlı veya daha yavaş olabilen sadece belirli işlemlerdir.
Bu yüzden asıl cevap, db'lerin okuma tarafında belirli iş yükleri için optimize edilmiş olduğunu ve bu da yazma tarafında zorluklara yol açtığını düşünüyorum. Genellikle bir sorunun olduğu durumlarda, taahhütler her zaman olmasa da, genellikle geri dönüşlere tercih edilir. Ancak bu, ikisinden birini yapmanın sonuçlarına bağlıdır (güncellemeler silinmekten farklıdır).