ROLLBACK hızlı bir işlem mi?


Yanıtlar:


14

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ı:

  • Bul / güncelle için 5500 ms
  • 3 ms taahhüt
  • 1 ms geri alma

@ Satır = 100 ile:

  • 8500 ms bul / güncelle
  • 15 ms taahhüt
  • 15 ms geri alma

@ Satır = 1000 ile:

  • 15000 ms bul / güncelle
  • 10 ms taahhüt
  • 500 ms geri alma

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".


2
'daha az iş' mutlaka 'daha hızlı' olmak zorunda değildir
Jack Douglas

Bunun begin traniş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 ...)?
garik

3
Hayır, tüm işler taahhütten önce yapılır. Taahhüt işleminin kendisi nispeten azdır.
Mark Storey-Smith

@ Mark 2m satırlar ekleyerek ve ya işleyerek ya da geri dönerek bazı kaba ve hazır testler yaptım. Geri alma dahil toplam süre, taahhüt dahil toplam süre için 10 saniye ile 30 saniye arasında değişti. YMMV elbette ama bu, basketbol sahası geri dönüşünün en azından çevremdeki orijinal işlemden daha uzun veya daha uzun olduğunu gösteriyor.
Jack Douglas

2
Taahhüt işleminin tamamlanması için zamanı ölçecek olsaydınız, aynı anda bir kontrol noktası düzenlenmedikçe (ayrı ve ilgisiz) minimum olmasını beklerdim. Bu benim açımdan, taahhüt çok az şey yaparken geri alma, taahhütten önce olan her şeyi ve biraz daha fazlasını yapıyor. Testlerinizdeki varyans oyundaki diğer faktörleri de aşıyor, ancak daha sonra bazı senaryoları bir araya getirmeye çalışacağım.
Mark Storey-Smith

13

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ü

  1. İşlem geri alınırken kilit tutulmaz
  2. Düşük öncelikli bir arka plan işlemi tarafından ele alınır

SQL Server için durumun aynı olup olmadığından emin değilim ama başkası değilse ...

Gelince "neden", diyorum ki rollbackolmalı nadir bir şey gitti yanlış vardır ve tabii ki genellikle sadece eğer, commitonun için optimize etmek mantıklı - çok daha yaygın olması muhtemeldircommit


9

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).


2
Ve hepimiz bir noktada "geri almak çok uzun sürüyor, yeniden başlayalım" konuşmasını yaptık değil mi?
Mark Storey-Smith

Birçok müşterinin bunu yaptığını gördüm. Bazıları göreceli olarak zarar görmemiş, bazıları ise daha az şanslı.
Aaron Bertrand

1
@ MarkStorey-Smith - Geri alma işleminin ortasında yeniden başlatırsanız, SQL Server'ın başlatma sırasında geri dönmeye devam etmesi gerekmez mi?
Nick Chammas

2
@Buna bağlı - geri alma işlemi yeniden başlatmadan önce engellenmişse, hizmetin yeniden başlatılmasından sonra çok daha hızlı davranabilir, çünkü bu diğer işlem henüz öldürülmüş olabilir. Bu senaryoda bir sürü "ne olursa olsun" vardır - bir sunucuyu yeniden başlattığınızda veya bir sorunu "düzeltmek" için bir hizmeti yeniden başlattığınızda, muhtemelen oyunda çok daha ciddi sorunlar vardır.
Aaron Bertrand

2
@Nick, evet tam olarak böyle oluyor. Benim yorumum "yanaktaki dil" olarak tasarlandı, o kadar çok ki, kaçınılmaz olarak, bir şey beklendiği gibi davranmadığında yeniden başlatmak isteyen mutlu halk tetikleyicisine açıklamak zorunda kalıyorsunuz.
Mark Storey-Smith

8

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.


Belirli işlemlerin geri alma için nasıl optimize edildiğine iyi bir örnek.
Mark Storey-Smith

5

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).


İyi bir yanıt, ancak küçük bir kelime oyunu: "PostgreSQL için, tüm tablolar yığın tabloları ve dizinler ayrıdır. Bu, geri alma veya taahhütte bulunma sırasında hiçbir veri yeniden düzenlenmemesi gerektiği anlamına gelir" Bu, hiçbir verinin bunun yerine "Taahhütten daha yavaş geri dönen büyük db'ler veri taşıma eğilimindedir" ve pg belirttiğiniz gibi değildir. Oracle ayrıca yığın depolamayı varsayılan olarak kullanır: ana fark, Oracle'ın 'vakum' yoluna gitmek yerine 'geri al'ı kullanması ve kesin / geri almayla ilgili tüm alanı geri almasıdır.
Jack Douglas
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.