Bagaimana dua rollback SQL Server ini berbeda?

13

Dalam SQL Server 2008 R2, bagaimana dua kemunduran ini berbeda:

  1. Jalankan ALTERpernyataan, selama beberapa menit, lalu tekan 'Batalkan Pelaksana'. Butuh beberapa menit untuk mengembalikan sepenuhnya.

  2. Jalankan ALTERpernyataan yang sama , tetapi ini memastikan bahwa LDFfile tidak cukup besar untuk menyelesaikannya dengan sukses. Setelah LDFbatas dipenuhi dan tidak ada 'autogrowth' diperbolehkan, eksekusi permintaan segera berhenti (atau rollback terjadi) dengan pesan kesalahan ini:

The statement has been terminated.
Msg 9002, Level 17, State 4, Line 1
The transaction log for database 'SampleDB' is full. 
To find out why space in the log cannot be reused, see the 
log_reuse_wait_desc column in sys.databases

Bagaimana kedua hal ini berbeda pada poin-poin berikut?

  1. Mengapa 'kembalikan' kedua itu terjadi secara instan? Saya tidak sepenuhnya yakin apakah itu bisa disebut rollback. Dugaan saya adalah, log transaksi ditulis sebagai eksekusi berlangsung dan setelah menyadari bahwa tidak ada cukup ruang untuk menyelesaikan tugas, itu hanya berhenti dengan beberapa pesan 'akhir', tanpa komit.

  2. Apa yang terjadi ketika rollback pertama membutuhkan banyak waktu (apakah rollback adalah single threaded)?
    2.1. Apakah SQL Server kembali dan membatalkan entri yang dibuat dalam LDFfile?
    2.2. The LDFukuran file semakin kecil pada akhir rollback (dari DBCC SQLPERF(LOGSPACE))

  3. Satu pertanyaan tambahan: Selama skenario kedua, SQL Server mulai mengkonsumsi LDFfile dengan cukup cepat. Dalam kasus saya, itu meningkat dari 18% penggunaan menjadi 90% penggunaan dalam beberapa menit pertama (<4 menit). Tapi begitu mencapai 99%, ia tinggal di sana selama 8 menit, sementara penggunaannya berfluktuasi antara 99,1% hingga 99,8%. Ini naik (99,8%) dan turun (99,2%) dan naik lagi (99,7%) dan turun (99,5%) beberapa kali sebelum kesalahan dilemparkan. Apa yang terjadi di balik layar?

Setiap tautan MSDN yang dapat membantu menjelaskan hal ini lebih dihargai.

Atas saran Ali Razeghi, saya menambahkan perfmon: Disk Bytes/sec

Skenario 1:

skenario 1

Skenario 2:

Skenario 2

ToC
sumber
Hanya komentar singkat: ukuran file! = Ruang yang digunakan dalam file.
Aaron Bertrand
@ Harun Ya, saya akrab dengan itu. Saya menggunakan DBCC SQLPERF (LOGSPACE) untuk mengukur penggunaan. File LDF tetap sama selama seluruh durasi, karena saya membatasi ukuran file hingga 10 GB. Penggunaan internal bervariasi.
ToC
1
Saya menduga bahwa rollback kedua muncul seketika, karena kesalahan dilaporkan setelah rollback selesai. Ini mungkin 8 menit yang Anda amati dalam 3., di mana penggunaan LDF tetap cukup konstan.
mustaccio
@ustaccio Saya akan setuju dengan Anda tetapi artefak menunjuk ke arah yang berbeda. Jika pada kenyataannya, rollback terjadi, maka penggunaan file log harus kembali ke jumlah yang lebih kecil; dan tidak tetap di 99,3% ketika pesan kesalahan dilemparkan.
ToC
1
Saya percaya rollback membutuhkan ruang log. Ketika log menjadi penuh selama kembalikan, DB menjadi tersangka. Tidak tersentuh lebih jauh. Ini terlihat seperti rollback instan tetapi rollback telah ditunda sampai Anda dapat mengambil database kembali online (ketika ada ruang disk yang tersedia); Juga, ketika log menjadi SQL Server penuh mungkin mencoba untuk membuat ruang dengan pos pemeriksaan yang mungkin menjelaskan lonjakan aktivitas IO.
usr

Jawaban:

1

Seperti ditunjukkan di atas, setelah menjalankan lebih banyak tes, saya sampai pada kesimpulan yang dihitung. Saya merangkum semuanya menjadi posting blog di sini , tetapi saya akan menyalin beberapa konten ke posting ini untuk anak cucu.

Dugaan (berdasarkan beberapa tes)

Sampai sekarang, saya tidak memiliki penjelasan yang jelas mengapa ini terjadi. Tapi berikut adalah perkiraan saya berdasarkan artefak yang dikumpulkan selama tes.

Kembalikan terjadi di kedua skenario. Salah satunya adalah rollback eksplisit (pengguna menekan tombol Batal), yang lainnya implisit (Sql Server membuat keputusan itu secara internal).

Dalam kedua skenario, lalu lintas yang menuju ke file log konsisten. Lihat gambar di bawah ini:

Skenario 1:

Skenario 1:

Skenario 2:

Skenario 2

  • Salah satu artefak yang memperkuat garis pemikiran ini adalah menangkap Jejak Sql selama kedua skenario.

    • Skenario 1 adalah bukti nyata alias ketika kita menekan 'Batal', itu bergulir kembali.
    • Dalam Skenario 2, pesan kesalahan ditampilkan setelah melakukan 'rollback' secara implisit. Di Sql Trace, kita melihat pesan kesalahan "Log transaksi untuk database 'SampleDB' penuh" lama sebelum pesan ditampilkan di layar. Jadi, tebakan saya adalah bahwa rollback terjadi di kedua skenario, tetapi pesan kesalahannya adalah Skenario 2 ditampilkan setelah berhasil dan sepenuhnya menjalankan rollback.
  • Skenario 2 tampaknya membutuhkan waktu lebih lama karena semakin maju, sehingga kemunduran lebih lama.

Perilaku yang tidak dapat dijelaskan:

  • Mengapa penggunaan file log sangat bervariasi?
    • Ini meningkat menjadi 90%, lalu turun ke 85%, lalu hingga 99% dan melayang di sana untuk waktu yang lama. Saya melihatnya naik turun seperti ini beberapa kali: 99,2%, 99,8%, 99,1%, 99,7%. Mengapa ini terjadi?
    • Satu penjelasan yang mungkin adalah bahwa, mungkin ada proses latar belakang (seperti Log Flush) yang membersihkan file log setiap beberapa menit. Dan setiap kali masuk, beberapa entri dihapus, menghasilkan lebih banyak ruang kosong yang tersedia.

Setiap ide untuk membantu menjelaskan perilaku ini dengan cara yang lebih baik dipersilakan.

ToC
sumber
2
Diperiksa dengan Paul Randal, dia mengkonfirmasi bahwa Anda sampai pada kesimpulan yang benar - kemunduran adalah sama dalam kedua kasus.
Paul White 9
0

Saya mencoba percobaan berikut dan mendapatkan hasil yang serupa. Dalam kedua kasus, fn_dblog () menunjukkan rollback yang terjadi dan tampaknya terjadi lebih cepat di Skenario 2 daripada di Skenario 1.

By the way, saya menempatkan baik MDF dan LDF pada disk eksternal (USB 2.0) tunggal yang sama.

Kesimpulan awal saya adalah bahwa tidak ada perbedaan dalam operasi rollback dalam kasus ini, dan mungkin perbedaan kecepatan yang jelas terkait subsistem I / O. Itulah hipotesis kerja saya saat ini.

Skenario 1:

  • Buat database dengan file log yang dimulai pada 1MB, tumbuh dalam potongan 4MB, dan memiliki ukuran maksimal 100MB.
  • Buka transaksi eksplisit, jalankan selama 10 detik, dan kemudian batalkan secara manual dalam SSMS
  • Lihatlah jumlah fn_dblog () dan catat ukuran cadangan dan periksa DBCC SQLPERF (LOGSPACE)

Skenario 2:

  • Buat database dengan file log yang dimulai pada 1MB, tumbuh dalam potongan 4MB, dan memiliki ukuran maksimal 100MB.
  • Buka transaksi eksplisit, jalankan hingga log penuh kesalahan muncul
  • Lihatlah jumlah fn_dblog () dan catat ukuran cadangan dan periksa DBCC SQLPERF (LOGSPACE)

Hasil Monitor Kinerja:

Skenario 1: ***Skenario 1***

Skenario 2: *** Skenario 2 ***

Kode:

GUNAKAN [master];
PERGILAH

JIKA DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
MULAI
    ALTER DATABASE [SampleDB] SET SINGLE_USER
        DENGAN SEGERA ROLLBACK;
    DROP DATABASE [SampleDB];
AKHIR;
PERGILAH

BUAT DATABASE [SampleDB] TENTANG UTAMA 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , SIZE = 3MB 
    , FILEGROWTH = 1MB 
)
LOG ON 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , UKURAN = 1MB 
    , MAXSIZE = 100MB 
    , FILEGROWTH = 4MB 
);
PERGILAH

GUNAKAN [SampleDB];
PERGILAH

- Tambahkan tabel
CREATE TABLE dbo.test
(
    c1 CHAR (8000) BUKAN NULL DEFAULT REPLICATE ('a', 8000)
) ON [PRIMARY];
PERGILAH

- Pastikan kita tidak model pemulihan semu-sederhana
CADANGAN DATABASE SampleDB
TO DISK = 'NUL';
PERGILAH

- Cadangkan file log
LOG CADANGAN SampleDB
TO DISK = 'NUL';
PERGILAH

- Periksa ruang log yang digunakan
DBCC SQLPERF (LOGSPACE);
PERGILAH

- Berapa banyak catatan yang terlihat dengan fn_dblog ()?
SELECT * FROM fn_dblog (NULL, NULL); - Sekitar 9 dalam kasus saya

/ **********************************
             SKENARIO 1
******************************** /
- Buka transaksi baru dan kemudian gulung kembali
TRANSAKSI AWAL

    Masukkan ke dalam dbo.test NILAI DEFAULT;
    GO 10000 - Biarkan dijalankan selama 10 detik dan kemudian tekan batal di jendela permintaan SSMS

    - Batalkan transaksi
    - Perlu beberapa detik untuk menyelesaikannya


- Tidak perlu mengembalikan transaksi, karena pembatalan sudah melakukannya untuk Anda.
-- Cobalah. Anda akan mendapatkan kesalahan ini
- Msg 3903, Level 16, Negara Bagian 1, Jalur 1
- Permintaan TRANSAKSI ROLLBACK tidak memiliki TRANSAKSI BEGIN yang sesuai.
TRANSAKSI ROLLBACK;

- Apa ruang log yang digunakan? Di atas 100%
DBCC SQLPERF (LOGSPACE);
PERGILAH

- Berapa banyak catatan yang terlihat dengan fn_dblog ()?
PILIH * 
FROM fn_dblog (NULL, NULL); - Sekitar 91.926 dalam kasus saya

- Total cadangan log ditunjukkan oleh fn_dblog ()?
SELECT SUM ([Cadangan Log]) AS [Total Cadangan Log]
FROM fn_dblog (NULL, NULL); - Sekitar 88,72MB


/ **********************************
             SKENARIO 2
******************************** /
- Menerbangkan DB dan memulai dari awal
GUNAKAN [master];
PERGILAH

JIKA DATABASEPROPERTYEX (N'SampleDB ', N'Version')> 0
MULAI
    ALTER DATABASE [SampleDB] SET SINGLE_USER
        DENGAN SEGERA ROLLBACK;
    DROP DATABASE [SampleDB];
AKHIR;
PERGILAH

BUAT DATABASE [SampleDB] TENTANG UTAMA 
( 
      NAME = N'SampleDB '
    , FILENAME = N'E: \ data \ SampleDB.mdf ' 
    , SIZE = 3MB 
    , FILEGROWTH = 1MB 
)
LOG ON 
( 
      NAME = N'SampleDB_log '
    , FILENAME = N'E: \ data \ SampleDB_log.ldf '
    , UKURAN = 1MB 
    , MAXSIZE = 100MB 
    , FILEGROWTH = 4MB 
);
PERGILAH

GUNAKAN [SampleDB];
PERGILAH

- Tambahkan tabel
CREATE TABLE dbo.test
(
    c1 CHAR (8000) BUKAN NULL DEFAULT REPLICATE ('a', 8000)
) ON [PRIMARY];
PERGILAH

- Pastikan kita tidak model pemulihan semu-sederhana
CADANGAN DATABASE SampleDB
TO DISK = 'NUL';
PERGILAH

- Cadangkan file log
LOG CADANGAN SampleDB
TO DISK = 'NUL';
PERGILAH

- Sekarang, mari kita meledakkan file log dalam transaksi kita
TRANSAKSI AWAL
    Masukkan ke dalam dbo.test NILAI DEFAULT;
    GO 10000

- Kembalikan tidak pernah terjadi. Cobalah. Anda akan mendapatkan kesalahan.
- Msg 3903, Level 16, Negara Bagian 1, Jalur 1
- Permintaan TRANSAKSI ROLLBACK tidak memiliki TRANSAKSI BEGIN yang sesuai.
TRANSAKSI ROLLBACK;

- Apakah file log 100% penuh? 
DBCC SQLPERF (LOGSPACE);

- Berapa banyak catatan yang terlihat dengan fn_dblog ()?
PILIH * 
FROM fn_dblog (NULL, NULL); - Sekitar 91.926 dalam kasus saya
PERGILAH

- Total cadangan log ditunjukkan oleh fn_dblog ()?
SELECT SUM ([Cadangan Log]) AS [Total Cadangan Log]
FROM fn_dblog (NULL, NULL); - 88.72MB
PERGILAH
ooutwire
sumber
Terima kasih untuk tes terperinci. Setelah menjalankan lebih banyak tes, saya sampai pada kesimpulan yang sama. Jadi, saya menulis posting blog . Bagi saya Skenario 2 membutuhkan waktu lebih lama untuk mengembalikan karena jumlah pekerjaan yang dilakukan dalam Skenario 2, sebelum Sql Server menyadari kebutuhan untuk mengembalikan lebih dari Skenario 1.
ToC