Czy dziennik SQL Server rejestruje niezaangażowane operacje?

12

Często widzę takie oświadczenia, jak log serwera SQL, który rejestruje każdą transakcję i operację.

Ale jestem mylić o tym, co się dzieje, gdy transakcja zostanie ostatecznie walcowane powrotem .

Powiedzmy wyraźna transakcja ma 3 oświadczenia: statement A, statement B, statement C, i wreszcie rollback statement D.

Teraz powiedz, kiedy wykonanie nie osiągnęło rollback statement D, czy modyfikacje wynikające z statements A through Czapisania w dzienniku serwera SQL?

Zrozumienie 1 :

Wszystkie wyciągi od A do D są rejestrowane. SQL Server rejestruje wszystko, bez względu na wszystko.

Zrozumienie 2 : Modyfikacje są przechowywane tylko gdzieś w pamięci i rejestrowane tylko w celu zalogowania, gdy SQL Server wyświetli commitinstrukcję. Jeśli okaże się, że jest to rollbackinstrukcja, SQL Server po prostu zignoruje transakcję, nie nastąpi zapis do dziennika, ponieważ nie służy to żadnemu celowi. Innymi słowy, SQL Server loguje się, gdy wynik netto przed i po transakcjach.

Oba wydają się logiczne, przynajmniej dla mnie, ale oba nie mogą mieć racji. Dziękuję za wszelką pomoc.

John Smith
źródło
Cześć. Spróbuj [ systoolsgroup.com/sql-log-analyzer.html] (SQL Log Analyzer), aby przeanalizować, co dzieje się w pliku dziennika. Możesz wypróbować bezpłatną wersję narzędzia SysTools SQL Log Analyzer do podglądu tylko danych dziennika SQL. Mam nadzieję, że to Ci odpowiada.
Rylan08

Odpowiedzi:

13

Zrozumienie 1 jest poprawne. SQL Server rejestruje każdą operację, która zmienia dane w dzienniku transakcji. Wycofanie jest zmianą danych, więc zapisuje to również w dzienniku transakcji. Jako instrukcja A zapisuje dane w dzienniku transakcji, a także rezerwuje dane w dzienniku transakcji na wypadek, gdyby instrukcja A musiała zostać wycofana. To samo dotyczy B i C. Po wycofaniu transakcji więcej informacji zostanie zapisanych w dzienniku.

Istnieje wiele sposobów, aby zobaczyć to w akcji, dlatego poniżej znajduje się szybka prezentacja. Oto zapytanie, którego użyję, aby zobaczyć, co zostało zapisane w dzienniku:

SELECT 
  COUNT(*) transaction_count
, SUM(database_transaction_log_bytes_used) used_bytes
, SUM(database_transaction_log_bytes_reserved) reserved_bytes
FROM sys.dm_tran_database_transactions
where database_id = 10;

Mój stół:

create table TLOGDEMO (FLUFF VARCHAR(1000));

BEGIN TRANSACTION

Zapytanie A korzysta z minimalnego rejestrowania:

INSERT INTO TLOGDEMO WITH (TABLOCK)
SELECT REPLICATE('A', 1000)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Po:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1    24006640       175429451 
╚═══════════════════╩════════════╩════════════════╝

Kwerenda B nie używa rejestrowania minimalnego:

INSERT INTO TLOGDEMO
SELECT REPLICATE('B', 1000)
FROM master..spt_values t1
CROSS JOIN master..spt_values t2;

Po B:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1  7352935708      1613986255 
╚═══════════════════╩════════════╩════════════════╝

Zapytanie C zmienia mniej danych:

INSERT INTO TLOGDEMO
SELECT REPLICATE('C', 1000)
FROM master..spt_values c;

Po C:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
                 1  7355821748      1614545331 
╚═══════════════════╩════════════╩════════════════╝

Teraz wydam ROLLBACKi zapytam DMV podczas wycofywania. Poniżej znajduje się tabela kilku migawek:

╔═══════════════════╦════════════╦════════════════╗
 transaction_count  used_bytes  reserved_bytes 
╠═══════════════════╬════════════╬════════════════╣
 1                  7393305528  1573797677     
 1                  7458767420  1502635737     
 1                  7682482356  1259440979     
 1                  7803881368  1127471233     
 ...                ...         ...            
╚═══════════════════╩════════════╩════════════════╝

W ciągu ROLLBACKużywanych bajtów wzrasta, a zarezerwowana liczba bajtów maleje. Wynika to z faktu, że SQL Server wykorzystuje wcześniej zarezerwowane miejsce do cofnięcia transakcji. Aby cofnąć transakcję, musi zmienić dane, aby zapisać więcej danych w dzienniku.

Joe Obbish
źródło
8

Modyfikacje tabel bazy danych są zapisywane najpierw w pliku dziennika, a następnie w samych tabelach, najpierw w pamięci, a następnie w asynchronicznym procesie nazywanym CHECKPOINTna dysku. Ten mechanizm jest znany jako WAL (Write-Ahead Logging) i jest wspólny dla wszystkich relacyjnych baz danych.

Sam dziennik jest najpierw zapisywany w pamięci (dokładnie w buforze dziennika), a następnie na dysku, ale tabele bazy danych nie są dotykane, dopóki dziennik nie zostanie zapisany na dysku.

Ten mechanizm umożliwia zarówno wycofanie zatwierdzonych transakcji, jak i wycofanie niezatwierdzonych transakcji podczas procesu odzyskiwania. Jeśli chodzi o twój przykład, jeśli coś złego wydarzyło się później statement Ci commitzamiast tego rollback(nie możesz tego wiedzieć wcześniej), bez zapisywania każdego kroku transakcji, RDBMS nie miałby sposobu na odzyskanie bazy danych w spójny sposób sposób, a transakcja nie spełniałaby D(trwałości) w ACID.

Kiedy niektóre operacje są wycofywane, to plik danych otrzymuje zmiany netto (via CHECKPOINT), a nie plik dziennika.

spaghettidba
źródło
5

Zrozumienie 1 jest poprawne, a spaghettidba i Joe mają dobre wyjaśnienia.

Jeśli chcesz przetestować dla siebie (na instancji testowej), możesz użyć poniższego skryptu:

--create a database and table for testing
USE master
GO
CREATE DATABASE tranlogtest
GO
USE tranlogtest
GO
CREATE TABLE t1
(junk char(1))

CHECKPOINT
GO

BEGIN TRAN
INSERT t1 VALUES ('a')
INSERT t1 VALUES ('b')
INSERT t1 VALUES ('c')

ROLLBACK
INSERT t1 VALUES ('d')

SELECT *
FROM fn_dblog(NULL,NULL)

Zobaczysz, że SQL Server rejestruje wszystko, nawet kroki podjęte w celu cofnięcia operacji.

Forrest
źródło