Przewodnik dotyczący blokowania transakcji i wersjonowania wierszy
Dotyczy:SQL Server
Azure SQL Database
Azure SQL Managed Instance
Azure Synapse Analytics
Analytics Platform System (PDW)
SQL Database w usłudze Microsoft Fabric
W każdej bazie danych niewłaściwe zarządzanie transakcjami często prowadzi do problemów z rywalizacją i wydajnością w systemach, które mają wielu użytkowników. Wraz ze wzrostem liczby użytkowników uzyskujących dostęp do danych, ważne staje się posiadanie aplikacji, które efektywnie wykorzystują transakcje. W tym przewodniku opisano mechanizmy blokowania i przechowywania wersji wierszy używane przez aparat bazy danych w celu zapewnienia integralności każdej transakcji i zawiera informacje na temat efektywnego kontrolowania transakcji przez aplikacje.
Notatka
Zoptymalizowane blokowanie to funkcja silnika bazy danych wprowadzona w 2023 r., która znacząco zmniejsza pamięć zajmowaną przez blokady oraz liczbę blokad wymaganych do współbieżnych zapisów. Ten artykuł został zaktualizowany, aby opisać zachowanie silnika bazy danych z oraz bez zoptymalizowanego blokowania.
- Aby uzyskać więcej informacji i dowiedzieć się, gdzie jest dostępne zoptymalizowane blokowanie, zobacz Zoptymalizowane blokowanie.
- Aby określić, czy zoptymalizowane blokowanie jest włączone w bazie danych, zobacz Czy włączono zoptymalizowane blokowanie?
Zoptymalizowane blokowanie wprowadza istotne zmiany w niektórych sekcjach tego artykułu, w tym:
- blokowanie w mechanizmie bazy danych
- Operacja usuwania
- Operacja wstawiania
- eskalacja blokady
- Zmniejsz blokowanie i eskalację
- zachowanie podczas modyfikowania danych
- zachowanie w podsumowaniu
- wskazówki dotyczące blokowania
Podstawy transakcji
Transakcja to sekwencja operacji wykonywanych jako pojedyncza jednostka logiczna pracy. Jednostka logiczna pracy musi zawierać cztery właściwości, nazywane atomowością, spójnością, izolacją i trwałością (ACID), aby mogła być zakwalifikowana jako transakcja.
niepodzielność
Transakcja musi być niepodzielnym elementem pracy; wszystkie jej modyfikacje danych są wykonywane, albo żadna z nich nie jest wykonywana.
spójność
Po zakończeniu transakcja musi pozostawić wszystkie dane w stanie spójnym. W relacyjnej bazie danych wszystkie reguły muszą być stosowane do modyfikacji transakcji w celu zachowania całej integralności danych. Wszystkie wewnętrzne struktury danych, takie jak indeksy drzewa B lub podwójnie połączone listy, muszą być poprawne na końcu transakcji.
Notatka
W dokumentacji jest zwykle używany termin B-tree w odniesieniu do indeksów. W indeksach rowstore silnik bazy danych implementuje drzewo B+. Nie dotyczy to indeksów magazynu kolumn ani indeksów w tabelach zoptymalizowanych pod kątem pamięci. Aby uzyskać więcej informacji, zobacz przewodnik dotyczący architektury i projektowania indeksów w SQL Server i Azure SQL.
Izolacja
Modyfikacje wprowadzone przez transakcje współbieżne muszą być odizolowane od modyfikacji wprowadzonych przez inne współbieżne transakcje. Transakcja rozpoznaje dane w stanie, w których znajdowała się przed zmodyfikowaniem innej współbieżnej transakcji, lub rozpoznaje dane po zakończeniu drugiej transakcji, ale nie rozpoznaje stanu pośredniego. Jest to określane jako seryjność, ponieważ umożliwia ponowne załadowanie danych początkowych i odtworzenie serii transakcji, aby doprowadzić dane do tego samego stanu, w którym były po wykonaniu oryginalnych transakcji.
trwałość
Po zakończeniu w pełni trwałej transakcji jego efekty są trwale wprowadzone w systemie. Modyfikacje są utrwalane nawet w przypadku awarii systemu. SQL Server 2014 (12.x) i nowsze umożliwiają opóźnione trwałe transakcje. Zatwierdzenie opóźnionych trwałych transakcji następuje, zanim rekord dziennika transakcji zostanie zapisany na dysku. Aby uzyskać więcej informacji na temat opóźnionej trwałości transakcji, zobacz artykuł "Trwałość Transakcji Kontrolnych".
Aplikacje są odpowiedzialne za uruchamianie i kończenie transakcji w punktach, które wymuszają logiczną spójność danych. Aplikacja musi zdefiniować sekwencję modyfikacji danych, które pozostawiają dane w spójnym stanie względem reguł biznesowych organizacji. Aplikacja wykonuje te modyfikacje w jednej transakcji, aby aparat bazy danych mógł wymusić integralność transakcji.
Jest to odpowiedzialność systemu bazy danych przedsiębiorstwa, takiego jak instancja silnika bazy danych, aby dostarczać mechanizmy gwarantujące integralność każdej transakcji. Aparat bazy danych zapewnia:
Mechanizmy blokujące, które zachowują izolację transakcji.
Mechanizmy rejestrowania w celu zapewnienia trwałości transakcji. W przypadku w pełni trwałych transakcji, rekord dziennika jest zapisywany na dysku przed zatwierdzeniem transakcji. W związku z tym, nawet jeśli sprzęt serwera, system operacyjny lub wystąpienie aparatu bazy danych ulegnie awarii, system używa dzienników transakcji do automatycznego wycofania wszystkich niekompletnych transakcji do momentu awarii systemu podczas ponownego uruchomienia. Transakcje trwałe są zatwierdzane z opóźnieniem, zanim rekord dziennika transakcji zostanie zapisany na dysku. Takie transakcje mogą zostać utracone, jeśli wystąpi awaria systemu, zanim rekord dziennika zostanie wzmocniony na dysku. Aby uzyskać więcej informacji na temat opóźnionej trwałości transakcji, zobacz artykuł "Trwałość Transakcji Kontrolnych".
Funkcje zarządzania transakcjami, które wymuszają niepodzielność transakcji i spójność. Po rozpoczęciu transakcji musi zostać pomyślnie ukończona (zatwierdzona) lub aparat bazy danych cofa wszystkie modyfikacje danych wprowadzone przez transakcję od momentu rozpoczęcia transakcji. Ta operacja jest określana jako wycofywanie transakcji, ponieważ zwraca dane do stanu sprzed tych zmian.
Kontrolowanie transakcji
Aplikacje kontrolują transakcje głównie przez określenie, kiedy transakcja rozpoczyna się i kończy. Można to określić przy użyciu instrukcji Transact-SQL lub funkcji interfejsu API (Database Application Programming Interface). System musi być również w stanie poprawnie obsługiwać błędy, które kończą transakcję przed jego ukończeniem. Aby uzyskać więcej informacji, zobacz Transakcje, Wykonywanie transakcji w ODBC, i Transakcje w SQL Server Native Client.
Domyślnie transakcje są zarządzane na poziomie połączenia. Po uruchomieniu transakcji na połączeniu wszystkie instrukcje Transact-SQL wykonywane na tym połączeniu są częścią transakcji do momentu zakończenia transakcji. Jednak w ramach wielu aktywnych sesji zestawu wyników (MARS), transakcja jawna lub niejawna Transact-SQL staje się transakcją o zakresie wsadowym, która jest zarządzana na poziomie wsadu. Po zakończeniu przetwarzania wsadowego, jeśli transakcja o zakresie wsadowym nie zostanie zatwierdzona ani wycofana, silnik bazy danych automatycznie ją wycofa. Aby uzyskać więcej informacji, zobacz Korzystanie z wielu aktywnych zestawów wyników (MARS).
Rozpoczynanie transakcji
Korzystając z funkcji interfejsu API i instrukcji Transact-SQL, można uruchamiać transakcje jako jawne, automatyczne zatwierdzanie lub niejawne transakcje.
jawne transakcje
Jawna transakcja to transakcja, w której jawnie definiujesz zarówno początek, jak i koniec transakcji za pośrednictwem funkcji interfejsu API lub wydając instrukcje Transact-SQL BEGIN TRANSACTION
, COMMIT TRANSACTION
, COMMIT WORK
, ROLLBACK TRANSACTION
lub ROLLBACK WORK
Transact-SQL. Po zakończeniu transakcji połączenie powraca do trybu transakcji, w którym nastąpiło przed rozpoczęciem jawnej transakcji, co może być trybem niejawnego lub automatycznego zatwierdzania.
Można użyć wszystkich instrukcji Transact-SQL w jawnej transakcji, z wyjątkiem następujących instrukcji:
CREATE DATABASE
ALTER DATABASE
DROP DATABASE
CREATE FULLTEXT CATALOG
ALTER FULLTEXT CATALOG
DROP FULLTEXT CATALOG
DROP FULLTEXT INDEX
ALTER FULLTEXT INDEX
CREATE FULLTEXT INDEX
BACKUP
RESTORE
RECONFIGURE
- Procedury składowane systemu pełnotekstowego
-
sp_dboption
ustawić opcje bazy danych lub dowolną procedurę systemową, która modyfikuje bazę danychmaster
w ramach jawnych lub niejawnych transakcji.
Notatka
UPDATE STATISTICS
można używać wewnątrz jawnej transakcji. Jednak UPDATE STATISTICS
zatwierdza się niezależnie od transakcji, którą otacza, i nie można go wycofać.
automatyczne zatwierdzanie transakcji
Tryb autozatwierdzania jest domyślnym trybem zarządzania transakcjami w aparacie bazy danych. Każde polecenie Transact-SQL jest zatwierdzane lub cofane po zakończeniu. Jeśli instrukcja zakończy się pomyślnie, zostanie zatwierdzona; jeśli wystąpi jakikolwiek błąd, zostanie wycofana. Połączenie z wystąpieniem silnika bazy danych działa w trybie automatycznego zatwierdzania, kiedy ten tryb domyślny nie został zmieniony przez jawne lub niejawne transakcje. Tryb autozatwierdzania jest również trybem domyślnym dla SqlClient, ADO, OLE DB i ODBC.
Niejawnych Transakcji
Gdy połączenie działa w trybie niejawnych transakcji, instancja Silnika Bazy Danych automatycznie rozpoczyna nową transakcję po zatwierdzeniu lub wycofaniu bieżącej transakcji. Nie należy określać początku transakcji; zatwierdzasz lub cofasz tylko każdą transakcję. Niejawny tryb transakcji generuje ciągły łańcuch transakcji. Ustaw niejawny tryb transakcji za pomocą funkcji interfejsu API lub instrukcji Transact-SQL SET IMPLICIT_TRANSACTIONS ON
. Ten tryb jest również znany jako Autocommit OFF, zobacz setAutoCommit Method (SQLServerConnection).
Po włączeniu niejawnego trybu transakcji dla połączenia instancja silnika bazy danych automatycznie rozpoczyna transakcję przy pierwszym wykonaniu którejkolwiek z tych instrukcji.
ALTER TABLE
CREATE
DELETE
DENY
DROP
FETCH
GRANT
INSERT
OPEN
REVOKE
SELECT
TRUNCATE
UPDATE
Transakcje o zasięgu wsadowym
Dotyczy tylko wielokrotnych aktywnych zestawów wyników (MARS), transakcja Transact-SQL jawna lub niejawna, która rozpoczyna się w ramach sesji MARS, staje się transakcją o zakresie wsadowym. Transakcja o zakresie wsadowym, która nie jest zatwierdzona lub wycofana, gdy wsad zostanie zakończony, jest automatycznie cofana przez mechanizm bazy danych.
Transakcje rozproszone
Transakcje rozproszone obejmują co najmniej dwa serwery znane jako zarządcy zasobów. Zarządzanie transakcją musi być koordynowane między menedżerami zasobów przez składnik serwera nazywany menedżerem transakcji. Każde wystąpienie silnika bazy danych może działać jako menedżer zasobów w transakcjach rozproszonych, koordynowanych przez menedżerów transakcji, takich jak Koordynator Transakcji Rozproszonych firmy Microsoft (MS DTC), lub innych menedżerów transakcji obsługujących specyfikację XA Grupy Open na potrzeby rozproszonego przetwarzania transakcji. Aby uzyskać więcej informacji, zobacz dokumentację usługi MS DTC.
Transakcja w ramach jednego wystąpienia silnika bazy danych, które obejmuje dwie lub więcej baz danych, jest transakcją rozproszoną. Wystąpienie zarządza transakcją rozproszoną wewnętrznie; dla użytkownika, działa jako transakcja lokalna.
W aplikacji transakcja rozproszona jest zarządzana tak samo jak transakcja lokalna. Na końcu transakcji aplikacja żąda zatwierdzenia lub wycofania transakcji. Zatwierdzenie rozproszone musi być zarządzane inaczej przez menedżera transakcji, aby zminimalizować ryzyko, że awaria sieci może doprowadzić do tego, że niektórzy zarządcy zasobów pomyślnie zatwierdzą transakcję, podczas gdy inni ją wycofają. Jest to osiągane przez zarządzanie procesem zatwierdzania w dwóch fazach (faza przygotowania i faza zatwierdzania), która jest nazywana zatwierdzeniem dwufazowym.
Faza przygotowawcza
Gdy menedżer transakcji odbiera żądanie zatwierdzenia, wysyła polecenie prepare do wszystkich menedżerów zasobów zaangażowanych w transakcję. Następnie każdy menedżer zasobów wykonuje wszystko, co jest wymagane, aby transakcja była trwała, a wszystkie bufory dziennika transakcji zostają zapisane na dysku. Gdy każdy menedżer zasobów ukończy fazę przygotowania, informuje menedżera transakcji o powodzeniu lub niepowodzeniu tej fazy. Program SQL Server 2014 (12.x) wprowadził opóźnioną trwałość transakcji. Transakcje opóźnione trwałe są zatwierdzane przed opróżnieniem buforów dziennika transakcji na dysk w każdym menedżerze zasobów. Aby uzyskać więcej informacji na temat opóźnionej trwałości transakcji, zobacz artykuł "Trwałość Transakcji Kontrolnych".
faza zatwierdzania
Jeśli menedżer transakcji otrzyma potwierdzenia przygotowania ze wszystkich menedżerów zasobów, wysyła polecenia zatwierdzenia transakcji do każdego menedżera zasobów. Menedżerowie zasobów mogą następnie ukończyć zatwierdzenie. Jeśli wszyscy menedżerowie zasobów zgłaszają pomyślne zatwierdzenie, menedżer transakcji wysyła powiadomienie o powodzeniu do aplikacji. Jeśli jakikolwiek menedżer zasobów zgłosił niepowodzenie przygotowania, menedżer transakcji wysyła polecenie wycofania do każdego menedżera zasobów i wskazuje niepowodzenie zatwierdzenia w aplikacji.
Aplikacje aparatu bazy danych mogą zarządzać transakcjami rozproszonymi za pośrednictwem Transact-SQL lub za pośrednictwem interfejsu API bazy danych. Aby uzyskać więcej informacji, zobacz BEGIN DISTRIBUTED TRANSACTION (Transact-SQL).
Transakcje końcowe
Transakcje można zakończyć za pomocą instrukcji COMMIT lub ROLLBACK albo za pomocą odpowiedniej funkcji interfejsu API.
Zatwierdzenie
Jeśli transakcja zakończy się pomyślnie, zatwierdź ją. Instrukcja
COMMIT
gwarantuje, że wszystkie modyfikacje transakcji zostaną wprowadzone w stałej części bazy danych. Zatwierdzenie zwalnia również zasoby, takie jak blokady, używane przez transakcję.Wycofaj
Jeśli w transakcji wystąpi błąd lub jeśli użytkownik zdecyduje się anulować transakcję, wycofaj transakcję. Instrukcja
ROLLBACK
zwraca wszystkie modyfikacje wprowadzone w transakcji, zwracając dane do stanu, w którym znajdowała się na początku transakcji. Cofnięcie transakcji zwalnia zasoby przechowywane przez transakcję.
Notatka
W przypadku wielu aktywnych sesji zestawów wyników (MARS) jawna transakcja uruchomiona za pośrednictwem funkcji interfejsu API nie może zostać zatwierdzona, gdy istnieją oczekujące żądania wykonania. Każda próba zatwierdzenia tego typu transakcji podczas wykonywania żądań powoduje wystąpienie błędu.
Błędy podczas przetwarzania transakcji
Jeśli błąd uniemożliwia pomyślne zakończenie transakcji, aparat bazy danych automatycznie wycofa transakcję i zwalnia wszystkie zasoby przechowywane przez transakcję. Jeśli połączenie sieciowe klienta z instancją Silnika bazy danych zostanie przerwane, wszystkie oczekujące transakcje dla tego połączenia zostaną wycofane, gdy sieć powiadomi instancję o zerwaniu połączenia. Jeśli aplikacja kliencka ulegnie awarii lub komputer kliencki zostanie wyłączony albo uruchomiony ponownie, spowoduje to przerwanie połączenia, a silnik bazy danych wycofa wszelkie niezakończone transakcje, gdy sieć powiadomi go o zerwaniu połączenia. Jeśli klient rozłączy się z aparatem bazy danych, wszystkie zaległe transakcje zostaną wycofane.
Jeśli w partii wystąpi błąd w czasie wykonywania instrukcji (na przykład naruszenie ograniczenia), domyślne działanie silnika bazy danych polega na wycofaniu tylko instrukcji, która wygenerowała błąd. To zachowanie można zmienić przy użyciu instrukcji SET XACT_ABORT ON
. Po wykonaniu SET XACT_ABORT ON
każdy błąd instrukcji czasu wykonywania powoduje automatyczne wycofanie bieżącej transakcji. Błędy kompilacji, takie jak błędy składni, nie mają wpływu na SET XACT_ABORT
. Aby uzyskać więcej informacji, zobacz SET XACT_ABORT (Transact-SQL).
W przypadku wystąpienia błędów należy uwzględnić odpowiednią akcję (COMMIT
lub ROLLBACK
) w kodzie aplikacji. Jednym z skutecznych narzędzi do obsługi błędów, w tym tych w transakcjach, jest konstrukcja Transact-SQL TRY...CATCH
. Aby uzyskać więcej informacji o przykładach obejmujących transakcje, zobacz TRY...CATCH (Transact-SQL). Począwszy od programu SQL Server 2012 (11.x), można użyć instrukcji THROW
, aby zgłosić wyjątek i przekazać wykonanie do bloku CATCH
konstrukcji TRY...CATCH
. Aby uzyskać więcej informacji, zobacz THROW (Transact-SQL).
Błędy kompilowania i uruchamiania w trybie autopoleceń
W trybie automatycznego zatwierdzania czasami wydaje się, że wystąpienie silnika bazy danych anulowało całą transakcję, zamiast wycofać tylko jedną instrukcję SQL. Dzieje się tak, jeśli napotkany błąd jest błędem kompilacji, a nie błędem czasu wykonywania. Błąd kompilacji uniemożliwia aparatowi bazy danych utworzenie planu wykonywania, dlatego nie można wykonać niczego w partii. Chociaż wydaje się, że wszystkie instrukcje przed wygenerowaniem błędu zostały wycofane, błąd uniemożliwił wykonanie czegokolwiek w partii. W poniższym przykładzie żadna z instrukcji INSERT
w trzeciej partii nie jest wykonywana z powodu błędu kompilacji. Wydaje się, że pierwsze dwie instrukcje INSERT
zostają cofnięte, ponieważ nigdy nie są wykonywane.
CREATE TABLE TestBatch (ColA INT PRIMARY KEY, ColB CHAR(3));
GO
INSERT INTO TestBatch VALUES (1, 'aaa');
INSERT INTO TestBatch VALUES (2, 'bbb');
INSERT INTO TestBatch VALUSE (3, 'ccc'); -- Syntax error.
GO
SELECT * FROM TestBatch; -- Returns no rows.
GO
W poniższym przykładzie trzecia instrukcja INSERT
generuje błąd zduplikowanego klucza podstawowego w czasie wykonywania. Pierwsze dwie instrukcje INSERT
wykonują się pomyślnie i są zatwierdzone, więc pozostają po błędzie czasu wykonywania.
CREATE TABLE TestBatch (ColA INT PRIMARY KEY, ColB CHAR(3));
GO
INSERT INTO TestBatch VALUES (1, 'aaa');
INSERT INTO TestBatch VALUES (2, 'bbb');
INSERT INTO TestBatch VALUES (1, 'ccc'); -- Duplicate key error.
GO
SELECT * FROM TestBatch; -- Returns rows 1 and 2.
GO
Aparat bazy danych używa odroczonego rozpoznawania nazw, gdzie nazwy obiektów są rozpoznawane w czasie wykonywania, a nie w czasie kompilacji. W poniższym przykładzie pierwsze dwie instrukcje INSERT
są wykonywane i zatwierdzane, a te dwa wiersze pozostają w tabeli TestBatch
, po tym jak trzecia instrukcja INSERT
generuje błąd czasu wykonywania, odwołując się do tabeli, która nie istnieje.
CREATE TABLE TestBatch (ColA INT PRIMARY KEY, ColB CHAR(3));
GO
INSERT INTO TestBatch VALUES (1, 'aaa');
INSERT INTO TestBatch VALUES (2, 'bbb');
INSERT INTO TestBch VALUES (3, 'ccc'); -- Table name error.
GO
SELECT * FROM TestBatch; -- Returns rows 1 and 2.
GO
Podstawy blokowania i przechowywania wersji wierszy
Aparat bazy danych używa następujących mechanizmów, aby zapewnić integralność transakcji i zachować spójność baz danych, gdy wielu użytkowników uzyskuje dostęp do danych w tym samym czasie:
blokowanie
Każde żądanie transakcji blokuje różne typy zasobów, takich jak wiersze, strony lub tabele, na których zależy transakcja. Blokady blokują modyfikowanie zasobów w inny sposób, co spowodowałoby problemy z transakcją żądającą blokady. Każda transakcja zwalnia blokady, gdy nie ma już zależności od zablokowanych zasobów.
wersjonowanie wierszy
Gdy używany jest poziom izolacji opartej na wersjach wierszy, aparat bazy danych obsługuje wersje każdego wiersza, który jest modyfikowany. Aplikacje mogą określać, że transakcja używa wersji wierszy do przeglądania danych na początku transakcji lub zapytania, zamiast chronić wszystkie odczyty za pomocą blokad. Dzięki zastosowaniu wersjonowania wierszy znacznie zmniejsza się prawdopodobieństwo, że operacja odczytu zablokuje inne transakcje.
Blokowanie i przechowywanie wersji wierszy uniemożliwia użytkownikom odczytywanie niezatwierdzonych danych i uniemożliwianie wielu użytkownikom jednoczesnej próby zmiany tych samych danych. Bez blokowania lub przechowywania wersji wierszy zapytania wykonywane względem tych danych mogą powodować nieoczekiwane wyniki, zwracając dane, które nie zostały jeszcze zatwierdzone w bazie danych.
Aplikacje mogą wybierać poziomy izolacji transakcji, które definiują poziom ochrony transakcji od modyfikacji wprowadzonych przez inne transakcje. Wskazówki na poziomie tabeli można określić dla poszczególnych instrukcji Transact-SQL w celu dalszego dostosowania zachowania do wymagań aplikacji.
Zarządzanie dostępem współbieżnych danych
Użytkownicy, którzy uzyskują dostęp do zasobu w tym samym czasie, uzyskują dostęp do zasobu równocześnie. Współbieżny dostęp do danych wymaga mechanizmów, aby zapobiec negatywnym skutkom, gdy wielu użytkowników próbuje modyfikować zasoby, z których aktywnie korzystają inni użytkownicy.
Efekty współbieżności
Użytkownicy modyfikujący dane mogą mieć wpływ na innych użytkowników, którzy odczytują lub modyfikują te same dane w tym samym czasie. Mówi się, że użytkownicy uzyskują jednocześnie dostęp do danych. Jeśli baza danych nie ma kontroli współbieżności, użytkownicy mogą zobaczyć następujące skutki uboczne:
utracone aktualizacje
Utracone aktualizacje występują, gdy co najmniej dwie transakcje wybierają ten sam wiersz, a następnie aktualizują wiersz na podstawie wartości, którą wybrano na początku. Każda transakcja nie jest świadoma innych transakcji. Ostatnia aktualizacja zastępuje aktualizacje wprowadzone przez inne transakcje, co powoduje utratę danych.
Na przykład dwa edytory tworzą elektroniczną kopię tego samego dokumentu. Każdy edytor zmienia kopię niezależnie, a następnie zapisuje zmienioną kopię, zastępując w ten sposób oryginalny dokument. Edytor, który zapisuje zmienioną kopię jako ostatni, nadpisuje zmiany wprowadzone przez innego edytora. Ten problem można uniknąć, jeśli jeden edytor nie może uzyskać dostępu do pliku do czasu zakończenia i zatwierdzenia transakcji przez drugi edytor.
niezatwierdzona zależność (brudny odczyt)
Niezatwierdzona zależność występuje, gdy druga transakcja odczytuje wiersz, który jest aktualizowany przez inną transakcję. Druga transakcja odczytuje dane, które nie zostały jeszcze zatwierdzone i mogą zostać zmienione przez transakcję aktualizującą wiersz.
Na przykład edytor wprowadza zmiany w dokumencie elektronicznym. Podczas wprowadzania zmian drugi edytor pobiera kopię dokumentu zawierającego wszystkie zmiany wprowadzone do tej pory i dystrybuuje dokument do zamierzonej grupy odbiorców. Następnie pierwszy edytor decyduje, że zmiany wprowadzone do tej pory są nieprawidłowe i usuwa zmiany i zapisuje dokument. Dokument rozproszony zawiera edycje, które już nie istnieją i powinny być traktowane tak, jakby nigdy nie istniały. Ten problem można uniknąć, jeśli nikt nie może odczytać zmienionego dokumentu, dopóki pierwszy edytor nie wykona ostatecznego zapisu modyfikacji i zatwierdzi transakcję.
niespójna analiza (niewykonywalne powtórne odczyty)
Niespójna analiza występuje, gdy druga transakcja uzyskuje dostęp do tego samego wiersza kilka razy i odczytuje różne dane za każdym razem. Niespójna analiza jest podobna do niezatwierdzonej zależności w tym, że inna transakcja zmienia dane odczytywane przez drugą transakcję. Jednak w niespójnej analizie dane odczytane przez drugą transakcję zostały zatwierdzone przez transakcję, która dokonała zmiany. Ponadto niespójna analiza obejmuje wiele operacji odczytu (dwie lub więcej) tego samego wiersza, przy czym za każdym razem informacje są zmieniane przez inną transakcję; stąd termin niepowtarzalny odczyt.
Na przykład edytor odczytuje ten sam dokument dwa razy, ale między każdym z czytań autor przepisuje dokument. Gdy edytor odczytuje dokument po raz drugi, zmienił się. Oryginalny odczyt nie był powtarzalny. Można byłoby uniknąć tego problemu, gdyby autor nie mógł zmieniać dokumentu, dopóki redaktor nie przeczyta go po raz ostatni.
Phantom odczytuje
Odczyt phantom jest sytuacją, która występuje, gdy są wykonywane dwa identyczne zapytania, a zestaw wierszy zwracanych przez drugie zapytanie jest inny. W poniższym przykładzie pokazano, jak może się to zdarzyć. Załóżmy, że dwie transakcje są wykonywane w tym samym czasie. Dwie instrukcje
SELECT
w pierwszej transakcji mogą zwracać różne wyniki, ponieważ instrukcjaINSERT
w drugiej transakcji zmienia dane używane przez obie te transakcje.--Transaction 1 BEGIN TRAN; SELECT ID FROM dbo.employee WHERE ID > 5 AND ID < 10; --The INSERT statement from the second transaction occurs here. SELECT ID FROM dbo.employee WHERE ID > 5 and ID < 10; COMMIT;
--Transaction 2 BEGIN TRAN; INSERT INTO dbo.employee (Id, Name) VALUES(6 ,'New'); COMMIT;
Brakujące i podwójne odczyty spowodowane aktualizacjami wierszy
Brak zaktualizowanego wiersza lub wielokrotne wyświetlanie zaktualizowanego wiersza
Transakcje działające na poziomie
READ UNCOMMITTED
(lub instrukcje korzystające ze wskazówki tabeliNOLOCK
) nie przydzielają blokad współdzielonych, w celu uniemożliwienia innym transakcjom modyfikowania danych odczytanych przez bieżącą transakcję. Transakcje uruchomione na poziomieREAD COMMITTED
powodują problemy z blokadami udostępnionymi, ale blokady wiersza lub strony są zwalniane po odczytaniu wiersza. W obu przypadkach podczas skanowania indeksu, jeśli inny użytkownik zmieni kolumnę klucza indeksu wiersza podczas odczytu, wiersz może pojawić się ponownie, jeśli zmiana klucza przeniosła wiersz na pozycję przed skanowaniem. Podobnie wiersz może nie być w ogóle odczytany, jeśli zmiana klucza przeniosła wiersz do pozycji w indeksie, która została już odczytana. Aby tego uniknąć, użyj wskazówkiSERIALIZABLE
lubHOLDLOCK
albo wersjonowania wierszy. Aby uzyskać więcej informacji, zobacz Wskazówki dotyczące tabel (Transact-SQL).Brak co najmniej jednego wiersza, który nie był celem aktualizacji
Podczas gdy używasz
READ UNCOMMITTED
, jeśli twoje zapytanie odczytuje wiersze przy użyciu skanowania kolejności alokacji (przy użyciu stron IAM), możesz przegapić wiersze, jeśli inna transakcja powoduje podział strony. Nie występuje to w przypadku korzystania z poziomu izolacjiREAD COMMITTED
.
Typy współbieżności
Gdy wiele transakcji próbuje zmodyfikować dane w bazie danych w tym samym czasie, należy zaimplementować system kontroli, aby modyfikacje wprowadzone przez jedną transakcję nie miały negatywnego wpływu na te z innej transakcji. Jest to nazywane kontrolką współbieżności.
Teoria kontroli współbieżności ma dwie klasyfikacje metod instalowania kontroli współbieżności:
pesymistyczne sterowanie współbieżnością
System blokad uniemożliwia transakcjom modyfikowanie danych w sposób, który wpływa na inne transakcje. Po wykonaniu przez transakcję akcji, która powoduje zastosowanie blokady, inne transakcje nie mogą wykonywać akcji powodujących konflikt z blokadą, dopóki właściciel go nie zwolni. Jest to nazywane pesymistyczną kontrolą, ponieważ jest zwykle używana w systemach, w których występuje duża rywalizacja o dane, gdzie koszt ochrony danych za pomocą blokad jest mniejszy niż koszt wycofywania transakcji, jeśli wystąpią konflikty współbieżności.
Optymistyczna kontrola współbieżności
W przypadku optymistycznej kontroli współbieżności transakcje nie blokują danych podczas ich odczytywania. Jednak gdy transakcja aktualizuje dane, system sprawdza, czy inna transakcja zmieniła dane po jego odczytaniu. Jeśli inna transakcja zaktualizowała dane, zostanie zgłoszony błąd. Zazwyczaj transakcja, która napotyka błąd, cofa się i rozpoczyna od nowa. Jest to nazywane optymistycznym, ponieważ jest zwykle używane w systemach, w których występuje niskie współzawodnictwo o dane, a koszt od czasu do czasu wycofywania transakcji jest niższy niż koszt blokowania danych w momencie odczytu.
Aparat bazy danych obsługuje obie metody sterowania współbieżnością. Użytkownicy określają typ kontrolki współbieżności, wybierając poziomy izolacji transakcji dla połączeń lub opcji współbieżności na kursorach. Te atrybuty można zdefiniować przy użyciu instrukcji Transact-SQL lub za pomocą właściwości i atrybutów interfejsów programowania aplikacji bazy danych (API), takich jak ADO, ADO.NET, OLE DB i ODBC.
Poziomy izolacji w aparacie bazy danych
Transakcje określają poziom izolacji, który definiuje stopień, w jakim jedna transakcja musi być odizolowana od modyfikacji zasobów lub danych dokonanych przez inne transakcje. Poziomy izolacji są opisane pod kątem skutków ubocznych współbieżności, takich jak na przykład brudne odczyty czy odczyty fantomowe, które mogą być dopuszczalne.
Kontrola poziomów izolacji transakcji:
- Czy blokady są uzyskiwane podczas odczytywania danych oraz jaki typ blokad jest żądany.
- Jak długo są przechowywane blokady odczytu.
- Czy operacja odczytu, która odwołuje się do wierszy zmodyfikowanych przez inną transakcję, jest dopuszczalna?
- Blokuje blokadę do momentu zwolnienia blokady na wyłączność w wierszu.
- Pobiera zatwierdzoną wersję wiersza, która istniała w momencie uruchomienia instrukcji lub transakcji.
- Odczytuje niezatwierdzone modyfikacje danych.
Ważny
Wybranie poziomu izolacji transakcji nie ma wpływu na blokady uzyskane w celu ochrony modyfikacji danych. Transakcja zawsze przechowuje wyłączną blokadę w celu przeprowadzenia modyfikacji danych i przechowuje tę blokadę do momentu zakończenia transakcji, niezależnie od poziomu izolacji ustawionego dla tej transakcji. W przypadku operacji odczytu poziomy izolacji transakcji definiują przede wszystkim poziom ochrony przed skutkami modyfikacji wprowadzonych przez inne transakcje.
Niższy poziom izolacji zwiększa zdolność wielu transakcji do jednoczesnego dostępu do danych, ale także zwiększa liczbę efektów współbieżności, takich jak brudne odczyty lub utracone aktualizacje, które transakcje mogą napotkać. Z drugiej strony wyższy poziom izolacji zmniejsza typy skutków współbieżności, które mogą napotkać transakcje, ale wymaga więcej zasobów systemowych i zwiększa prawdopodobieństwo, że jedna transakcja blokuje inną. Wybór odpowiedniego poziomu izolacji zależy od równoważenia wymagań dotyczących integralności danych aplikacji na poziomie obciążenia poszczególnych poziomów izolacji. Najwyższy poziom izolacji, SERIALIZABLE
, gwarantuje, że transakcja pobiera dokładnie te same dane za każdym razem, gdy powtarza operację odczytu, ale robi to, wykonując poziom blokowania, który może mieć wpływ na inne transakcje w systemach wielu użytkowników. Najniższy poziom izolacji, READ UNCOMMITTED
, może pobierać dane zmodyfikowane, ale niezatwierdzone przez inne transakcje. Wszystkie skutki uboczne współbieżności mogą wystąpić w READ UNCOMMITTED
, ale nie ma blokady odczytu ani przechowywania wersji, więc obciążenie jest zminimalizowane.
Poziomy izolacji aparatu bazy danych
Standard ISO definiuje następujące poziomy izolacji, z których wszystkie są obsługiwane przez aparat bazy danych:
Poziom izolacji | Definicja |
---|---|
READ UNCOMMITTED |
Najniższy poziom izolacji, na którym transakcje są izolowane tylko na tyle, aby upewnić się, że dane fizycznie niespójne nie są odczytywane. Na tym poziomie dozwolone są brudne odczyty, więc jedna transakcja może zobaczyć niezatwierdzone zmiany wprowadzone przez inne transakcje. |
READ COMMITTED |
Umożliwia transakcji odczytywanie danych wcześniej odczytanych (niezmodyfikowanych) przez inną transakcję bez oczekiwania na ukończenie pierwszej transakcji. Aparat bazy danych przechowuje blokady zapisu (nabyte na wybranych danych) do końca transakcji, ale blokady odczytu są zwalniane natychmiast po wykonaniu operacji odczytu. Jest to domyślny poziom silnika bazy danych. |
REPEATABLE READ |
Silnik bazy danych przechowuje blokady odczytu i zapisu, które są nałożone na wybrane dane do końca transakcji. Jednak ze względu na to, że blokady zakresu nie są zarządzane, mogą wystąpić odczyty widmowe. |
SERIALIZABLE |
Najwyższy poziom, na którym transakcje są całkowicie odizolowane od siebie. Aparat bazy danych przechowuje blokady odczytu i zapisu pozyskane na wybranych danych do końca transakcji. Blokady zakresu są uzyskiwane, gdy operacja SELECT używa klauzuli WHERE zakresu, aby uniknąć odczytów fantomowych. Uwaga: operacje DDL i transakcje w replikowanych tabelach mogą zakończyć się niepowodzeniem, gdy wymaga się poziomu izolacji SERIALIZABLE . Dzieje się tak, ponieważ zapytania replikacji używają wskazówek, które mogą być niezgodne z poziomem izolacji SERIALIZABLE . |
Silnik bazy danych obsługuje również dwa dodatkowe poziomy izolacji transakcji, które używają wersjonowania wierszy. Jedną z nich jest implementacja poziomu izolacji READ COMMITTED
, a drugi to SNAPSHOT
poziom izolacji transakcji.
Poziom izolacji wersjonowania wierszy | Definicja |
---|---|
Read Committed Snapshot (RCSI) |
Po ustawieniu opcji bazy danych READ_COMMITTED_SNAPSHOT na ON (domyślne ustawienie w usłudze Azure SQL Database), poziom izolacji READ COMMITTED używa wersjonowania wierszy w celu zapewnienia spójności odczytu na poziomie instrukcji. Operacje odczytu wymagają tylko blokad na poziomie tabeli zapewniających stabilność schematu (Sch-S ) i bez blokad stron ani wierszy. Oznacza to, że silnik bazy danych używa wersjonowania wierszy, aby przedstawić każdą instrukcję w postaci transakcyjnie spójnej migawki danych, jaką istniała na początku tej instrukcji. Blokady nie są używane do ochrony danych przed aktualizacjami przez inne transakcje. Funkcja zdefiniowana przez użytkownika może zwracać dane zatwierdzone po rozpoczęciu instrukcji zawierającej funkcję UDF.Gdy opcja READ_COMMITTED_SNAPSHOT bazy danych jest skonfigurowana na OFF , co jest ustawieniem domyślnym w programie SQL Server i usłudze Azure SQL Managed Instance, izolacja READ COMMITTED używa udostępnionych blokad, aby zapobiec modyfikowaniu wierszy przez inne transakcje, podczas gdy bieżąca transakcja uruchamia operację odczytu. Udostępnione blokady blokują również instrukcję odczytu wierszy zmodyfikowanych przez inne transakcje do momentu zakończenia innej transakcji. Obie implementacje spełniają definicję ISO izolacji READ COMMITTED . |
SNAPSHOT |
Poziom izolacji migawki używa wersjonowania wierszy, aby zapewnić spójność odczytu na poziomie transakcji. Operacje odczytu nie uzyskują blokad stron ani blokad wierszy; uzyskiwane są jedynie blokady tabel związane z stabilnością schematuSch-S . Podczas odczytywania wierszy zmodyfikowanych przez inną transakcję operacje odczytu pobierają wersję wiersza, która istniała podczas uruchamiania transakcji. Izolację SNAPSHOT można używać tylko wtedy, gdy opcja bazy danych ALLOW_SNAPSHOT_ISOLATION jest ustawiona na wartość ON . Domyślnie ta opcja jest ustawiona na OFF dla baz danych użytkowników w programie SQL Server i usłudze Azure SQL Managed Instance oraz ustawiono wartość ON dla baz danych w usłudze Azure SQL Database.Uwaga: Aparat bazy danych nie obsługuje przechowywania wersji metadanych. Z tego powodu istnieją ograniczenia co do operacji DDL, które można przeprowadzać w jawnej transakcji działającej pod izolacją migawkową. Następujące instrukcje DDL nie są dozwolone w trybie izolacji migawkowej po instrukcji BEGIN TRANSACTION : ALTER TABLE , CREATE INDEX , CREATE XML INDEX , ALTER INDEX , DROP INDEX , DBCC REINDEX , ALTER PARTITION FUNCTION , ALTER PARTITION SCHEME ani w żadnej instrukcji DDL uruchamianej przez środowisko CLR (Common Language Runtime). Instrukcje tego rodzaju są dozwolone w przypadku korzystania z izolacji migawki w niejawnych transakcjach. Zgodnie z definicją, niejawna transakcja to pojedyncza instrukcja umożliwiająca wymuszenie semantyki izolacji migawkowej, nawet przy użyciu instrukcji DDL. Naruszenia tej zasady mogą powodować błąd 3961: Snapshot isolation transaction failed in database '%.*ls' because the object accessed by the statement has been modified by a DDL statement in another concurrent transaction since the start of this transaction. It is not allowed because the metadata is not versioned. A concurrent update to metadata could lead to inconsistency if mixed with snapshot isolation. |
W poniższej tabeli przedstawiono efekty uboczne współbieżności uaktywniane przez różne poziomy izolacji.
Poziom izolacji | Odczyt zanieczyszczony | Niepowtarzalny odczyt | Fantom |
---|---|---|---|
READ UNCOMMITTED |
Tak | Tak | Tak |
READ COMMITTED |
Nie | Tak | Tak |
REPEATABLE READ |
Nie | Nie | Tak |
SNAPSHOT |
Nie | Nie | Nie |
SERIALIZABLE |
Nie | Nie | Nie |
Aby uzyskać więcej informacji na temat określonych typów blokowania lub wersjonowania wierszy kontrolowanych przez każdy poziom izolacji transakcji, zobacz SET TRANSACTION ISOLATION LEVEL (Transact-SQL).
Poziomy izolacji transakcji można ustawić przy użyciu Transact-SQL lub interfejsu API bazy danych.
Transact-SQL
Transact-SQL skrypty używają instrukcji SET TRANSACTION ISOLATION LEVEL
.
ADO
Aplikacje ADO ustawiają właściwość IsolationLevel
obiektu Connection
na adXactReadUncommitted
, adXactReadCommitted
, adXactRepeatableRead
lub adXactReadSerializable
.
ADO.NET
Aplikacje ADO.NET korzystające z zarządzanej przestrzeni nazw System.Data.SqlClient
mogą wywoływać metodę SqlConnection.BeginTransaction
, ustawiając opcję IsolationLevel
na Unspecified
, Chaos
, ReadUncommitted
, ReadCommitted
, RepeatableRead
, Serializable
lub Snapshot
.
OLE DB
Podczas inicjowania transakcji aplikacje korzystające z OLE DB wywołują ITransactionLocal::StartTransaction
z isoLevel
ustawionym na ISOLATIONLEVEL_READUNCOMMITTED
, ISOLATIONLEVEL_READCOMMITTED
, ISOLATIONLEVEL_REPEATABLEREAD
, ISOLATIONLEVEL_SNAPSHOT
lub ISOLATIONLEVEL_SERIALIZABLE
.
Podczas określania poziomu izolacji transakcji w trybie automatycznego zatwierdzania aplikacje OLE DB mogą ustawić DBPROPSET_SESSION
właściwości DBPROP_SESS_AUTOCOMMITISOLEVELS
na DBPROPVAL_TI_CHAOS
, DBPROPVAL_TI_READUNCOMMITTED
, DBPROPVAL_TI_BROWSE
, DBPROPVAL_TI_CURSORSTABILITY
, DBPROPVAL_TI_READCOMMITTED
, DBPROPVAL_TI_REPEATABLEREAD
, DBPROPVAL_TI_SERIALIZABLE
, DBPROPVAL_TI_ISOLATED
lub DBPROPVAL_TI_SNAPSHOT
.
ODBC
Aplikacje ODBC wywołują SQLSetConnectAttr
, mając Attribute
ustawione na SQL_ATTR_TXN_ISOLATION
oraz ValuePtr
ustawione na SQL_TXN_READ_UNCOMMITTED
, SQL_TXN_READ_COMMITTED
, SQL_TXN_REPEATABLE_READ
lub SQL_TXN_SERIALIZABLE
.
W przypadku transakcji migawek aplikacje wywołają SQLSetConnectAttr
z atrybutem ustawionym na SQL_COPT_SS_TXN_ISOLATION
i ValuePtr
ustawionym na wartość SQL_TXN_SS_SNAPSHOT
. Transakcję migawki można pobrać przy użyciu SQL_COPT_SS_TXN_ISOLATION
lub SQL_ATTR_TXN_ISOLATION
.
Blokowanie silnika bazy danych
Blokowanie jest mechanizmem używanym przez aparat bazy danych do synchronizowania dostępu wielu użytkowników z tym samym elementem danych w tym samym czasie.
Zanim transakcja uzyska zależność od bieżącego stanu danych, takich jak odczytywanie lub modyfikowanie danych, musi chronić się przed skutkami innej transakcji modyfikujące te same dane. Transakcja robi to, żądając blokady na fragmencie danych. Blokady mają różne tryby, takie jak współużytkowany (S
) lub wyłączny (X
). Tryb blokady definiuje poziom zależności transakcji na danych. Nie można przyznać żadnej transakcji blokady, która powoduje konflikt z trybem blokady już przyznanej na tych samych danych innej transakcji. Jeśli transakcja żąda trybu blokady, który powoduje konflikt z blokadą, która została już udzielona na tych samych danych, aparat bazy danych wstrzyma żądającą transakcję do momentu wydania pierwszej blokady.
Gdy transakcja modyfikuje fragment danych, przechowuje pewne blokady chroniące modyfikację do końca transakcji. Czas przechowywania blokad nabytych w celu zabezpieczenia operacji odczytu zależy od ustawienia poziomu izolacji transakcji i tego, czy funkcja zoptymalizowanego blokowania jest włączona.
Gdy zoptymalizowane blokowanie nie jest włączone, blokady wierszy i stron niezbędne do zapisu są przechowywane do końca transakcji.
Po włączeniu zoptymalizowanego blokowania trzymana jest tylko blokada identyfikatora transakcji (TID) do końca transakcji. W ramach domyślnego poziomu izolacji
READ COMMITTED
transakcje nie będą przechowywać blokad wierszy i stron niezbędnych do zapisu do końca transakcji. Zmniejsza to wymaganą pamięć blokady i zmniejsza potrzebę eskalacji blokady. Ponadto po włączeniu zoptymalizowanego blokowania blokada po kwalifikacjach (LAQ) optymalizacji ocenia predykaty zapytania w najnowszej zatwierdzonej wersji wiersza bez uzyskiwania blokady, poprawiając współbieżność.
Wszystkie blokady przechowywane przez transakcję są zwalniane po zakończeniu transakcji (zatwierdzenia lub wycofania).
Aplikacje zwykle nie żądają blokad bezpośrednio. Blokady są zarządzane wewnętrznie przez część modułu bazy danych nazywaną menedżerem blokad. Gdy instancja aparatu bazy danych przetwarza instrukcję Transact-SQL, procesor zapytań aparatu bazy danych określa, które zasoby mają być uzyskane. Procesor zapytań określa, jakie typy blokad są wymagane do ochrony każdego zasobu na podstawie typu dostępu i ustawienia poziomu izolacji transakcji. Następnie procesor zapytań żąda odpowiednich blokad u menedżera blokad. Menedżer blokad przyznaje blokady, jeśli nie ma żadnych konfliktowych blokad przechowywanych przez inne transakcje.
Blokowanie stopnia szczegółowości i hierarchii
Silnik bazy danych ma wielogranularne blokady, które umożliwiają zablokowanie przez transakcję różnych typów zasobów. Aby zminimalizować koszt blokowania, aparat bazy danych automatycznie blokuje zasoby na poziomie odpowiednim dla zadania. Blokowanie przy mniejszej szczegółowości, takiej jak wiersze, zwiększa współbieżność, ale ma większe obciążenie, ponieważ więcej blokad musi być przechowywanych, jeśli wiele wierszy jest zablokowanych. Blokowanie większego stopnia szczegółowości, takiego jak tabele, jest kosztowne pod względem współbieżności, ponieważ blokowanie całej tabeli ogranicza dostęp do dowolnej części tabeli przez inne transakcje. Jednak ma mniejsze obciążenie, ponieważ jest utrzymywana mniejsza liczba blokad.
Silnik bazy danych często musi uzyskać blokady na różnych poziomach, aby w pełni chronić zasób. Ta grupa blokad na wielu poziomach szczegółowości jest nazywana hierarchią blokady. Na przykład aby w pełni chronić odczyt indeksu, wystąpienie aparatu bazy danych może wymagać uzyskania blokad współdzielonych na wierszach i blokad współdzielonych intencji na stronach i tabeli.
W poniższej tabeli przedstawiono zasoby, które aparat bazy danych może zablokować.
Zasób | Opis |
---|---|
RID |
Identyfikator wiersza używany do blokowania pojedynczego wiersza w stercie danych. |
KEY |
Blokada wiersza w celu zablokowania pojedynczego wiersza w indeksie drzewa B. |
PAGE |
Strona 8 kilobajtów (KB) w bazie danych, taka jak dane lub strony indeksu. |
EXTENT |
Ciągła grupa ośmiu stron, takich jak dane lub strony indeksu. |
HoBT
1 |
Sterta lub drzewo B. Blokada chroniąca drzewo B (indeks) lub strony danych stert w tabeli, która nie ma indeksu klastrowanego. |
TABLE
1 |
Cała tabela, w tym wszystkie dane i indeksy. |
FILE |
Plik bazy danych. |
APPLICATION |
Zasób określony przez aplikację. |
METADATA |
Blokady metadanych. |
ALLOCATION_UNIT |
Jednostka alokacji. |
DATABASE |
Cała baza danych. |
XACT
2 |
Blokada identyfikatora transakcji (TID) używana w Zoptymalizowane blokowanie. Aby uzyskać więcej informacji, zobacz blokowanie identyfikatorów transakcji (TID) . |
1HoBT
i TABLE
zamki mogą być wpływane przez opcję LOCK_ESCALATION
ALTER TABLE.
2 Dodatkowe zasoby blokujące są dostępne dla zasobów blokady XACT
, zobacz Dodatki diagnostyczne w celu zoptymalizowanego blokowania.
Tryby blokowania
Silnik bazy danych blokuje zasoby przy użyciu różnych trybów blokowania, które określają, jak zasoby mogą być używane przez współbieżne transakcje.
W poniższej tabeli przedstawiono tryby blokowania zasobów używane przez aparat bazy danych.
Tryb blokady | Opis |
---|---|
udostępnione (S ) |
Służy do operacji odczytu, które nie zmieniają ani nie aktualizują danych, takich jak instrukcja SELECT . |
Aktualizacja (U ) |
Używane w zasobach, które można zaktualizować. Zapobiega typowej formie zakleszczenia, która występuje, gdy wiele sesji odczytuje, blokuje i potencjalnie aktualizuje zasoby później. |
ekskluzywne (X ) |
Służy do operacji modyfikacji danych, takich jak INSERT , UPDATE lub DELETE . Gwarantuje, że w tym samym czasie nie można wprowadzić wielu aktualizacji do tego samego zasobu. |
intencja | Służy do ustanawiania hierarchii blokady. Typy blokad intencji to: intencja wspólna (IS ), intencja wyłączna (IX ) i wspólna z intencją wyłączną (SIX ). |
Schema | Używane, gdy operacja zależna od schematu tabeli jest wykonywana. Typy blokad schematu to: modyfikacja schematu (Sch-M ) i stabilność schematu (Sch-S ). |
Aktualizacja zbiorcza (BU ) |
Używane podczas zbiorczego kopiowania danych do tabeli za pomocą wskazówki TABLOCK . |
zakres kluczy | Chroni zakres wierszy odczytywanych przez zapytanie podczas korzystania z poziomu izolacji transakcji SERIALIZABLE . Zapewnia, że inne transakcje nie mogą wstawiać wierszy, które kwalifikowałyby się do zapytań transakcji SERIALIZABLE , gdyby zapytania te zostały wykonane ponownie. |
Blokady dzielone
Udostępnione (S
) blokady umożliwiają równoczesnym transakcjom odczytywanie zasobu w ramach pesymistycznej kontroli współbieżności. Żadne inne transakcje nie mogą modyfikować danych, gdy na zasobie istnieją współdzielone blokady (S
). Udostępnione (S
) blokady na zasobie są zwalniane natychmiast po zakończeniu operacji odczytu, chyba że poziom izolacji transakcji jest ustawiony na REPEATABLE READ
lub wyżej, albo użyta jest wskazówka blokady w celu zachowania udostępnionych (S
) blokad na czas trwania transakcji.
Blokady aktualizacji
Silnik bazy danych umieszcza blokady aktualizacji (U
) podczas przygotowywania się do wykonania aktualizacji.
U
blokady są zgodne z blokadami S
, ale tylko jedna transakcja może przechowywać blokadę U
jednocześnie dla danego zasobu. Jest to kluczowe — wiele współbieżnych transakcji może trzymać blokady S
, ale tylko jedna transakcja może utrzymywać blokadę U
na zasobie. Blokady aktualizacji (U
) z czasem zostają zamienione na blokady na wyłączność (X
), aby zaktualizować wiersz.
Blokady aktualizacji (U
) mogą być również wykonywane przez instrukcje inne niż UPDATE
, gdy w instrukcji jest określona wskazówka tabeli UPDLOCK.
Niektóre aplikacje używają wzorca "wybierz wiersz, a następnie zaktualizuj wiersz", w którym odczyt i zapis są jawnie oddzielone w ramach transakcji. W takim przypadku, jeśli poziom izolacji jest
REPEATABLE READ
lubSERIALIZABLE
, współbieżne aktualizacje mogą spowodować zakleszczenie w następujący sposób:Transakcja odczytuje dane, uzyskuje dzieloną (
S
) blokadę zasobu, a następnie modyfikuje dane, co wymaga konwersji blokady na wyłączną (X
) blokadę. Jeśli dwie transakcje uzyskają współużytkowane (S
) blokady zasobu, a następnie spróbują zaktualizować dane jednocześnie, jedna z transakcji podejmie próbę przekształcenia blokady we wyłączną (X
) blokadę. Przekształcenie blokady udostępnionej na blokadę wyłączności musi czekać, ponieważ blokada wyłączności (X
) dla jednej transakcji nie jest zgodna z blokadą udostępnioną (S
) innej transakcji; występuje czekanie na blokadę. Druga transakcja próbuje uzyskać wyłączną blokadę (X
) dla jej aktualizacji. Ponieważ obie transakcje przekształcają się w blokady na wyłączność (X
) i każda z nich czeka, aż druga transakcja zwolni swoją współdzieloną blokadę (S
), występuje zakleszczenie.W domyślnym
READ COMMITTED
poziomie izolacjiS
blokady trwają krótko, zwalniane natychmiast po ich użyciu. Chociaż zakleszczenie opisane powyżej jest nadal możliwe, jest znacznie mniej prawdopodobne przy blokadach o krótkim czasie trwania.Aby uniknąć tego typu zakleszczenia, aplikacje mogą postępować zgodnie z wzorcem "wybierz wiersz ze wskazówką
UPDLOCK
, a następnie zaktualizuj wiersz".Jeśli wskazówka
UPDLOCK
jest używana w zapisie, gdy izolacjaSNAPSHOT
jest używana, transakcja musi mieć dostęp do najnowszej wersji wiersza. Jeśli najnowsza wersja nie jest już widoczna, można odbieraćMsg 3960, Level 16, State 2 Snapshot isolation transaction aborted due to update conflict
. Aby zapoznać się z przykładem, zobacz Work with snapshot isolation (Praca z izolacją migawki).
Zamki wyłącznościowe
Blokady na wyłączność (X
) uniemożliwiają dostęp do zasobu za pomocą transakcji współbieżnych. Z wyłączną blokadą (X
) żadne inne transakcje nie mogą modyfikować danych chronionych przez blokadę; Operacje odczytu mogą odbywać się tylko przy użyciu wskazówki NOLOCK
lub poziomu izolacji READ UNCOMMITTED
.
Instrukcje modyfikacji danych, takie jak INSERT
, UPDATE
i DELETE
łączą operacje odczytu i modyfikacji. Instrukcja najpierw wykonuje operacje odczytu w celu uzyskania danych przed wykonaniem wymaganych operacji modyfikacji. W związku z tym instrukcje modyfikacji danych zwykle żądają blokad udostępnionych i blokad wyłącznych. Na przykład instrukcja UPDATE
może modyfikować wiersze w jednej tabeli na podstawie sprzężenia z inną tabelą. W tym przypadku instrukcja UPDATE
żąda udostępnionych blokad w wierszach odczytanych w tabeli sprzężeń oprócz żądania blokad wyłącznych w zaktualizowanych wierszach.
Blokady intencji
Silnik bazy danych używa blokad intencji w celu ochrony umieszczenia blokady współdzielonej (S
) lub blokady wyłącznej (X
) na zasobie na niższym poziomie hierarchii blokady. Blokady intencji mają nazwę "blokady intencji", ponieważ są uzyskiwane przed blokadą na niższym poziomie i sygnalizują zamiar umieszczenia blokad na niższym poziomie.
Blokady intencji służą dwóm celom:
- Aby uniemożliwić innym transakcjom modyfikowanie zasobu wyższego poziomu w sposób, który unieważniłby blokadę na niższym poziomie.
- Aby zwiększyć efektywność silnika bazy danych w wykrywaniu konfliktów blokad na wyższym poziomie szczegółowości.
Na przykład blokada intencji współdzielonej jest żądana na poziomie tabeli, zanim blokady wspólne (S
) zostaną zażądane na stronach lub wierszach w tej tabeli. Ustawienie blokady intencji na poziomie tabeli uniemożliwia kolejnemu transakcji późniejsze uzyskanie wyłącznej blokady (X
) w tabeli zawierającej tę stronę. Blokady intencji zwiększają wydajność, ponieważ aparat bazy danych analizuje blokady intencji tylko na poziomie tabeli, aby określić, czy transakcja może bezpiecznie uzyskać blokadę w tej tabeli. Spowoduje to usunięcie wymogu zbadania każdego wiersza lub blokady strony w tabeli w celu określenia, czy transakcja może zablokować całą tabelę.
blokady intencji obejmują blokadę dzielonej intencji (IS
), blokadę wyłącznej intencji (IX
) i dzielone z wyłączną intencją (SIX
).
Tryb blokady | Opis |
---|---|
Intencja udostępniona (IS ) |
Zabezpiecza żądane lub pozyskane blokady udostępnione dla niektórych (ale nie wszystkich) zasobów na niższych poziomach hierarchii. |
Intent exclusive (IX ) |
Chroni żądane lub pozyskane blokady na wyłączność w niektórych (ale nie wszystkich) zasobach niższych w hierarchii.
IX jest nadzbiorem IS , a także chroni żądania udostępnionych blokad na zasobach niższego poziomu. |
Udostępnione z zamiarem wyłączności (SIX ) |
Chroni żądane lub pozyskane blokady współdzielone na wszystkich zasobach niższych w hierarchii oraz intencjonalne blokady wyłączne na niektórych (ale nie wszystkich) zasobach niższego poziomu. Na najwyższym poziomie zasobów dozwolone są współbieżne blokady IS . Na przykład uzyskanie blokady SIX w tabeli uzyskuje również blokady intencjonalne wyłączności na stronach, które są modyfikowane, oraz blokady wyłączające na zmodyfikowanych wierszach. Jednocześnie na dany zasób może istnieć tylko jedna blokada SIX , co uniemożliwia innym transakcjom jego aktualizację. Jednak inne transakcje mogą odczytywać zasoby niższe w hierarchii, uzyskując blokady IS na poziomie tabeli. |
aktualizacja intencji (IU ) |
Chroni żądane lub pozyskane blokady aktualizacji dla wszystkich zasobów niższych w hierarchii. blokady IU są używane tylko w zasobach strony internetowej.
IU blokady są konwertowane na blokady IX w przypadku przeprowadzenia operacji aktualizacji. |
aktualizacja intencji współdzielonej (SIU ) |
Połączenie blokad S i IU jest rezultatem uzyskania tych blokad oddzielnie i jednoczesnego trzymania obydwóch. Na przykład transakcja wykonuje zapytanie z wskazówką PAGLOCK , a następnie wykonuje operację aktualizacji. Zapytanie ze wskazówką PAGLOCK uzyskuje blokadę S , a operacja aktualizacji uzyskuje blokadę IU . |
Zamiar aktualizacji wyłączny (UIX ) |
Połączenie blokad U i IX jest rezultatem uzyskania tych blokad oddzielnie i jednoczesnego trzymania obydwóch. |
Blokady schematu
Silnik bazy danych używa blokad modyfikacji schematu (Sch-M
) podczas operacji języka definicji danych tabeli (DDL), takich jak dodanie kolumny lub usunięcie tabeli. W czasie, gdy jest on przechowywany, blokada Sch-M
uniemożliwia współbieżny dostęp do tabeli. Oznacza to, że blokada Sch-M
blokuje wszystkie operacje zewnętrzne do momentu zwolnienia blokady.
Niektóre operacje języka manipulowania danymi (DML), takie jak truncowanie tabeli, używają Sch-M
blokad, aby zapobiec dostępowi do tabel objętych operacjami współbieżnymi.
Silnik bazy danych używa blokad stabilności schematu (Sch-S
) podczas kompilowania i wykonywania zapytań.
Sch-S
zamki nie blokują żadnych blokad transakcyjnych, w tym blokad wyłącznych (X
). W związku z tym inne transakcje, w tym z blokadami X
na tabeli, nadal działają podczas kompilowania zapytania. Jednak współbieżne operacje DDL i współbieżne operacje DML, które uzyskują blokady Sch-M
, są blokowane przez blokady Sch-S
.
Blokady aktualizacji zbiorczej
Blokady zbiorczych aktualizacji (BU
) umożliwiają wielu wątkom współbieżne ładowanie danych do tej samej tabeli, uniemożliwiając jednocześnie innym procesom, które nie ładują zbiorczo danych, dostęp do tabeli. Silnik bazy danych używa blokad aktualizacji zbiorczej (BU
), gdy oba poniższe warunki są spełnione.
- Używasz instrukcji Transact-SQL
BULK INSERT
lub funkcjiOPENROWSET(BULK)
lub jednego z poleceń interfejsu API wstawiania zbiorczego, takich jak .NETSqlBulkCopy
, interfejsy API szybkiego ładowania OLEDB lub interfejsy API kopiowania zbiorczego ODBC, aby zbiorczo skopiować dane do tabeli. - Określono wskazówkę
TABLOCK
lub ustawiono opcję tabelitable lock on bulk load
przy użyciu sp_tableoption.
Napiwek
W przeciwieństwie do instrukcji BULK INSERT, która utrzymuje mniej restrykcyjną blokadę aktualizacji zbiorczej (BU
), INSERT INTO...SELECT
ze wskazówką TABLOCK
utrzymuje blokadę zamierzonej wyłączności (IX
) na tabeli. Oznacza to, że nie można wstawić wierszy przy użyciu operacji wstawiania równoległego.
Blokady zakresu kluczy
Blokady zakresu kluczy chronią zakres wierszy niejawnie uwzględnionych w zestawie rekordów odczytywanych przez instrukcję Transact-SQL podczas korzystania z poziomu izolacji transakcji SERIALIZABLE
. Blokowanie zakresu kluczy uniemożliwia odczyty phantom. Dzięki ochronie zakresów kluczy między wierszami zapobiega również wstawianiu lub usuwaniu zjaw w zestawie rekordów, do których uzyskuje dostęp transakcja.
Zablokuj zgodność
Zgodność blokad określa, czy wiele transakcji może jednocześnie uzyskiwać blokady na tym samym zasobie. Jeśli zasób jest już zablokowany przez inną transakcję, można udzielić nowego żądania blokady tylko wtedy, gdy tryb żądanej blokady jest zgodny z trybem istniejącej blokady. Jeśli tryb żądanej blokady nie jest zgodny z istniejącą blokadą, transakcja żądająca nowej blokady czeka na zwolnienie istniejącej blokady lub wygaśnięcie czasu oczekiwania na blokadę. Na przykład żadne tryby blokady nie są zgodne z blokadami wyłącznymi. Gdy blokada wyłączna (X
) jest utrzymywana, żadna inna transakcja nie może uzyskać blokady żadnego rodzaju (udostępnionej, aktualizacyjnej lub wyłącznej) na tym zasobie, dopóki blokada wyłączna (X
) nie zostanie zwolniona. Z drugiej strony, jeśli blokada współdzielona (S
) została zastosowana do zasobu, inne transakcje mogą również uzyskać blokadę współdzieloną lub blokadę aktualizacyjną (U
) na ten zasób, nawet jeśli pierwsza transakcja nie została ukończona. Jednak inne transakcje nie mogą uzyskać wyłącznej blokady, dopóki blokada współdzielona nie zostanie zwolniona.
Poniższa tabela przedstawia zgodność najczęściej spotykanych trybów blokowania.
Istniejący tryb udzielony | IS |
S |
U |
IX |
SIX |
X |
---|---|---|---|---|---|---|
żądany tryb | ||||||
Intencja udostępniona (IS ) |
Tak | Tak | Tak | Tak | Tak | Nie |
udostępnione (S ) |
Tak | Tak | Tak | Nie | Nie | Nie |
Aktualizacja (U ) |
Tak | Tak | Nie | Nie | Nie | Nie |
Intent exclusive (IX ) |
Tak | Nie | Nie | Tak | Nie | Nie |
Udostępnione z zamiarem wyłączności (SIX ) |
Tak | Nie | Nie | Nie | Nie | Nie |
ekskluzywne (X ) |
Nie | Nie | Nie | Nie | Nie | Nie |
Notatka
Blokada zamiaru ekskluzywnego (IX
) jest zgodna z trybem blokady IX
, ponieważ IX
oznacza, że zamiarem jest zaktualizowanie tylko niektórych wierszy, a nie wszystkich. Inne transakcje, które próbują odczytać lub zaktualizować niektóre wiersze, są również dozwolone, o ile nie są to same wiersze aktualizowane przez inne transakcje. Ponadto, jeśli dwie transakcje próbują zaktualizować ten sam wiersz, obie transakcje otrzymują blokadę IX
na poziomie tabeli i strony. Jednak jedna transakcja otrzymuje blokadę X
na poziomie wiersza. Druga transakcja musi czekać, aż zostanie usunięta blokada na poziomie wiersza.
Użyj poniższej tabeli, aby określić zgodność wszystkich trybów blokady dostępnych w silniku bazy danych.
Klucz | Opis |
---|---|
N | Brak konfliktu |
Ja | Nielegalny |
C | Konflikt |
NL | Brak blokady |
SCH-S | Blokada stabilności schematu |
SCH-M | Blokada modyfikacji schematu |
S | Udostępnione |
U | Aktualizacja |
X | Wyłączny |
JEST | Zamiar udostępniony |
J.M. | Aktualizacja intencji |
IX | Wyłączność intencji |
SIU | Udostępnij z aktualizacją intencji |
SZEŚĆ | Udostępnianie z intencją na wyłączność |
UIX | Aktualizacja z wyłącznym zamiarem |
BU | Aktualizacja zbiorcza |
RS-S | Współużytkowany zakres udostępniony |
RS-U | Aktualizacja zakresu udostępnionego |
RI-N | Wstaw zakres pusty |
RI-S | Wstaw współużytkowany zakres |
RI-U | Wstaw aktualizację zakresu |
RI-X | Wstaw wyłączność zakresu |
RX-S | Wyłączny zakres współdzielony |
RX-U | Ekskluzywna aktualizacja zakresu |
RX-X | Wyłączny zakres wyłączny |
Blokowanie zakresu kluczy
Blokady zakresu kluczy chronią zakres wierszy niejawnie uwzględnionych w zestawie rekordów odczytywanych przez instrukcję Transact-SQL podczas korzystania z poziomu izolacji transakcji SERIALIZABLE
. Poziom izolacji SERIALIZABLE
wymaga, aby każde zapytanie wykonywane podczas transakcji musiało uzyskać ten sam zestaw wierszy za każdym razem, gdy jest wykonywany podczas transakcji. Blokada zakresu kluczy spełnia to wymaganie, uniemożliwiając innym transakcjom wstawianie nowych wierszy, których klucze mieszczą się w zakresie kluczy odczytanych przez transakcję SERIALIZABLE
.
Blokowanie zakresu kluczy uniemożliwia odczyty phantom. Dzięki ochronie zakresów kluczy między wierszami uniemożliwia również wstawienia widmowe do zestawu rekordów, do których uzyskuje dostęp transakcja.
W indeksie umieszczana jest blokada zakresu kluczy, która określa początkową i końcową wartość klucza. Ta blokada blokuje wszelkie próby wstawiania, aktualizowania lub usuwania dowolnego wiersza z wartością klucza, która mieści się w zakresie, ponieważ te operacje musiałyby najpierw uzyskać blokadę indeksu. Na przykład transakcja SERIALIZABLE
może wydać instrukcję SELECT
, która odczytuje wszystkie wiersze, których wartości klucza pasują do warunku BETWEEN 'AAA' AND 'CZZ'
. Blokada zakresu kluczy dla wartości kluczy w zakresie od 'AAA' do 'CZZ' uniemożliwia innym transakcjom wstawianie wierszy z wartościami klucza w dowolnym miejscu w tym zakresie, takich jak 'ADG', 'BBD', lub 'CAL'.
Tryby blokady zakresu kluczy
Blokady zakresu kluczy obejmują zarówno zakres, jak i składnik wiersza określony w formacie wiersz-zakres.
- Zakres reprezentuje tryb blokady chroniący zakres między dwoma kolejnymi wpisami indeksu.
- Wiersz reprezentuje tryb blokady, który chroni wpis indeksowy.
- Tryb reprezentuje używany tryb połączonej blokady. Tryby blokady zakresu kluczy składają się z dwóch części. Pierwszy reprezentuje typ blokady używany do blokowania zakresu indeksów (zakresT), a drugi reprezentuje typ blokady używany do blokowania określonego klucza (K). Dwie części są połączone łącznikiem (-), takim jak RangeT-K.
Zakres | Szereg | Tryb | Opis |
---|---|---|---|
RangeS |
S |
RangeS-S |
Zakres udostępniony, blokada współużytkowanego zasobu; SERIALIZABLE skanowanie zakresu. |
RangeS |
U |
RangeS-U |
Zakres udostępniony, zaktualizuj blokadę zasobów; SERIALIZABLE aktualizacja skanu. |
RangeI |
Null |
RangeI-N |
Wstaw zakres, blokada zasobu o wartości null; używana do testowania zakresów przed wstawieniem nowego klucza do indeksu. |
RangeX |
X |
RangeX-X |
Wyłączny zakres, wyłączna blokada zasobów; używany podczas aktualizowania klucza w zakresie. |
Notatka
Wewnętrzny tryb blokady Null
jest zgodny ze wszystkimi innymi trybami blokady.
Tryby blokady zakresu kluczy mają macierz zgodności, która pokazuje, które blokady są zgodne z innymi blokadami uzyskanymi na nakładających się kluczach i zakresach.
Istniejący tryb udzielony | S |
U |
X |
RangeS-S |
RangeS-U |
RangeI-N |
RangeX-X |
---|---|---|---|---|---|---|---|
żądany tryb | |||||||
udostępnione (S ) |
Tak | Tak | Nie | Tak | Tak | Tak | Nie |
Aktualizacja (U ) |
Tak | Nie | Nie | Tak | Nie | Tak | Nie |
ekskluzywne (X ) |
Nie | Nie | Nie | Nie | Nie | Tak | Nie |
RangeS-S |
Tak | Tak | Nie | Tak | Tak | Nie | Nie |
RangeS-U |
Tak | Nie | Nie | Tak | Nie | Nie | Nie |
RangeI-N |
Tak | Tak | Tak | Nie | Nie | Tak | Nie |
RangeX-X |
Nie | Nie | Nie | Nie | Nie | Nie | Nie |
Blokady konwersji
Blokady konwersji są tworzone, gdy blokada zakresu kluczy nakłada się na kolejną blokadę.
Blokada 1 | Zamek 2 | Blokada konwersji |
---|---|---|
S |
RangeI-N |
RangeI-S |
U |
RangeI-N |
RangeI-U |
X |
RangeI-N |
RangeI-X |
RangeI-N |
RangeS-S |
RangeX-S |
RangeI-N |
RangeS-U |
RangeX-U |
Blokady konwersji można zaobserwować przez krótki czas w różnych złożonych okolicznościach, czasami podczas uruchamiania procesów współbieżnych.
Seryjne skanowanie zakresu, jednoelementowe pobieranie, usuwanie i wstawianie
Blokowanie zakresu kluczy gwarantuje, że następujące operacje można serializować:
- Zapytanie zakresowego skanowania
- Jednotonowe pobieranie nieistniejących wierszy
- Operacja usuwania
- Operacja wstawiania
Przed wystąpieniem blokady zakresu kluczy należy spełnić następujące warunki:
- Poziom izolacji transakcji musi być ustawiony na wartość
SERIALIZABLE
. - Procesor zapytań musi używać indeksu, aby zaimplementować predykat filtru zakresu. Na przykład klauzula
WHERE
w zdaniuSELECT
może ustanowić warunek zakresu z tym predykatem:ColumnX BETWEEN N'AAA' AND N'CZZ'
. Blokadę zakresu kluczy można uzyskać tylko wtedy, gdyColumnX
jest objęta kluczem indeksu.
Przykłady
Poniższa tabela i indeks są używane jako podstawa przykładów blokowania zakresu kluczy, które następują.
Zapytanie zakresowego skanowania
Aby upewnić się, że zapytanie skanowania zakresu jest serializowalne, to samo zapytanie powinno zwrócić te same wyniki za każdym razem, gdy jest wykonywane w ramach tej samej transakcji. Nowe wiersze nie mogą być wstawione w zapytaniu skanowania zakresu przez inne transakcje; w przeciwnym razie stają się to wstawkami phantom. Na przykład poniższe zapytanie używa tabeli i indeksu na poprzedniej ilustracji:
SELECT name
FROM mytable
WHERE name BETWEEN 'A' AND 'C';
Blokady zakresu kluczy są umieszczane w wpisach indeksu odpowiadających zakresowi wierszy, w których nazwa znajduje się między wartościami Adam
i Dale
, co uniemożliwia dodanie lub usunięcie nowych wierszy kwalifikujących się w poprzednim zapytaniu. Mimo że pierwszą nazwą w tym zakresie jest Adam
, blokada zakresu kluczy trybu RangeS-S
dla tego wpisu indeksu gwarantuje, że nie można dodać nowych nazw rozpoczynających się od litery A
przed Adam
, takich jak Abigail
. Podobnie blokada zakresu kluczy RangeS-S
we wpisie indeksu dla Dale
gwarantuje, że po C
nie można dodać nowych nazw rozpoczynających się od litery Carlos
, takich jak Clive
.
Notatka
Liczba blokad RangeS-S
posiadanych to n+1, gdzie n to liczba wierszy spełniających zapytanie.
Singletonowe pobieranie nieistniejących danych
Jeśli zapytanie w ramach transakcji próbuje wybrać wiersz, który nie istnieje, wysłanie zapytania w późniejszym punkcie w ramach tej samej transakcji musi zwrócić ten sam wynik. Żadna inna transakcja nie może wstawić tego nieistniejącego wiersza. Na przykład biorąc pod uwagę to zapytanie:
SELECT name
FROM mytable
WHERE name = 'Bill';
Blokada zakresu kluczy jest umieszczana we wpisie indeksu odpowiadającym zakresowi nazw od Ben
do Bing
, ponieważ nazwa Bill
zostanie wstawiona między tymi dwoma sąsiednimi wpisami indeksu. Na wpisie indeksu RangeS-S
umieszczona jest blokada zakresu kluczy trybu Bing
. Zapobiega to sytuacji, w której żadna inna transakcja nie może wstawić wartości, takich jak Bill
, między wpisami indeksu Ben
a Bing
.
Operacja usuwania bez zoptymalizowanego blokowania
Podczas usuwania wiersza w ramach transakcji zakres, w którym znajduje się wiersz, nie musi być zablokowany przez cały czas trwania operacji usuwania w ramach transakcji. Zablokowanie usuniętej wartości klucza do końca transakcji jest wystarczające, aby zachować możliwość serializacji. Na przykład biorąc pod uwagę tę instrukcję DELETE
:
DELETE mytable
WHERE name = 'Bob';
Blokada wyłączności (X
) jest umieszczana we wpisie indeksu odpowiadającym nazwie Bob
. Inne transakcje mogą wstawiać lub usuwać wartości przed lub po wierszu z wartością Bob
, która jest usuwana. Jednak każda transakcja, która próbuje odczytywać, wstawiać lub usuwać wiersze pasujące do wartości Bob
, zostanie zablokowana do momentu, gdy transakcja usuwająca albo zostanie zatwierdzona, albo cofnięta. (Opcja bazy danych READ_COMMITTED_SNAPSHOT
i poziom izolacji SNAPSHOT
umożliwiają także odczyty z wersji wcześniej zatwierdzonego wiersza stanu).
Usuwanie zakresu można wykonać przy użyciu trzech podstawowych trybów blokowania: wiersza, strony lub blokady tabeli. Strategia blokowania wierszy, strony lub tabeli jest określana przez optymalizator zapytań lub może być określona przez użytkownika za pomocą wskazówek optymalizatora zapytań, takich jak ROWLOCK
, PAGLOCK
lub TABLOCK
. Gdy jest używana PAGLOCK
lub TABLOCK
, aparat bazy danych natychmiast cofa przydział strony indeksu, jeśli wszystkie wiersze zostaną usunięte z tej strony. Natomiast w przypadku użycia ROWLOCK
wszystkie usunięte wiersze są oznaczone jako usunięte; później zostaną one usunięte ze strony indeksu przy użyciu zadania w tle.
Operacja usuwania z zoptymalizowanym blokowaniem
Podczas usuwania wiersza w ramach transakcji blokady wierszy i stron są uzyskiwane i zwalniane przyrostowo, a nie przechowywane przez czas trwania transakcji. Na przykład, biorąc pod uwagę następującą instrukcję DELETE:
DELETE mytable
WHERE name = 'Bob';
Blokada TID jest umieszczana we wszystkich zmodyfikowanych wierszach przez czas trwania transakcji. Blokada jest pobierana na TID odpowiadający wierszom indeksu związanym z wartością Bob
. W przypadku zoptymalizowanego blokowania blokady stron i wierszy są nadal uzyskiwane dla aktualizacji, ale każda blokada strony i wiersza jest zwalniana natychmiast po tym, jak każdy wiersz zostanie zaktualizowany. Blokada TID chroni wiersze przed zaktualizowaniem do momentu zakończenia transakcji. Każda transakcja, która próbuje odczytywać, wstawiać lub usuwać wiersze z wartością Bob
, jest blokowana do momentu, gdy transakcja usuwająca albo zostanie zatwierdzona, albo wycofana. (Opcja bazy danych READ_COMMITTED_SNAPSHOT
i poziom izolacji SNAPSHOT
umożliwiają także odczyty z wersji wcześniej zatwierdzonego wiersza stanu).
W przeciwnym razie mechanika blokowania operacji usuwania jest taka sama jak bez zoptymalizowanego blokowania.
Operacja wstawiania bez zoptymalizowanego blokowania
Podczas wstawiania wiersza w ramach transakcji zakres, do który wchodzi wiersz, nie musi być zablokowany przez czas trwania transakcji wykonującej operację wstawiania. Zablokowanie wstawionej wartości klucza do końca transakcji jest wystarczające, aby zachować możliwość serializacji. Na przykład, biorąc pod uwagę następującą instrukcję INSERT:
INSERT mytable VALUES ('Dan');
Blokada zakresu kluczy trybu RangeI-N
jest umieszczana w wierszu indeksu odpowiadającym nazwie David
do testowania zakresu. Jeśli blokada zostanie udzielona, zostanie wstawiony wiersz z wartością Dan
, a na wstawionym wierszu zostanie umieszczona blokada na wyłączność (X
). Blokada zakresu kluczy trybu RangeI-N
jest niezbędna tylko do testowania zakresu i nie jest przechowywana przez czas trwania transakcji wykonującej operację wstawiania. Inne transakcje mogą wstawiać lub usuwać wartości przed lub po wstawionym wierszu z wartością Dan
. Jednak każda transakcja próbująca odczytać, wstawić lub usunąć wiersz z wartością Dan
zostanie zablokowana, dopóki transakcja wstawiająca nie zostanie zatwierdzona lub cofnięta.
Operacja wstawiania z zoptymalizowanym blokowaniem
Podczas wstawiania wiersza w ramach transakcji zakres, do który wchodzi wiersz, nie musi być zablokowany przez czas trwania transakcji wykonującej operację wstawiania. Blokady wierszy i stron są rzadko uzyskiwane, tylko wtedy, gdy trwa ponowne kompilowanie indeksu online lub gdy istnieją równoczesne transakcje SERIALIZABLE
. Jeśli zastosowano blokady wierszy i stron, są one szybko zwalniane i nie są przetrzymywane przez czas trwania transakcji. Umieszczenie wyłącznej blokady TID na wstawionej wartości klucza do końca transakcji jest wystarczające, aby zachować serializację. Na przykład biorąc pod uwagę tę instrukcję INSERT
:
INSERT mytable VALUES ('Dan');
W przypadku zoptymalizowanego blokowania blokada RangeI-N
jest uzyskiwana tylko wtedy, gdy w wystąpieniu jest używana co najmniej jedna transakcja korzystająca z poziomu izolacji SERIALIZABLE
. Blokada zakresu kluczy trybu RangeI-N
jest umieszczana w wierszu indeksu odpowiadającym nazwie David
do testowania zakresu. Jeśli blokada zostanie udzielona, zostanie wstawiony wiersz z wartością Dan
, a na wstawionym wierszu zostanie umieszczona blokada na wyłączność (X
). Blokada zakresu kluczy trybu RangeI-N
jest niezbędna tylko do testowania zakresu i nie jest przechowywana przez czas trwania transakcji wykonującej operację wstawiania. Inne transakcje mogą wstawiać lub usuwać wartości przed lub po wstawionym wierszu z wartością Dan
. Jednak każda transakcja próbująca odczytać, wstawić lub usunąć wiersz z wartością Dan
zostanie zablokowana, dopóki transakcja wstawiająca nie zostanie zatwierdzona lub cofnięta.
Eskalacja blokad
Eskalacja blokady to proces przekształcania wielu precyzyjnych blokad na mniej gruboziarnistych, zmniejszając obciążenie systemu przy jednoczesnym zwiększaniu prawdopodobieństwa współbieżnego konfliktu.
Eskalacja blokady działa inaczej w zależności od tego, czy zoptymalizowane blokowanie jest włączone.
Eskalacja blokowania bez optymalizacji blokad
Silnik bazy danych, uzyskując blokady niskiego poziomu, umieszcza również blokady intencji na obiektach, które zawierają te obiekty.
- Podczas blokowania wierszy lub zakresów kluczy indeksu silnik bazy danych umieszcza blokadę intencji na stronach zawierających wiersze lub klucze.
- Podczas blokowania stron aparat bazy danych umieszcza blokadę intencji na obiektach wyższego poziomu, które zawierają strony. Oprócz blokady intencji na obiekcie, blokady strony z intencją są wymagane dla następujących obiektów:
- Strony na poziomie liścia nieklastrowanych indeksów
- Strony danych klastrowanych indeksów
- Strony danych stert
Silnik bazy danych może stosować zarówno blokowanie na poziomie wiersza, jak i strony dla tej samej instrukcji, aby zminimalizować liczbę blokad i zmniejszyć prawdopodobieństwo konieczności eskalacji blokad. Na przykład, silnik bazy danych może nałożyć blokady stron na indeks nieklastrowany (jeśli w węźle indeksu wybrano wystarczającą liczbę sąsiadujących kluczy, aby spełnić zapytanie) oraz blokady wierszy na indeks klastrowany lub stertę.
Aby zwiększyć poziom blokad, aparat bazy danych próbuje zmienić blokadę zamiarową w tabeli na odpowiadającą pełną blokadę, na przykład zmieniając blokadę zamiaru na wyłączność (IX
) na blokadę wyłączną (X
) lub blokadę zamiaru współdzielonego (IS
) na blokadę współdzieloną (S
). Jeśli próba eskalacji blokady powiedzie się i zostanie uzyskana pełna blokada tabeli, wówczas wszystkie blokady HoBT, strony (PAGE
) lub na poziomie wiersza (RID
, KEY
), które transakcja posiada na stercie lub indeksie, zostaną zwolnione. Jeśli nie można uzyskać pełnej blokady, w tym czasie nie nastąpi eskalacja blokady, a aparat bazy danych będzie nadal uzyskiwać blokady wiersza, klucza lub strony.
Silnik bazy danych nie eskaluje blokad wierszy ani zakresów kluczy do blokad stron, lecz eskaluje je bezpośrednio do blokad tabeli. Podobnie blokady stron są zawsze eskalowane do blokad tabeli. Blokowanie tabel partycjonowanych może eskalować do poziomu HoBT dla skojarzonej partycji zamiast do blokady tabeli. Blokada na poziomie HoBT niekoniecznie blokuje wyrównane HoBTy dla partycji.
Notatka
Blokady na poziomie HoBT zwykle zwiększają współbieżność, ale wprowadzają możliwość zakleszczenia, gdy transakcje, które blokują różne partycje, każda z nich chce rozszerzyć swoje wyłączne blokady na inne partycje. W rzadkich przypadkach granulacja blokowania TABLE
może działać lepiej.
Jeśli próba eskalacji blokady zakończy się niepowodzeniem z powodu konfliktów blokad przechowywanych przez równoczesne transakcje, silnik bazy danych ponawia próbę eskalacji blokady dla każdych kolejnych 1250 blokad nabytych przez transakcję.
Każde zdarzenie eskalacji działa głównie na poziomie pojedynczej instrukcji Transact-SQL. Gdy zdarzenie się rozpoczyna, silnik bazy danych próbuje eskalować wszystkie blokady należące do bieżącej transakcji w którejkolwiek z tabel, do których odnosi się aktywna instrukcja, pod warunkiem że spełnia wymagania dotyczące progu eskalacji. Jeśli zdarzenie eskalacji rozpoczyna się przed uzyskaniem dostępu do tabeli przez instrukcję, nie zostanie podjęta próba eskalacji blokad w tej tabeli. Jeśli eskalacja blokady powiedzie się, wszelkie blokady uzyskane przez transakcję w poprzedniej instrukcji i nadal przechowywane w momencie rozpoczęcia zdarzenia są eskalowane, jeśli tabela jest przywoływane przez bieżącą instrukcję i jest uwzględniona w zdarzeniu eskalacji.
Załóżmy na przykład, że sesja wykonuje następujące operacje:
- Rozpoczyna transakcję.
- Aktualizacje
TableA
. Spowoduje to wygenerowanie wyłącznych blokad wierszy wTableA
, które są przechowywane do momentu zakończenia transakcji. - Aktualizacje
TableB
. Spowoduje to wygenerowanie wyłącznych blokad wierszy wTableB
, które są przechowywane do momentu zakończenia transakcji. - Wykonuje operację
SELECT
, która łączyTableA
zTableC
. Plan wykonywania zapytania zakłada pobranie wierszy zTableA
przed pobraniem ich zTableC
. - Instrukcja
SELECT
powoduje eskalację blokady podczas pobierania wierszy zTableA
, zanim uzyska dostęp doTableC
.
Jeśli eskalacja blokady powiedzie się, tylko blokady przechowywane przez sesję w TableA
są eskalowane. Obejmuje to zarówno blokady współdzielone z instrukcji SELECT
, jak i blokady wyłączne z poprzedniej instrukcji UPDATE
. Podczas gdy tylko blokady sesji nabyte w TableA
dla instrukcji SELECT
są liczone w celu określenia, czy należy przeprowadzić eskalację blokady, po pomyślnym przeprowadzeniu eskalacji wszystkie blokady przechowywane przez sesję w TableA
są zamieniane na wyłączną blokadę na tabeli, a wszystkie inne blokady o niższym poziomie szczegółowości, w tym blokady intencji, na TableA
zostają zwolnione.
Nie podjęto próby eskalacji blokad na TableB
, ponieważ nie było aktywnego odwołania do TableB
w instrukcji SELECT
. Podobnie nie podjęto próby eskalacji blokad na TableC
, które nie są eskalowane, ponieważ nie były jeszcze dostępne podczas eskalacji.
Eskalacja blokad przy użyciu zoptymalizowanego blokowania
Zoptymalizowane blokowanie pomaga zmniejszyć ilość pamięci blokady, ponieważ przez cały czas trwania transakcji są przechowywane bardzo mało blokad. Gdy silnik bazy danych uzyskuje blokady wierszy i stron, eskalacja blokady może występować w podobny sposób, ale znacznie rzadziej. Zoptymalizowane blokowanie zwykle kończy się powodzeniem w unikaniu eskalacji blokady, obniżając liczbę blokad i wymaganą ilość pamięci blokady.
Po włączeniu zoptymalizowanego blokowania i w domyślnym poziomie izolacji READ COMMITTED
, aparat bazy danych zwalnia blokady wiersza i strony natychmiast po zmodyfikowaniu wiersza. Żadne blokady wierszy i stron nie są przechowywane przez czas trwania transakcji, z wyjątkiem pojedynczej blokady identyfikatora transakcji (TID). Zmniejsza to prawdopodobieństwo eskalacji blokady.
Progi blokady eskalacji
Eskalacja blokady jest wyzwalana, gdy eskalacja blokady nie jest wyłączona w tabeli przy użyciu opcji ALTER TABLE SET LOCK_ESCALATION
i gdy istnieje jeden z następujących warunków:
- Pojedyncza instrukcja typu Transact-SQL uzyskuje co najmniej 5000 blokad w jednej niepartycyjnej tabeli lub indeksie.
- Pojedyncza instrukcja Transact-SQL uzyskuje co najmniej 5000 blokad w jednej partycji tabeli partycjonowanej, a opcja
ALTER TABLE SET LOCK_ESCALATION
jest ustawiona na wartość AUTO. - Liczba blokad w wystąpieniu silnika bazy danych przekracza progi pamięci lub konfiguracji.
Jeśli nie można eskalować blokad z powodu konfliktów blokad, silnik bazy danych okresowo przeprowadza eskalację blokady przy każdych 1,250 nowo pozyskanych blokadach.
Próg eskalacji dla instrukcji Transact-SQL
Gdy silnik bazy danych sprawdza możliwe eskalacje co 1250 nowo uzyskanych blokad, eskalacja blokady nastąpi wtedy i tylko wtedy, gdy instrukcja Transact-SQL uzyskała co najmniej 5000 blokad w jednym odwołaniu do tabeli. Eskalacja blokady jest wyzwalana, gdy instrukcja Transact-SQL uzyskuje co najmniej 5000 blokad w jednym odwołaniu do tabeli. Na przykład eskalacja blokady nie jest uruchamiana, jeśli instrukcja uzyskuje 3000 blokad w jednym indeksie i 3000 blokad w innym indeksie tej samej tabeli. Podobnie eskalacja blokady nie jest wyzwalana, jeśli instrukcja ma sprzężenie samodzielne w tabeli, a każde odwołanie do tabeli uzyskuje tylko 3000 blokad w tabeli.
Eskalacja blokady występuje tylko w przypadku tabel, do których uzyskiwano dostęp w momencie wyzwolenia eskalacji. Załóżmy, że pojedyncza instrukcja SELECT
to sprzężenie, które uzyskuje dostęp do trzech tabel w tej sekwencji: TableA
, TableB
i TableC
. Instrukcja uzyskuje 3000 blokad wierszy w indeksie klastrowanym dla TableA
i co najmniej 5000 blokad wierszy w indeksie klastrowanym dla TableB
, ale jeszcze nie uzyskała dostępu do TableC
. Kiedy silnik bazy danych wykryje, że instrukcja nabyła co najmniej 5000 blokad wierszy w TableB
, próbuje zwiększyć poziom wszystkich blokad utrzymywanych przez bieżącą transakcję w TableB
. Podejmuje również próbę eskalacji wszystkich blokad przechowywanych przez bieżącą transakcję na TableA
, ale ponieważ liczba blokad na TableA
jest mniejsza niż 5000, eskalacja zakończy się niepowodzeniem. Nie podjęto próby eskalacji blokady dla TableC
, ponieważ obiekt ten nie był jeszcze dostępny, gdy nastąpiła eskalacja.
Próg eskalacji dla wystąpienia silnika bazy danych
Za każdym razem, gdy liczba blokad jest większa niż próg pamięci dla eskalacji blokady, aparat bazy danych wyzwala eskalację blokady. Próg pamięci zależy od ustawienia blokad dla opcji konfiguracji.
Jeśli opcja
locks
jest ustawiona na domyślną wartość 0, próg eskalacji blokady zostaje przekroczony, gdy pamięć używana przez obiekty blokad stanowi 24 procent pamięci używanej przez aparat bazy danych, z wyłączeniem pamięci AWE. Struktura danych używana do reprezentowania blokady wynosi około 100 bajtów. Ten próg jest dynamiczny, ponieważ silnik bazy danych dynamicznie uzyskuje i zwalnia pamięć, aby dostosować się do różnych obciążeń roboczych.Jeśli opcja
locks
jest wartością inną niż 0, próg eskalacji blokady wynosi 40 procent (lub mniej, jeśli istnieje ciśnienie pamięci) wartości opcji blokad.
Silnik bazy danych może wybrać dowolną aktywną instrukcję z dowolnej sesji do eskalacji, a dla każdego 1250 nowych blokad wybierze instrukcje do eskalacji, o ile pamięć blokady używana w wystąpieniu pozostaje powyżej progu.
Eskalacja blokad z mieszanymi typami blokad
W przypadku eskalacji blokady blokada wybrana dla sterty lub indeksu jest wystarczająco silna, aby spełnić wymagania najbardziej restrykcyjnej blokady na niższym poziomie.
Załóżmy na przykład, że sesja:
- Rozpoczyna transakcję.
- Aktualizuje tabelę zawierającą indeks klastrowany.
- Wystawia polecenie
SELECT
, które odwołuje się do tej samej tabeli.
Instrukcja UPDATE
uzyskuje następujące blokady:
- Wyłączne (
X
) blokuje zaktualizowane wiersze danych. - Intencjonalna wyłączność (
IX
) blokady są nakładane na stronach klastrowanego indeksu zawierających te wiersze. - Blokada
IX
na indeksie klastrowanym oraz kolejna na tabeli.
Instrukcja SELECT
uzyskuje następujące blokady:
- Udostępnione (
S
) blokuje wszystkie odczyty wierszy danych, chyba że wiersz jest już chroniony przez blokadęX
z instrukcjiUPDATE
. - Intent Shared (
IS
) blokuje wszystkie klastrowane strony indeksu zawierające te wiersze, chyba że strona jest już chroniona blokadąIX
. - Brak blokady w klastrowanym indeksie lub tabeli, ponieważ są one już chronione przez blokady
IX
.
Jeśli instrukcja SELECT
zdobędzie wystarczającą liczbę blokad, aby spowodować eskalację blokady i eskalacja zakończy się powodzeniem, blokada IX
w tabeli zostanie przekonwertowana na blokadę X
, a wszystkie blokady wiersza, strony i indeksu zostaną zwolnione. Zarówno aktualizacje, jak i odczyty są chronione przez blokadę X
w tabeli.
Zmniejszanie blokowania i eskalowania blokady
W większości przypadków mechanizm bazy danych zapewnia najlepszą wydajność, pracując z domyślnymi ustawieniami blokowania i eskalacji blokad.
Skorzystaj z blokowania zoptymalizowanego .
- Zoptymalizowane blokowanie oferuje ulepszony mechanizm blokowania transakcji, który zmniejsza zużycie pamięci blokady i blokowanie współbieżnych transakcji. Eskalacja blokady jest znacznie mniej prawdopodobna, gdy jest włączona zoptymalizowana blokada.
- Unikaj używania podpowiedzi tabel ze zoptymalizowanym blokowaniem. Wskazówki dotyczące tabel mogą zmniejszyć skuteczność zoptymalizowanego blokowania.
- Włącz opcję READ_COMMITTED_SNAPSHOT dla bazy danych, aby uzyskać największą korzyść z zoptymalizowanego blokowania. Jest to wartość domyślna w usłudze Azure SQL Database.
- Zoptymalizowane blokowanie wymaga włączenia przyspieszonego odzyskiwania bazy danych (ADR) w bazie danych.
Jeśli wystąpienie aparatu bazy danych generuje wiele blokad i doświadcza częstych eskalacji blokad, rozważ zmniejszenie liczby blokad przy użyciu następujących strategii:
Używaj poziomu izolacji, który nie generuje wspólnych blokad podczas operacji odczytu.
-
READ COMMITTED
poziom izolacji, gdy opcja bazy danychREAD_COMMITTED_SNAPSHOT
jestON
. - poziom izolacji
SNAPSHOT
- poziom izolacji
READ UNCOMMITTED
Może to być używane tylko w przypadku systemów, które mogą działać z zanieczyszczonymi odczytami.
-
Użyj podpowiedzi dotyczących tabeli
PAGLOCK
lubTABLOCK
, aby aparat bazy danych korzystał z blokad strony, sterty lub indeksu zamiast blokad niskiego poziomu. Użycie tej opcji zwiększa jednak problemy użytkowników blokujących innych użytkowników próbujących uzyskać dostęp do tych samych danych i nie powinny być używane w systemach z więcej niż kilkoma równoczesnymi użytkownikami.Jeśli zoptymalizowane blokowanie nie jest dostępne, w przypadku tabel partycjonowanych użyj opcji
LOCK_ESCALATION
ALTER TABLE, aby eskalować blokady do partycji zamiast tabeli lub wyłączyć eskalację blokady dla tabeli.Podziel duże operacje wsadowe na kilka mniejszych operacji. Na przykład, gdybyś uruchomił następujące zapytanie, aby usunąć kilkaset tysięcy starych wierszy z tabeli audytowej, a potem okazało się, że spowodowało to eskalację blokady, która zablokowała innych użytkowników:
DELETE FROM LogMessages WHERE LogDate < '2024-09-26'
Usuwając te wiersze po kilkaset naraz, można znacznie zmniejszyć liczbę blokad, które gromadzą się na każdą transakcję i zapobiegać eskalacji blokad. Na przykład:
DECLARE @DeletedRows int; WHILE @DeletedRows IS NULL OR @DeletedRows > 0 BEGIN DELETE TOP (500) FROM LogMessages WHERE LogDate < '2024-09-26' SELECT @DeletedRows = @@ROWCOUNT; END;
Zmniejsz ślad blokady zapytania, czyniąc zapytanie możliwie najbardziej wydajnym. Obszerne skanowania lub duża liczba wyszukiwań kluczy może zwiększyć prawdopodobieństwo eskalacji blokady; co więcej, zwiększa to prawdopodobieństwo zakleszczeń i ogólnie negatywnie wpływa na współbieżność i wydajność. Po znalezieniu zapytania, które powoduje eskalację blokady, poszukaj możliwości utworzenia nowych indeksów lub dodania kolumn do istniejącego indeksu w celu usunięcia pełnego indeksu lub skanowania tabel oraz zmaksymalizowania wydajności wyszukiwania indeksów. Rozważ użycie Narzędzia do dostrajania silnika bazy danych do przeprowadzenia automatycznej analizy indeksu w zapytaniu. Aby uzyskać więcej informacji, zobacz Tutorial: Database Engine Tuning Advisor. Jednym z celów tej optymalizacji jest sprawienie, aby operacje wyszukiwania w indeksie zwracały jak najmniej wierszy, aby zminimalizować koszt wyszukiwania kluczy (zmaksymalizować selektywność indeksu dla określonego zapytania). Jeśli aparat bazy danych szacuje, że operator logiczny wyszukiwania klucza może zwrócić wiele wierszy, może zastosować optymalizację pobierania wstępnego do przeprowadzenia wyszukiwania. Jeśli silnik bazy danych używa wstępnego pobierania dla wyszukiwania, musi zwiększyć poziom izolacji transakcji dla części zapytania do
REPEATABLE READ
. Oznacza to, że to, co wygląda jak instrukcjaSELECT
na poziomie izolacjiREAD COMMITTED
, może uzyskać wiele tysięcy blokad kluczy (zarówno w indeksie klastrowanym, jak i jednym indeksie nieklastrowanym), co może spowodować, że takie zapytanie przekroczy progi eskalacji blokady. Jest to szczególnie ważne, jeśli okaże się, że eskalowany poziom blokady dotyczy udostępnionej blokady tabeli, co jednak nie jest często spotykane przy domyślnym poziomie izolacjiREAD COMMITTED
.Jeśli wyszukiwanie klucza za pomocą optymalizacji przefetchowania powoduje eskalację blokady, rozważ dodanie dodatkowych kolumn do indeksu nieklastrowanego, który pojawia się w operatorze logicznym Wyszukiwanie indeksu lub Skanowanie indeksu poniżej operatora logicznego wyszukiwania klucza w planie zapytania. Możliwe jest utworzenie indeksu obejmującego (indeks zawierający wszystkie kolumny w tabeli, które były użyte w zapytaniu), lub przynajmniej indeksu, który obejmuje kolumny używane jako kryteria sprzężenia lub w klauzuli
WHERE
, jeśli uwzględnienie wszystkiego z listy kolumnSELECT
jest niepraktyczne. Sprzężenie zagnieżdżonej pętli może również używać optymalizacji pobierania wstępnego i powoduje to takie samo zachowanie blokujące.Nie można eskalować blokady, jeśli inny SPID obecnie trzyma niezgodną blokadę tabeli. Eskalacja blokady zawsze eskaluje się do blokady tabeli i nigdy nie dochodzi do blokady strony. Ponadto, jeśli próba eskalacji blokady nie powiedzie się, ponieważ inny SPID posiada niezgodną blokadę tabeli, zapytanie, które próbowało eskalować blokadę, nie zostaje zablokowane podczas oczekiwania na blokadę tabeli. Zamiast tego nadal uzyskuje blokady na oryginalnym, bardziej szczegółowym poziomie (wiersz, klucz lub strona), okresowo podejmując dodatkowe próby eskalacji. W związku z tym jedną z metod zapobiegania eskalacji blokady dla określonej tabeli jest uzyskanie i utrzymanie blokady na innym połączeniu, które nie jest zgodne z typem eskalowanej blokady. Blokada intencji na wyłączność (
IX
) na poziomie tabeli nie blokuje żadnych wierszy ani stron, ale nadal nie jest zgodna z eskalowaną blokadą współdzieloną (S
) ani wyłączną (X
) na poziomie tabeli. Załóżmy na przykład, że musisz uruchomić zadanie wsadowe modyfikujące dużą liczbę wierszy w tabelimytable
, co spowodowało zablokowanie wynikające z eskalacji blokady. Jeśli to zadanie zawsze jest wykonywane w mniej niż godzinę, możesz utworzyć zadanie Transact-SQL zawierające następujący kod i zaplanować uruchomienie nowego zadania kilka minut przed godziną rozpoczęcia zadania wsadowego:BEGIN TRAN; SELECT * FROM mytable WITH (UPDLOCK, HOLDLOCK) WHERE 1 = 0; WAITFOR DELAY '1:00:00'; COMMIT TRAN;
To zapytanie uzyskuje i utrzymuje blokadę typu
IX
namytable
przez jedną godzinę, co zapobiega eskalacji blokady na tabeli w tym okresie. Ta partia nie modyfikuje żadnych danych ani nie blokuje innych zapytań (chyba że inne zapytanie wymusza blokadę tabeli za pomocą wskazówkiTABLOCK
lub jeśli administrator wyłączył blokadę strony lub wiersza w indeksie namytable
).Możesz również użyć flag śledzenia 1211 i 1224, aby wyłączyć wszystkie lub niektóre eskalacje blokady. Jednak te flagi śledzenia wyłączają wszystkie globalne eskalacje blokady dla całego wystąpienia silnika bazy danych. Eskalacja blokad pełni użyteczną funkcję w silniku baz danych, maksymalizując wydajność zapytań, które w przeciwnym razie są spowalniane przez narzut związany z pozyskiwaniem i zwalnianiem kilku tysięcy blokad. Eskalacja blokad pomaga również zminimalizować ilość pamięci wymaganą do śledzenia blokad. Pamięć, którą aparat bazy danych może dynamicznie przydzielić dla struktur blokady, jest skończona, więc jeśli wyłączysz eskalację blokady, a pamięć blokady będzie wystarczająco duża, próba przydzielenia dodatkowych blokad dla dowolnego zapytania może zakończyć się niepowodzeniem i wystąpi następujący błąd:
Error: 1204, Severity: 19, State: 1 The SQL Server cannot obtain a LOCK resource at this time. Rerun your statement when there are fewer active users or ask the system administrator to check the SQL Server lock and memory configuration.
Notatka
Gdy wystąpi błąd MSSQLSERVER_1204, zatrzymuje przetwarzanie bieżącej instrukcji i powoduje wycofanie aktywnej transakcji. Wycofanie może blokować użytkowników lub prowadzić do długiego czasu odzyskiwania bazy danych, jeśli ponownie uruchomisz usługę bazy danych.
Notatka
Użycie wskazówki dotyczącej blokady, takiej jak
ROWLOCK
, zmienia tylko początkowe ustawienie blokady. Wskazówki dotyczące blokady nie uniemożliwiają eskalacji blokady.
Począwszy od programu SQL Server 2008 (10.0.x), zachowanie eskalacji blokady zmieniło się wraz z wprowadzeniem opcji tabeli LOCK_ESCALATION
. Aby uzyskać więcej informacji, zobacz opcję LOCK_ESCALATION
ALTER TABLE .
Monitorowanie eskalacji blokady
Monitoruj eskalację blokady przy użyciu zdarzenia rozszerzonego lock_escalation
, jak pokazano w poniższym przykładzie:
-- Session creates a histogram of the number of lock escalations per database
CREATE EVENT SESSION [Track_lock_escalation] ON SERVER
ADD EVENT sqlserver.lock_escalation
(
SET collect_database_name=1,collect_statement=1
ACTION(sqlserver.database_id,sqlserver.database_name,sqlserver.query_hash_signed,sqlserver.query_plan_hash_signed,sqlserver.sql_text,sqlserver.username)
)
ADD TARGET package0.histogram
(
SET source=N'sqlserver.database_id'
)
GO
Dynamiczne blokowanie
Użycie blokad niskiego poziomu, takich jak blokady wierszy, zwiększa współbieżność, zmniejszając prawdopodobieństwo, że dwie transakcje żądają blokad na tym samym fragmencie danych w tym samym czasie. Użycie blokad niskiego poziomu zwiększa również liczbę blokad i zasobów potrzebnych do zarządzania nimi. Korzystanie z wysokich poziomów blokad tabel lub stron zmniejsza obciążenie, ale kosztem obniżenia współbieżności.
Silnik bazy danych używa strategii dynamicznego blokowania w celu określenia najbardziej skutecznych blokad. Aparat bazy danych automatycznie określa, jakie blokady są najbardziej odpowiednie podczas wykonywania zapytania na podstawie cech schematu i zapytania. Na przykład w celu zmniejszenia obciążenia związanego z blokowaniem optymalizator może wybrać blokady stron w indeksie podczas skanowania indeksu.
Blokowanie partycjonowania
W przypadku dużych systemów komputerowych blokady na często odwoływane obiekty mogą stać się wąskim gardłem wydajności, ponieważ uzyskiwanie i zwalnianie blokad powoduje konkurencję o wewnętrzne zasoby blokujące. Partyconowanie blokad usprawnia działanie mechanizmu blokady przez podzielenie jednego zasobu blokady na wiele zasobów blokady. Ta funkcja jest dostępna tylko dla systemów z co najmniej 16 procesorami logicznymi i jest automatycznie włączona i nie można jej wyłączyć. Można partycjonować tylko blokady obiektów. Blokady obiektów, które mają podtyp, nie są partycjonowane. Aby uzyskać więcej informacji, zobacz sys.dm_tran_locks (Transact-SQL).
Omówienie partycjonowania blokady
Zadania blokujące mają dostęp do kilku zasobów współdzielonych, z których dwa są zoptymalizowane poprzez partycjonowanie blokad:
Spinlock
Steruje to dostępem do zasobu blokady, takiego jak wiersz lub tabela.
Bez podziału na partycje, jeden spinlock zarządza wszystkimi żądaniami dotyczącymi blokady dla pojedynczego zasobu blokady. W systemach, które doświadczają dużej ilości aktywności, rywalizacja może wystąpić, gdy żądania blokady oczekują na udostępnienie spinlocka. W takiej sytuacji uzyskanie blokad może stać się wąskim gardłem i negatywnie wpłynąć na wydajność.
Aby zmniejszyć rywalizację o pojedynczy zasób blokady, partycjonowanie blokady dzieli pojedynczy zasób blokady na różne zasoby blokady w celu dystrybucji obciążenia między wiele blokad obrotowych.
pamięci
Służy do przechowywania struktur blokady zasobów.
Po pozyskaniu spinlocka struktury blokady są przechowywane w pamięci, a następnie są do nich dostęp i są one ewentualnie modyfikowane. Dystrybucja dostępu do blokady między wieloma zasobami pomaga wyeliminować konieczność transferu bloków pamięci między procesorami, co przyczynia się do zwiększenia wydajności.
Wdrożenie i monitorowanie partycjonowania blokad
Partycjonowanie blokad jest domyślnie włączone dla systemów z co najmniej 16 procesorami. Po włączeniu partycjonowania blokady, w dzienniku błędów programu SQL Server rejestrowany jest komunikat informacyjny.
Podczas uzyskiwania blokad w zasobie partycjonowanym:
Tylko tryby blokady
NL
,Sch-S
,IS
,IU
iIX
są uzyskiwane na jednej partycji.Udostępnione (
S
), wyłączne (X
) i inne blokady w trybach innych niżNL
,Sch-S
,IS
,IU
iIX
należy uzyskać na wszystkich partycjach, począwszy od identyfikatora partycji 0 i następującego w kolejności identyfikatora partycji. Te blokady w zasobie podzielonym na partycje używają więcej pamięci niż blokady w tym samym trybie w zasobie bez partycji, ponieważ każda partycja jest skutecznie oddzielną blokadą. Wzrost pamięci zależy od liczby partycji. Liczniki Wydajności Blokad w SQL Server wyświetlają informacje o pamięci używanej przez blokady partycjonowane i niepartycjonowane.
Transakcja jest przypisywana do partycji po rozpoczęciu transakcji. W przypadku transakcji wszystkie żądania blokady, które można podzielić na partycje, używają partycji przypisanej do tej transakcji. Dzięki tej metodzie dostęp do blokowania zasobów tego samego obiektu przez różne transakcje jest dystrybuowany między różne partycje.
Kolumna resource_lock_partition
w widoku zarządzania dynamicznego sys.dm_tran_locks
zawiera identyfikator partycji blokady dla zasobu podzielonego na partycje blokady. Aby uzyskać więcej informacji, zobacz sys.dm_tran_locks (Transact-SQL).
Praca z partycjonowaniem zamków
Poniższe przykłady kodu ilustrują partycjonowanie blokad. W przykładach dwie transakcje są wykonywane w dwóch różnych sesjach, aby pokazać sposób działania partycjonowania blokady w systemie komputerowym z 16 procesorami.
Te instrukcje Transact-SQL tworzą obiekty testowe, które są używane w poniższych przykładach.
-- Create a test table.
CREATE TABLE TestTable
(
col1 int
);
GO
-- Create a clustered index on the table.
CREATE CLUSTERED INDEX ci_TestTable ON TestTable (col1);
GO
-- Populate the table.
INSERT INTO TestTable
VALUES (1);
GO
Przykład A
Sesja 1:
Instrukcja SELECT
jest wykonywana w ramach transakcji. Ze względu na blokadę z oznaczeniem HOLDLOCK
ta instrukcja uzyskuje i zachowuje blokadę typu intencja udostępnienia (IS
) na tabeli (na potrzeby tej ilustracji, blokady wierszy i stron są ignorowane). Blokada IS
jest uzyskiwana tylko na partycji przypisanej do transakcji. W tym przykładzie przyjęto założenie, że blokada IS
jest uzyskiwana na podstawie identyfikatora partycji 7.
-- Start a transaction.
BEGIN TRANSACTION;
-- This SELECT statement will acquire an IS lock on the table.
SELECT col1
FROM TestTable
WITH (HOLDLOCK);
Sesja 2:
Transakcja rozpoczyna się, a instrukcja SELECT
uruchomiona w ramach tej transakcji uzyskuje i zachowuje współdzieloną (S
) blokadę na tabeli. Blokada S
jest uzyskiwana na wszystkich partycjach, co powoduje zablokowanie wielu tabel — po jednym dla każdej partycji. Na przykład w systemie z 16 procesorami, 16 blokad S
zostanie przydzielonych do identyfikatorów partycji blokady 0–15. Ponieważ blokada S
jest zgodna z blokadą IS
przechowywaną na partycji o identyfikatorze 7 przez transakcję w sesji 1, nie ma blokowania między transakcjami.
BEGIN TRANSACTION;
SELECT col1
FROM TestTable
WITH (TABLOCK, HOLDLOCK);
Sesja 1:
Następująca instrukcja SELECT
jest wykonywana w ramach transakcji, która jest nadal aktywna w ramach sesji 1. Z powodu wyłącznej wskazówki blokady (X
) transakcja próbuje uzyskać blokadę X
na tabeli. Jednak blokada S
utrzymywana przez transakcję w sesji 2 blokuje blokadę X
o identyfikatorze partycji 0.
SELECT col1
FROM TestTable
WITH (TABLOCKX);
Przykład B
Sesja 1:
Instrukcja SELECT
jest wykonywana w ramach transakcji. Ze względu na blokadę z oznaczeniem HOLDLOCK
ta instrukcja uzyskuje i zachowuje blokadę typu intencja udostępnienia (IS
) na tabeli (na potrzeby tej ilustracji, blokady wierszy i stron są ignorowane). Blokada IS
jest uzyskiwana tylko na partycji przypisanej do transakcji. W tym przykładzie przyjęto założenie, że blokada IS
jest uzyskiwana na podstawie identyfikatora partycji 6.
-- Start a transaction.
BEGIN TRANSACTION;
-- This SELECT statement will acquire an IS lock on the table.
SELECT col1
FROM TestTable
WITH (HOLDLOCK);
Sesja 2:
Instrukcja SELECT
jest wykonywana w ramach transakcji. Ze względu na wskazówkę dotyczącą blokady TABLOCKX
transakcja próbuje uzyskać wyłączną blokadę (X
) w tabeli. Należy pamiętać, że blokada X
musi zostać uzyskana na wszystkich partycjach, począwszy od identyfikatora partycji 0. Blokada X
jest uzyskiwana na wszystkich identyfikatorach partycji 0–5, ale jest blokowana przez blokadę IS
uzyskaną na identyfikatorze partycji 6.
Na identyfikatorach partycji 7–15, których blokada X
jeszcze nie osiągnęła, inne transakcje mogą nadal pozyskiwać blokady.
BEGIN TRANSACTION;
SELECT col1
FROM TestTable
WITH (TABLOCKX, HOLDLOCK);
Poziomy izolacji opartej na wersjach wierszy w aparacie bazy danych
Począwszy od programu SQL Server 2005 (9.x), silnik bazodanowy oferuje implementację istniejącego poziomu izolacji transakcji, READ COMMITTED
, który udostępnia migawkę na poziomie instrukcji przy użyciu wersjonowania wierszy. Silnik bazy danych oferuje również poziom izolacji transakcji, SNAPSHOT
, który udostępnia migawkę na poziomie transakcji także przy użyciu wersjonowania wierszy.
Przechowywanie wersji wierszy to ogólna struktura w programie SQL Server, która wywołuje mechanizm kopiowania na zapis po zmodyfikowaniu lub usunięciu wiersza. Wymaga to, aby podczas uruchamiania transakcji stara wersja wiersza była dostępna dla transakcji, które wymagają wcześniejszego stanu spójnej transakcji. Wersjonowanie wierszy jest używane do implementacji następujących cech:
- Zbuduj tabele
inserted
ideleted
w wyzwalaczach. Wszystkie wiersze zmodyfikowane przez wyzwalacz są wersjonowane. Obejmuje to wiersze zmodyfikowane przez instrukcję, która uruchomiła wyzwalacz, a także wszelkie modyfikacje danych wprowadzone przez wyzwalacz. - Obsługa wielu aktywnych zestawów wyników (MARS). Jeśli sesja MARS wystawia instrukcję modyfikacji danych (na przykład
INSERT
,UPDATE
lubDELETE
) w czasie, gdy istnieje aktywny zestaw wyników, wiersze, których dotyczy instrukcja modyfikacji, są wersjonowane. - Obsługa operacji indeksu określających opcję
ONLINE
. - Wsparcie dla poziomów izolacji transakcji opartych na wersjonowaniu wierszy:
- Nowa implementacja poziomu izolacji
READ COMMITTED
, która używa wersjonowania wierszy w celu zapewnienia spójności odczytu na poziomie instrukcji. - Nowy poziom izolacji,
SNAPSHOT
, aby zapewnić spójność odczytu na poziomie transakcji.
- Nowa implementacja poziomu izolacji
Wersje wierszy są przechowywane w magazynie wersji. Jeśli w bazie danych włączone jest przyspieszone odzyskiwanie bazy danych (ADR), wówczas magazyn wersji zostanie utworzony właśnie w tej bazie danych. W przeciwnym razie magazyn wersji jest tworzony w bazie danych tempdb
.
Baza danych musi mieć wystarczającą ilość przestrzeni na magazyn wersji. Gdy magazyn wersji znajduje się w tempdb
, a baza danych tempdb
jest pełna, operacje aktualizacji przestają generować wersje, ale nadal kończą się powodzeniem, ale operacje odczytu mogą zakończyć się niepowodzeniem, ponieważ określona wymagana wersja wiersza nie istnieje. Ma to wpływ na operacje takie jak wyzwalacze, MARS i indeksowanie online.
Gdy jest używana metoda ADR i magazyn wersji jest pełny, operacje odczytu nadal kończą się powodzeniem, ale operacje zapisu generujące wersje, takie jak UPDATE
i DELETE
kończą się niepowodzeniem.
INSERT
operacje nadal kończą się powodzeniem, jeśli baza danych ma wystarczającą ilość miejsca.
Wersjonowanie wierszy dla transakcji READ COMMITTED
i SNAPSHOT
to proces dwuetapowy:
Ustaw jedną z opcji bazy danych
READ_COMMITTED_SNAPSHOT
,ALLOW_SNAPSHOT_ISOLATION
lub obie na wartośćON
.Ustaw odpowiedni poziom izolacji transakcji w aplikacji:
- Gdy opcja bazy danych
READ_COMMITTED_SNAPSHOT
jestON
, transakcje ustawiające poziom izolacjiREAD COMMITTED
korzystają z wersjonowania wierszy. - Gdy opcja bazy danych
ALLOW_SNAPSHOT_ISOLATION
jestON
, transakcje mogą ustawić poziom izolacjiSNAPSHOT
.
- Gdy opcja bazy danych
Jeśli opcja bazy danych READ_COMMITTED_SNAPSHOT
lub ALLOW_SNAPSHOT_ISOLATION
jest ustawiona na ON
, aparat bazy danych przypisuje numer sekwencji transakcji (XSN) do każdej transakcji, która używa wersjonowania wierszy do manipulacji danymi. Transakcje zaczynają się od momentu wykonania instrukcji BEGIN TRANSACTION
. Jednak numer sekwencji transakcji rozpoczyna się od pierwszej operacji odczytu lub zapisu po instrukcji BEGIN TRANSACTION
. Numer sekwencji transakcji jest zwiększany o jeden przy każdym przypisaniu.
Gdy opcje bazy danych READ_COMMITTED_SNAPSHOT
lub ALLOW_SNAPSHOT_ISOLATION
są ustawione na ON
, kopie logiczne (wersje) są obsługiwane dla wszystkich modyfikacji danych wykonywanych w bazie danych. Za każdym razem, gdy wiersz jest modyfikowany przez określoną transakcję, instancja silnika bazy danych przechowuje wersję wcześniej zatwierdzonego obrazu wiersza w magazynie wersji. Każda wersja jest oznaczona numerem sekwencji transakcji, która dokonała zmiany. Wersje zmodyfikowanych wierszy są łączone przy użyciu listy powiązań. Najnowsza wartość wiersza jest zawsze przechowywana w bieżącej bazie danych i połączona z wersjonowanymi wierszami w magazynie wersji.
Notatka
W przypadku modyfikacji dużych obiektów (LOB) tylko zmieniony fragment jest kopiowany do magazynu wersji.
Wersje wierszy są przechowywane wystarczająco długo, aby spełniać wymagania transakcji działających na poziomach izolacji opartych na wersjonowaniu wierszy. Silnik bazy danych śledzi najwcześniejszy przydatny numer sekwencji transakcji i okresowo usuwa wszystkie wersje wierszy oznaczone numerami sekwencji transakcji, które są niższe niż najwcześniejszy przydatny numer sekwencji.
Gdy obie opcje bazy danych są ustawione na OFF
, wersjonowane są tylko te wiersze, które zostały zmodyfikowane przez wyzwalacze lub sesje MARS, albo odczytane przez operacje indeksu online. Te wersje wierszy są zwalniane, gdy nie są już potrzebne. Proces działający w tle usuwa przestarzałe wersje wierszy.
Notatka
W przypadku transakcji krótko działających wersja zmodyfikowanego wiersza może zostać zapisana w pamięci podręcznej w puli bez zapisywania w magazynie wersji. Jeśli potrzeba przechowywania wersji wiersza jest krótkotrwała, wiersz zostanie usunięty z puli buforów i nie spowoduje narzutu operacji we/wy.
Zachowanie podczas odczytywania danych
W przypadku transakcji działających w obszarze danych odczytu opartych na wersjach wierszy operacje odczytu nie uzyskują udostępnionych (S
) blokad na odczytywanych danych, a w związku z tym nie blokują transakcji modyfikujących dane. Ponadto obciążenie związane z blokowaniem zasobów jest zminimalizowane, ponieważ liczba nabytych blokad jest zmniejszana.
READ COMMITTED
izolacja przy użyciu wersjonowania wierszy i izolacja SNAPSHOT
są przeznaczone do zapewnienia spójności odczytu wersjonowanych danych na poziomie instrukcji lub transakcji.
Wszystkie zapytania, w tym transakcje działające na poziomach izolacji opartych na wersjonowaniu wierszy, uzyskują blokady stabilności schematu (Sch-S
) podczas kompilacji i wykonywania. W związku z tym zapytania są blokowane, gdy współbieżna transakcja trzyma blokadę modyfikacji schematu (Sch-M
) w tabeli. Na przykład operacja języka definicji danych (DDL) uzyskuje blokadę Sch-M
przed zmodyfikowaniem informacji o schemacie tabeli. Transakcje, w tym te działające na poziomie izolacji opartym na wersjonowaniu wierszy, są blokowane, gdy próbują uzyskać blokadę Sch-S
. Z drugiej strony zapytanie zawierające blokadę Sch-S
blokuje współbieżną transakcję, która próbuje uzyskać blokadę Sch-M
.
Po rozpoczęciu transakcji z użyciem poziomu izolacji SNAPSHOT
, instancja silnika bazy danych rejestruje wszystkie aktualnie aktywne transakcje. Gdy transakcja SNAPSHOT
odczytuje wiersz zawierający łańcuch wersji, aparat bazy danych podąża za łańcuchem i pobiera wiersz, w którym znajduje się numer sekwencji transakcji:
Najbliższy, ale niższy niż numer sekwencyjny transakcji migawki odczytującej wiersz.
Nie znajduje się na liście transakcji aktywnych w momencie rozpoczęcia transakcji migawki.
Operacje odczytu wykonywane przez transakcję SNAPSHOT
pobierają ostatnią wersję każdego wiersza zatwierdzonego w momencie rozpoczęcia transakcji SNAPSHOT
. Zapewnia to transakcyjnie spójną migawkę danych, jak istniały na początku transakcji.
READ COMMITTED
transakcje przy użyciu przechowywania wersji wierszy działają w taki sam sposób. Różnica polega na tym, że transakcja READ COMMITTED
nie używa własnego numeru sekwencji transakcji podczas wybierania wersji wierszy. Za każdym razem, gdy instrukcja jest uruchamiana, transakcja READ COMMITTED
odczytuje najnowszy numer sekwencyjny transakcji wystawiony dla tej instancji aparatu bazy danych. Jest to numer sekwencji transakcji używany do wybierania wersji wierszy dla tego zapytania. Dzięki temu transakcje READ COMMITTED
mogą zobaczyć migawkę danych, jak istnieją na początku każdej instrukcji.
Notatka
Mimo że READ COMMITTED
transakcje korzystające z przechowywania wersji wierszy zapewniają transakcyjnie spójny widok danych na poziomie instrukcji, wersje wierszy generowane lub używane przez tego typu transakcje są utrzymywane do momentu zakończenia transakcji.
Zachowanie podczas modyfikowania danych
Zachowanie zapisów danych różni się zarówno z włączonym, jak i bez włączonego optymalizowanego blokowania.
Modyfikowanie danych bez zoptymalizowanego blokowania
W transakcji READ COMMITTED
przy użyciu wersjonowania wierszy wybór wierszy do aktualizacji odbywa się przy użyciu blokującego przeszukiwania, w którym blokada aktualizacji (U
) jest nakładana na wiersz danych podczas odczytywania wartości danych. Jest to to samo co transakcja READ COMMITTED
, która nie używa wersjonowania wierszy. Jeśli wiersz danych nie spełnia kryteriów aktualizacji, blokada aktualizacji zostanie zwolniona w tym wierszu, a następny wiersz zostanie zablokowany i zeskanowany.
Transakcje działające w izolacji SNAPSHOT
przyjmują optymistyczne podejście do modyfikacji danych, zakładając blokady na danych przed wykonaniem modyfikacji w celu wyłącznie wymuszenia ograniczeń. W przeciwnym razie blokady na danych nie są uzyskiwane, dopóki dane nie mają być modyfikowane. Gdy wiersz danych spełnia kryteria aktualizacji, transakcja SNAPSHOT
sprawdza, czy wiersz danych nie został zmodyfikowany przez współbieżną transakcję zatwierdzoną po rozpoczęciu transakcji SNAPSHOT
. Jeśli wiersz danych został zmodyfikowany poza transakcją SNAPSHOT
, wystąpi konflikt aktualizacji i transakcja SNAPSHOT
zostanie zakończona. Konflikt aktualizacji jest obsługiwany przez aparat bazy danych i nie ma możliwości wyłączenia wykrywania konfliktów aktualizacji.
Notatka
Operacje aktualizacji działające w ramach izolacji SNAPSHOT
są wykonywane wewnętrznie w ramach izolacji READ COMMITTED
, gdy transakcja SNAPSHOT
uzyskuje dostęp do dowolnego z następujących elementów:
Tabela z ograniczeniem klucza obcego.
Tabela, do której odwołuje się ograniczenie klucza obcego innej tabeli.
Widok indeksowany odwołujący się do więcej niż jednej tabeli.
Jednak nawet w tych warunkach operacja aktualizacji nadal sprawdza, czy dane nie zostały zmodyfikowane przez inną transakcję. Jeśli dane zostały zmodyfikowane przez inną transakcję, transakcja SNAPSHOT
napotka konflikt aktualizacji i zostanie zakończona. Konflikty aktualizacji muszą być obsługiwane i ponawiane przez aplikację.
Modyfikowanie danych przy użyciu zoptymalizowanego blokowania
Po włączeniu zoptymalizowanego blokowania i włączeniu opcji bazy danych READ_COMMITTED_SNAPSHOT
(RCSI), oraz przy użyciu domyślnego poziomu izolacji READ COMMITTED
, czytelnicy nie uzyskują żadnych blokad, a pisarze uzyskują krótkoterminowe blokady niskiego poziomu zamiast blokad wygasających na końcu transakcji.
Włączenie RCSI jest zalecane w celu uzyskania najwyższej wydajności z zoptymalizowanym blokowaniem. W przypadku używania bardziej rygorystycznych poziomów izolacji, takich jak REPEATABLE READ
lub SERIALIZABLE
, aparat bazy danych przechowuje blokady wierszy i stron do końca transakcji, zarówno dla użytkowników odczytujących, jak i zapisujących, co powoduje zwiększenie blokowania i zajęcia pamięci.
W przypadku włączenia trybu RCSI i używania domyślnego poziomu izolacji READ COMMITTED
, pisarze kwalifikują wiersze w odniesieniu do predykatu na podstawie najnowszej zatwierdzonej wersji wiersza, bez uzyskiwania blokad U
. Zapytanie czeka tylko wtedy, gdy wiersz spełnia kryteria i istnieje inna aktywna transakcja zapisu na tym wierszu lub stronie. Kwalifikowanie na podstawie najnowszej zatwierdzonej wersji i blokowanie tylko kwalifikowanych wierszy zmniejsza blokowanie i zwiększa współbieżność.
W przypadku wykrycia konfliktów aktualizacji przy użyciu RCSI w domyślnym poziomie izolacji READ COMMITTED
, są one obsługiwane i ponawiane automatycznie bez wpływu na obciążenia klientów.
Przy włączonym zoptymalizowanym blokowaniu i korzystaniu z poziomu izolacji SNAPSHOT
zachowanie konfliktów aktualizacji jest takie samo jak przy wyłączonym zoptymalizowanym blokowaniu. Konflikty aktualizacji muszą być obsługiwane i ponawiane przez aplikację.
Notatka
Aby uzyskać więcej informacji na temat zmian w zachowaniu funkcji blokady po kwalifikacji (LAQ) w kontekście zoptymalizowanego blokowania, zobacz Zmiany w zachowaniu zapytania w przypadku zoptymalizowanego blokowania i RCSI.
Zachowanie w podsumowaniu
W poniższej tabeli przedstawiono różnice między izolacją SNAPSHOT
a izolacją READ COMMITTED
przy użyciu wersjonowania wierszy.
Własność |
READ COMMITTED poziom izolacji przy użyciu wersjonowania wierszy |
SNAPSHOT poziom izolacji |
---|---|---|
Opcja bazy danych, która musi być ustawiona na ON , aby włączyć wymaganą obsługę. |
READ_COMMITTED_SNAPSHOT |
ALLOW_SNAPSHOT_ISOLATION |
Jak sesja żąda określonego typu wersjonowania wierszy. | Użyj domyślnego poziomu izolacji READ COMMITTED lub uruchom instrukcję SET TRANSACTION ISOLATION LEVEL , aby określić poziom izolacji READ COMMITTED . Można to zrobić po rozpoczęciu transakcji. |
Konieczne jest wykonanie SET TRANSACTION ISOLATION LEVEL w celu określenia poziomu izolacji SNAPSHOT przed rozpoczęciem transakcji. |
Wersja danych odczytanych według instrukcji. | Wszystkie dane zatwierdzone przed rozpoczęciem każdej instrukcji. | Wszystkie dane zatwierdzone przed rozpoczęciem każdej transakcji. |
Sposób obsługi aktualizacji. |
Bez wykorzystania zoptymalizowanego blokowania: Przywraca wersje wierszy na rzeczywiste dane w celu wyboru wierszy do aktualizacji i stosuje blokady aktualizacji na wybranych wierszach danych. Uzyskuje wyłączne blokady na rzeczywiste wiersze danych, które mają zostać zmodyfikowane. Brak wykrywania konfliktów aktualizacji. Z optymalnym blokowaniem: Na podstawie ostatniej zatwierdzonej wersji wybiera się wiersze, bez konieczności uzyskiwania blokad. Jeśli wiersze kwalifikują się do aktualizacji, zostaną uzyskane ekskluzywne blokady wiersza lub strony. Jeśli zostaną wykryte konflikty aktualizacji, są one obsługiwane i ponawiane automatycznie. |
Używa wersji wierszy do wybierania wierszy do zaktualizowania. Próbuje uzyskać wyłączną blokadę rzeczywistego wiersza danych do zmodyfikowania; jeśli jednak dane zostały zmodyfikowane przez inną transakcję, wystąpi konflikt aktualizacji i transakcja migawki zostanie zakończona. |
Aktualizowanie wykrywania konfliktów |
bez zoptymalizowanego blokowania: Brak. Z zoptymalizowanym blokowaniem: Jeśli zostaną wykryte konflikty aktualizacji, są one obsługiwane i ponawiane automatycznie. |
Zintegrowana obsługa. Nie można wyłączyć. |
Użycie zasobów przechowywania wersji wierszy
Struktura przechowywania wersji wierszy obsługuje następujące funkcje aparatu bazy danych:
- Wyzwalaczy
- Wiele aktywnych zestawów wyników (MARS)
- Indeksowanie online
Platforma przechowywania wersji wierszy obsługuje również następujące poziomy izolacji transakcji opartej na wersjach wierszy:
- Gdy opcja
READ_COMMITTED_SNAPSHOT
bazy danych jest ustawiona naON
, transakcjeREAD_COMMITTED
zapewniają konsystencję odczytu na poziomie instrukcji przy użyciu wersjonowania wierszy. - Gdy opcja
ALLOW_SNAPSHOT_ISOLATION
bazy danych jest ustawiona naON
, transakcjeSNAPSHOT
zapewniają spójność odczytu na poziomie transakcji przy użyciu wersjonowania wierszy.
Poziomy izolacji oparte na wersjonowaniu wierszy zmniejszają liczbę blokad uzyskiwanych przez transakcję przez eliminację użycia udostępnionych blokad w operacjach odczytu. Zwiększa to wydajność systemu przez zmniejszenie zasobów używanych do zarządzania blokadami. Wydajność jest również zwiększana przez zmniejszenie częstości blokowania transakcji przez blokady nałożone przez inne transakcje.
Poziomy izolacji opartej na wersjach wierszy zwiększają zasoby wymagane przez modyfikacje danych. Włączenie tych opcji powoduje, że wszystkie modyfikacje danych bazy danych mają być wersjonowane. Kopia danych przed modyfikacją jest przechowywana w magazynie wersji nawet wtedy, gdy nie ma aktywnych transakcji przy użyciu izolacji opartej na wersjach wierszy. Dane po modyfikacji zawierają wskaźnik do danych w wersji w repozytorium wersji. W przypadku dużych obiektów tylko część zmienionego obiektu jest przechowywana w magazynie wersji.
Miejsce używane w bazie danych tempdb
Dla każdego wystąpienia silnika bazy danych magazyn wersji musi mieć wystarczająco dużo miejsca, aby pomieścić wersje wierszy. Administrator bazy danych musi upewnić się, że tempdb
i inne bazy danych (jeśli włączono ADR) mają wystarczająco dużo miejsca na obsługę magazynu wersji. Istnieją dwa typy magazynów wersji:
- Magazyn wersji kompilacji indeksu online jest używany na potrzeby kompilacji indeksu online.
- Wspólny magazyn wersji jest używany dla wszystkich innych operacji modyfikacji danych.
Wersje wierszy muszą być przechowywane tak długo, jak aktywna transakcja musi mieć do nich dostęp. Okresowo wątek w tle usuwa wersje wierszy, które nie są już potrzebne i zwalnia miejsce w repozytorium wersji. Długotrwała transakcja uniemożliwia zwolnienie miejsca w przechowalni wersji, jeśli spełnia którykolwiek z następujących warunków:
- Używa izolacji opartej na wersjach wierszy.
- Używa wyzwalaczy, MARS lub operacji kompilacji indeksu online.
- Generuje wersje wierszy.
Notatka
Po wywołaniu wyzwalacza wewnątrz transakcji wersje wierszy utworzone przez wyzwalacz są utrzymywane do końca transakcji, mimo że wersje wierszy nie są już potrzebne po zakończeniu wyzwalacza. Dotyczy to także transakcji READ COMMITTED
, które korzystają z wersjonowania wierszy. W przypadku tego typu transakcji wymagany jest spójny transakcyjnie widok bazy danych tylko dla każdej instrukcji w transakcji. Oznacza to, że wersje wierszy utworzone dla oświadczenia w transakcji nie są już potrzebne po zakończeniu oświadczenia. Jednak wersje wierszy utworzone przez każdą instrukcję w transakcji są utrzymywane do momentu zakończenia transakcji.
Jeśli magazyn wersji znajduje się w tempdb
i tempdb
zabraknie miejsca, aparat bazy danych wymusza zmniejszenie magazynu wersji. Podczas procesu zmniejszania najdłużej działające transakcje, które nie wygenerowały jeszcze wersji wierszy, są oznaczone jako ofiary. Komunikat 3967 jest generowany w dzienniku błędów dla każdej transakcji ofiary. Jeśli transakcja jest oznaczona jako ofiara, nie może już odczytywać wersji wierszy w repozytorium wersji. Podczas próby odczytu wersji wierszy zostanie wygenerowany komunikat 3966 i transakcja zostanie wycofana. Jeśli proces zmniejszania zakończy się pomyślnie, miejsce stanie się dostępne w tempdb
. W przeciwnym razie tempdb
zabraknie miejsca i następuje:
Operacje zapisu są nadal wykonywane, ale nie generują wersji. Komunikat informacyjny (3959) pojawia się w dzienniku błędów, ale nie ma to wpływu na transakcję zapisującą dane.
Transakcje, które próbują uzyskać dostęp do wersji wierszy, które nie zostały wygenerowane z powodu pełnego wycofania
tempdb
, kończą się błędem 3958.
Miejsce używane w wierszach danych
Każdy wiersz bazy danych może używać maksymalnie 14 bajtów na końcu wiersza na potrzeby informacji o wersjonowaniu wierszy. Informacje o wersjonowaniu wierszy zawierają numer sekwencji transakcji, która zatwierdziła wersję, oraz wskaźnik do wersji wiersza. Te 14 bajtów są dodawane przy pierwszym zmodyfikowaniu wiersza lub po wstawieniu nowego wiersza w dowolnym z następujących warunków:
- opcje
READ_COMMITTED_SNAPSHOT
lubALLOW_SNAPSHOT_ISOLATION
są ustawione naON
. - Tabela ma wyzwalacz.
- Jest używanych wiele aktywnych zestawów wyników (MARS).
- Operacje kompilacji indeksu online są obecnie uruchomione w tabeli.
Jeśli magazyn wersji znajduje się w tempdb
, te 14 bajtów zostanie usuniętych z wiersza bazy danych przy pierwszym zmodyfikowaniu tego wiersza w każdych z tych warunków:
- Opcje
READ_COMMITTED_SNAPSHOT
iALLOW_SNAPSHOT_ISOLATION
są ustawione naOFF
. - Wyzwalacz nie istnieje już w tabeli.
- Usługa MARS nie jest używana.
- Operacje kompilacji indeksu online nie są obecnie uruchomione.
14 bajtów jest również usuwanych po zmodyfikowaniu wiersza, jeśli ADR nie jest już aktywne, a powyższe warunki są spełnione.
Jeśli używasz dowolnego z funkcji przechowywania wersji wierszy, może być konieczne przydzielenie dodatkowego miejsca na dysku dla bazy danych, aby pomieścić 14 bajtów na wiersz bazy danych. Dodanie informacji o wersji wierszy może spowodować podziały stron indeksu lub alokację nowej strony danych, jeśli na bieżącej stronie nie ma wystarczającej ilości miejsca. Jeśli na przykład średnia długość wiersza wynosi 100 bajtów, dodatkowe 14 bajtów powoduje, że istniejąca tabela będzie rosnąć do 14 procent.
Zmniejszenie współczynnika wypełnienia może pomóc zapobiec fragmentacji lub zmniejszyć fragmentację stron indeksu. Aby wyświetlić informacje o aktualnej gęstości stron dla danych i indeksów tabeli lub widoku, można użyć sys.dm_db_index_physical_stats.
Miejsce używane przez magazyn wersji trwałej (PVS)
Po włączeniu reguły ADR wersje wierszy mogą być przechowywane w magazynie wersji trwałej (PVS) na jeden z następujących sposobów, w zależności od rozmiaru wiersza przed modyfikacją:
- Jeśli rozmiar jest mały, cała stara wersja wiersza jest przechowywana jako część zmodyfikowanego wiersza.
- Jeśli rozmiar jest pośredni, różnica między starą wersją wiersza a zmodyfikowanym wierszem jest przechowywana jako część zmodyfikowanego wiersza. Różnica jest skonstruowana w sposób umożliwiający aparatowi bazy danych odtworzenie całej starej wersji wiersza w razie potrzeby.
- Jeśli rozmiar jest duży, cała stara wersja wiersza jest przechowywana w oddzielnej tabeli wewnętrznej.
Dwie pierwsze metody są nazywane magazynem wersji w wierszu. Ostatnia metoda nazywa się wersja magazynowania poza wierszem z indeksem . Gdy wersje w wierszu nie są już potrzebne, są usuwane, aby zwolnić miejsce na stronach. Podobnie, strony w tabeli wewnętrznej, zawierające niepotrzebne już wersje poza wierszami, są usuwane przez moduł czyszczący wersje.
Przechowywanie wersji wierszy w ramach wiersza optymalizuje pobieranie danych przez transakcje, które muszą odczytywać wersje wierszy. Jeśli wersja jest przechowywana w wierszu, oddzielny odczyt strony PVS poza wierszem nie jest wymagany.
Funkcja DMV sys.dm_db_index_physical_stats dostarcza informacji o liczbie i typie wersji przechowywanych w wierszu i poza wierszem dla partycji indeksu. Łączny rozmiar danych wersji przechowywanych w wierszu jest zgłaszany w kolumnie total_inrow_version_payload_size_in_bytes
.
Rozmiar magazynu wersji poza wierszem jest zgłaszany w kolumnie persistent_version_store_size_kb
w widoku DMV sys.dm_tran_persistent_version_store_stats.
Miejsce używane w dużych obiektach
Aparat bazy danych obsługuje kilka typów danych, które mogą zawierać duże ciągi o długości do 2 gigabajtów (GB), takie jak: nvarchar(max)
, varchar(max)
, varbinary(max)
, ntext
, text
i image
. Duże dane przechowywane przy użyciu tych typów danych są przechowywane w serii fragmentów danych połączonych z wierszem danych. Informacje o wersjonowaniu wierszy są przechowywane w każdym fragmencie używanym do przechowywania tych wielkich ciągów znaków. Fragmenty danych są przechowywane w zestawie stron przeznaczonych dla dużych obiektów w tabeli.
Ponieważ nowe duże wartości są dodawane do bazy danych, są przydzielane przy użyciu maksymalnie 8040 bajtów danych na fragment. Wcześniejsze wersje aparatu bazy danych przechowywały do 8080 bajtów danych ntext
, text
lub image
na fragment.
Istniejące dane ntext
, text
i image
dużych obiektów (LOB) nie są aktualizowane, aby zwolnić miejsce na informacje dotyczące przechowywania wersji wierszy podczas uaktualniania bazy danych do programu SQL Server z wcześniejszej wersji programu SQL Server. Za pierwszym razem, gdy dane LOB są modyfikowane, są dynamicznie uaktualniane, aby umożliwić przechowywanie informacji o wersjonowaniu. Dzieje się tak nawet wtedy, gdy wersje wierszy nie są generowane. Po zaktualizowaniu danych LOB maksymalna liczba bajtów przechowywanych na szczegół zostanie zmniejszona z 8080 bajtów do 8040 bajtów. Proces aktualizacji jest odpowiednikiem usuwania wartości LOB i ponownego wstawiania tej samej wartości. Dane LOB są uaktualniane, nawet jeśli zmodyfikowano tylko 1 bajt. Jest to jednorazowa operacja dla każdej kolumny ntext
, text
lub image
, ale każda operacja może wygenerować dużą ilość alokacji stron i aktywności we/wy w zależności od rozmiaru danych LOB. Może również wygenerować dużą ilość aktywności rejestrowania, jeśli modyfikacja zostanie w pełni zarejestrowana.
WRITETEXT
i UPDATETEXT
operacje są minimalnie rejestrowane, jeśli model odzyskiwania bazy danych nie jest ustawiony na PEŁNY.
Aby spełnić to wymaganie, należy przydzielić wystarczającą ilość miejsca na dysku.
Monitorowanie wersjonowania wierszy i magazynu wersji
Do monitorowania procesów przechowywania wersji wierszy, magazynu wersji i izolacji migawek pod kątem wydajności i problemów, aparat bazy danych udostępnia narzędzia w postaci dynamicznych widoków zarządzania i liczników wydajności.
Dynamiczne widoki zarządzania
Następujące dynamiczne widoki zarządzania zawierają informacje na temat bieżącego stanu systemu tempdb
i magazynu wersji, a także transakcji przy użyciu wersjonowania wierszy.
sys.dm_db_file_space_usage
. Zwraca informacje o użyciu miejsca dla każdego pliku w bazie danych. Aby uzyskać więcej informacji, zobacz sys.dm_db_file_space_usage (Transact-SQL).sys.dm_db_session_space_usage
. Zwraca aktywność alokacji i dealokacji stron dla bazy danych według sesji. Więcej informacji znajdziesz w sys.dm_db_session_space_usage (Transact-SQL).sys.dm_db_task_space_usage
. Zwraca aktywność alokacji i dealokacji stron według zadania dla bazy danych. Aby uzyskać więcej informacji, zobacz sys.dm_db_task_space_usage (Transact-SQL).sys.dm_tran_top_version_generators
. Zwraca tabelę wirtualną dla obiektów generujących większość wersji w magazynie wersji. Grupuje 256 najdłuższych zagregowanych rekordów według database_id i rowset_id. Ta funkcja służy do znajdowania największych odbiorców magazynu wersji. Dotyczy tylko magazynu wersji wtempdb
. Aby uzyskać więcej informacji, zobacz sys.dm_tran_top_version_generators (Transact-SQL).sys.dm_tran_version_store
. Zwraca tabelę wirtualną, która wyświetla wszystkie rekordy wersji we wspólnym magazynie wersji. Dotyczy tylko magazynu wersji wtempdb
. Aby uzyskać więcej informacji, zobacz sys.dm_tran_version_store (Transact-SQL).sys.dm_tran_version_store_space_usage
. Zwraca wirtualną tabelę, która wyświetla łączną ilość miejsca wtempdb
używanego przez zapisy magazynu wersji dla każdej z baz danych. Dotyczy tylko magazynu wersji wtempdb
. Aby uzyskać więcej informacji, zobacz sys.dm_tran_version_store_space_usage (Transact-SQL).Notatka
Wykonywanie zapytań
sys.dm_tran_top_version_generators
isys.dm_tran_version_store
może być kosztowne, ponieważ oba skanują cały magazyn wersji, który może być duży.sys.dm_tran_version_store_space_usage
jest wydajne i niedrogie do uruchomienia, ponieważ nie przechodzi przez poszczególne rekordy magazynu wersji, lecz zamiast tego zwraca zbiorczą przestrzeń magazynu wersji używaną przeztempdb
na każdą bazę danych.sys.dm_tran_active_snapshot_database_transactions
. Zwraca tabelę wirtualną dla wszystkich aktywnych transakcji we wszystkich bazach danych w wystąpieniu SQL Server, które używają wersjonowania wierszy. Transakcje systemowe nie są wyświetlane w tym widoku DMV. Aby uzyskać więcej informacji, zobacz sys.dm_tran_active_snapshot_database_transactions (Transact-SQL).sys.dm_tran_transactions_snapshot
. Zwraca wirtualną tabelę, która wyświetla migawki zrobione przez każdą transakcję. Migawka zawiera numer sekwencji transakcji aktywnych korzystających z przechowywania wersji wierszy. Aby uzyskać więcej informacji, zobacz sys.dm_tran_transactions_snapshot (Transact-SQL).sys.dm_tran_current_transaction
. Zwraca pojedynczy wiersz, który wyświetla informacje o stanie transakcji związane z wersjonowaniem wierszy w bieżącej sesji. Aby uzyskać więcej informacji, zobacz sys.dm_tran_current_transaction (Transact-SQL).sys.dm_tran_current_snapshot
. Zwraca tabelę wirtualną, która wyświetla wszystkie aktywne transakcje w chwili rozpoczęcia bieżącej transakcji izolacji migawki. Jeśli bieżąca transakcja korzysta z izolacji migawkowej, ta funkcja nie zwraca żadnych wierszy.sys.dm_tran_current_snapshot
DMV jest podobny dosys.dm_tran_transactions_snapshot
, z tą różnicą, że zwraca tylko aktywne transakcje dla bieżącej migawki. Aby uzyskać więcej informacji, zobacz sys.dm_tran_current_snapshot (Transact-SQL).sys.dm_tran_persistent_version_store_stats
. Zwraca statystyki trwałego magazynu wersji w każdej bazie danych w przypadku włączenia przyspieszonego odzyskiwania bazy danych. Aby uzyskać więcej informacji, zobacz sys.dm_tran_persistent_version_store_stats (Transact-SQL).
Liczniki wydajności
Poniższe liczniki wydajności monitorują magazyn wersji w tempdb
, a także transakcje przy użyciu wersjonowania wierszy. Liczniki wydajności znajdują się w obiekcie wydajności SQLServer:Transactions
.
wolne miejsce w bazie danych tempdb (KB). Monitoruje ilość wolnego miejsca w kilobajtach (KB) w bazie danych
tempdb
. Do obsługi magazynu wersji obsługującego izolację migawek musi być wystarczająca ilość wolnego miejsca wtempdb
.Poniższa formuła zawiera przybliżone oszacowanie rozmiaru magazynu wersji. W przypadku długotrwałych transakcji warto monitorować generowanie i szybkość oczyszczania w celu oszacowania maksymalnego rozmiaru magazynu wersji.
[rozmiar wspólnego magazynu wersji] = 2 * [dane magazynu wersji generowane na minutę] * [najdłuższy czas działania (w minutach) transakcji]
Najdłuższy czas wykonywania transakcji nie powinien obejmować kompilacji indeksów online. Ponieważ te operacje mogą trwać długo w przypadku bardzo dużych tabel, kompilacje indeksów online używają oddzielnego magazynu wersji. Przybliżony rozmiar magazynu wersji kompilacji indeksu online jest równy ilości danych zmodyfikowanych w tabeli, w tym wszystkich indeksów, podczas gdy kompilacja indeksu online jest aktywna.
rozmiar magazynu wersji (KB). Monitoruje rozmiar w KB wszystkich magazynów wersji w
tempdb
. Te informacje pomagają określić potrzebną ilość miejsca w bazie danychtempdb
dla magazynu wersji. Monitorowanie tego licznika w danym okresie zapewnia przydatne oszacowanie dodatkowego miejsca potrzebnego dotempdb
.szybkość generowania wersji (KB/s). Monitoruje szybkość generowania wersji w KB na sekundę we wszystkich sklepach wersji w
tempdb
.współczynnik oczyszczania wersji (KB/s). Monitoruje tempo oczyszczania wersji w KB na sekundę we wszystkich magazynach wersji w
tempdb
.Notatka
Informacje dotyczące szybkości generowania wersji (KB/s) i szybkości oczyszczania wersji (KB/s) mogą służyć do przewidywania wymagań przestrzeni
tempdb
.liczba jednostek magazynu wersji. Monitoruje liczbę jednostek magazynu wersji.
tworzenie jednostki Version Store. Monitoruje całkowitą liczbę jednostek magazynu wersji utworzonych do przechowywania wersji wierszy od momentu uruchomienia instancji.
skracanie jednostki magazynu wersji. Monitoruje łączną liczbę jednostek magazynu wersji obciętych od momentu uruchomienia wystąpienia. Jednostka magazynu wersji jest obcinana, gdy program SQL Server określa, że żadne wiersze wersji przechowywane w jednostce magazynu wersji nie są potrzebne do uruchamiania aktywnych transakcji.
współczynnik konfliktu aktualizacji. Monitoruje stosunek transakcji migawek aktualizacji, które napotkały konflikty aktualizacji, do łącznej liczby transakcji migawek aktualizacji.
najdłuższy czas wykonywania transakcji. Monitoruje najdłuższy czas działania w sekundach dowolnej transakcji przy użyciu wersjonowania wierszy. Może to służyć do określenia, czy jakakolwiek transakcja działa przez nieoczekiwanie długi czas.
Transakcje. Monitoruje łączną liczbę aktywnych transakcji. Nie obejmuje to transakcji systemowych.
Transakcje Migawkowe. Monitoruje łączną liczbę aktywnych transakcji migawek.
Zaktualizuj transakcje migawki. Monitoruje łączną liczbę aktywnych transakcji migawkowych, które wykonują operacje aktualizacji.
Transakcje wersji nie-snapshot. Monitoruje łączną liczbę aktywnych transakcji niebędących migawkami, które generują rekordy wersji.
Notatka
Suma transakcji aktualizacji migawek i transakcji wersji bezmigawkowych reprezentuje łączną liczbę transakcji uczestniczących w generowaniu wersji. Różnica między Transakcjami Migawkowymi a Transakcjami Aktualizacji Migawek oznacza liczbę transakcji migawkowych tylko do odczytu.
Przykład izolacji na poziomie opartym na wersjonowaniu wierszy
W poniższych przykładach pokazano różnice w zachowaniu między transakcjami z izolacją SNAPSHOT
a transakcjami READ COMMITTED
wykorzystującymi wersjonowanie wierszy.
A. Praca z poziomem izolacji migawki
W tym przykładzie transakcja uruchomiona w izolacji poziomu SNAPSHOT
odczytuje dane, które są następnie modyfikowane przez inną transakcję. Transakcja SNAPSHOT
nie blokuje operacji aktualizacji wykonywanej przez inną transakcję i kontynuuje odczytywanie danych z wersjonowanego wiersza, ignorując modyfikację danych. Jednak gdy transakcja SNAPSHOT
próbuje zmodyfikować dane, które zostały już zmodyfikowane przez inną transakcję, transakcja SNAPSHOT
generuje błąd i zostaje zakończona.
W sesji 1:
USE AdventureWorks2022;
GO
-- Enable snapshot isolation on the database.
ALTER DATABASE AdventureWorks2022 SET ALLOW_SNAPSHOT_ISOLATION ON;
GO
-- Start a snapshot transaction
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
GO
BEGIN TRANSACTION;
-- This SELECT statement will return
-- 48 vacation hours for the employee.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 2:
USE AdventureWorks2022;
GO
-- Start a transaction.
BEGIN TRANSACTION;
-- Subtract a vacation day from employee 4.
-- Update is not blocked by session 1 since
-- under snapshot isolation shared locks are
-- not requested.
UPDATE HumanResources.Employee
SET VacationHours = VacationHours - 8
WHERE BusinessEntityID = 4;
-- Verify that the employee now has 40 vacation hours.
SELECT VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 1:
-- Reissue the SELECT statement - this shows
-- the employee having 48 vacation hours. The
-- snapshot transaction is still reading data from
-- the older, versioned row.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 2:
-- Commit the transaction; this commits the data
-- modification.
COMMIT TRANSACTION;
GO
W sesji 1:
-- Reissue the SELECT statement - this still
-- shows the employee having 48 vacation hours
-- even after the other transaction has committed
-- the data modification.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
-- Because the data has been modified outside of the
-- snapshot transaction, any further data changes to
-- that data by the snapshot transaction will cause
-- the snapshot transaction to fail. This statement
-- will generate a 3960 error and the transaction will
-- terminate.
UPDATE HumanResources.Employee
SET SickLeaveHours = SickLeaveHours - 8
WHERE BusinessEntityID = 4;
-- Undo the changes to the database from session 1.
-- This will not undo the change from session 2.
ROLLBACK TRANSACTION;
GO
B. Praca z izolacją READ COMMITTED przy użyciu wersjonowania wierszy
W tym przykładzie transakcja READ COMMITTED
z użyciem wersjonowania wierszy działa współbieżnie z inną transakcją. Transakcja READ COMMITTED
działa inaczej niż transakcja SNAPSHOT
. Podobnie jak transakcja SNAPSHOT
, transakcja READ COMMITTED
odczytuje wersjonowane wiersze nawet po tym, jak inna transakcja zmodyfikuje dane. Jednak w przeciwieństwie do transakcji SNAPSHOT
transakcja READ COMMITTED
:
- Odczytuje zmodyfikowane dane po zatwierdzeniu zmian danych przez inną transakcję.
- Jest w stanie zaktualizować dane zmodyfikowane przez inną transakcję, których nie mogła zaktualizować transakcja
SNAPSHOT
.
W sesji 1:
USE AdventureWorks2022;
GO
-- Enable READ_COMMITTED_SNAPSHOT on the database.
-- For this statement to succeed, this session
-- must be the only connection to the AdventureWorks2022
-- database.
ALTER DATABASE AdventureWorks2022 SET READ_COMMITTED_SNAPSHOT ON;
GO
-- Start a read-committed transaction
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
GO
BEGIN TRANSACTION;
-- This SELECT statement will return
-- 48 vacation hours for the employee.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 2:
USE AdventureWorks2022;
GO
-- Start a transaction.
BEGIN TRANSACTION;
-- Subtract a vacation day from employee 4.
-- Update is not blocked by session 1 since
-- under read-committed using row versioning shared locks are
-- not requested.
UPDATE HumanResources.Employee
SET VacationHours = VacationHours - 8
WHERE BusinessEntityID = 4;
-- Verify that the employee now has 40 vacation hours.
SELECT VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 1:
-- Reissue the SELECT statement - this still shows
-- the employee having 48 vacation hours. The
-- read-committed transaction is still reading data
-- from the versioned row and the other transaction
-- has not committed the data changes yet.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
W sesji 2:
-- Commit the transaction.
COMMIT TRANSACTION;
GO
W sesji 1:
-- Reissue the SELECT statement which now shows the
-- employee having 40 vacation hours. Being
-- read-committed, this transaction is reading the
-- committed data. This is different from snapshot
-- isolation which reads from the versioned row.
SELECT BusinessEntityID, VacationHours
FROM HumanResources.Employee
WHERE BusinessEntityID = 4;
-- This statement, which caused the snapshot transaction
-- to fail, will succeed with read-committed using row versioning.
UPDATE HumanResources.Employee
SET SickLeaveHours = SickLeaveHours - 8
WHERE BusinessEntityID = 4;
-- Undo the changes to the database from session 1.
-- This will not undo the change from session 2.
ROLLBACK TRANSACTION;
GO
Włącz poziomy izolacji oparte na wersjonowaniu wierszy
Administratorzy bazy danych kontrolują ustawienia na poziomie bazy danych na potrzeby przechowywania wersji wierszy przy użyciu opcji bazy danych READ_COMMITTED_SNAPSHOT
i ALLOW_SNAPSHOT_ISOLATION
w instrukcji ALTER DATABASE
.
Gdy opcja READ_COMMITTED_SNAPSHOT
bazy danych jest ustawiona na ON
, mechanizmy używane do obsługi tej opcji są natychmiast aktywowane. Podczas ustawiania opcji READ_COMMITTED_SNAPSHOT
tylko połączenie wykonujące polecenie ALTER DATABASE
jest dozwolone w bazie danych. Nie może istnieć żadne inne otwarte połączenie w bazie danych do czasu zakończenia ALTER DATABASE
. Baza danych nie musi być w trybie pojedynczego użytkownika.
Następująca instrukcja Transact-SQL umożliwia READ_COMMITTED_SNAPSHOT
:
ALTER DATABASE AdventureWorks2022 SET READ_COMMITTED_SNAPSHOT ON;
Kiedy opcja bazy danych ALLOW_SNAPSHOT_ISOLATION
jest ustawiona na ON
, instancja silnika bazy danych nie zaczyna generować wersji wierszy dla zmodyfikowanych danych, aż do zakończenia wszystkich aktywnych transakcji, które zmodyfikowały dane w bazie danych. Jeśli istnieją aktywne transakcje modyfikacji, aparat bazy danych ustawia stan opcji PENDING_ON
. Po zakończeniu wszystkich transakcji modyfikacji stan opcji zostanie zmieniony na ON
. Użytkownicy nie mogą uruchomić transakcji SNAPSHOT
w bazie danych, dopóki opcja nie zostanie ON
. Podobnie baza danych przechodzi przez stan PENDING_OFF
, gdy administrator bazy danych ustawia opcję ALLOW_SNAPSHOT_ISOLATION
na OFF
.
Następująca instrukcja Transact-SQL umożliwia ALLOW_SNAPSHOT_ISOLATION
:
ALTER DATABASE AdventureWorks2022 SET ALLOW_SNAPSHOT_ISOLATION ON;
W poniższej tabeli wymieniono i opisano stany opcji ALLOW_SNAPSHOT_ISOLATION
. Użycie ALTER DATABASE
z opcją ALLOW_SNAPSHOT_ISOLATION
nie blokuje użytkowników, którzy obecnie uzyskują dostęp do danych bazy danych.
Stan izolacji SNAPSHOT dla bieżącej bazy danych |
Opis |
---|---|
OFF |
Obsługa transakcji izolacyjnych SNAPSHOT nie została uruchomiona. Żadne transakcje izolacyjne SNAPSHOT nie są dozwolone. |
PENDING_ON |
Wsparcie dla transakcji izolacyjnych SNAPSHOT znajduje się w stanie przejściowym (z OFF do ON ). Otwarte transakcje muszą zostać ukończone.Żadne transakcje izolacyjne SNAPSHOT nie są dozwolone. |
ON |
Obsługa izolacji transakcji SNAPSHOT została aktywowana.Transakcje SNAPSHOT są dozwolone. |
PENDING_OFF |
Wsparcie dla transakcji izolacyjnych SNAPSHOT znajduje się w stanie przejściowym (z ON do OFF ).SNAPSHOT transakcje uruchomione po tym czasie nie mogą uzyskać dostępu do tej bazy danych. Istniejące transakcje SNAPSHOT nadal mogą uzyskiwać dostęp do tej bazy danych. Istniejące transakcje zapisu nadal używają wersjonowania w tej bazie danych. Stan PENDING_OFF stanie się OFF dopiero wtedy, gdy wszystkie transakcje SNAPSHOT rozpoczęte w momencie, gdy stan izolacji bazy danych SNAPSHOT był ON , zostaną zakończone. |
Użyj widoku katalogu sys.databases
, aby określić stan obu opcji bazy danych wersjonowania wierszy.
Wszystkie aktualizacje tabel użytkowników i niektórych tabel systemowych przechowywanych w master
i msdb
generują wersje wierszy.
Opcja ALLOW_SNAPSHOT_ISOLATION
jest automatycznie ustawiana na ON
w bazach danych master
i msdb
i nie może być wyłączona.
Użytkownicy nie mogą ustawić opcji READ_COMMITTED_SNAPSHOT
na ON
w master
, tempdb
lub msdb
.
Używanie poziomów izolacji opartych na wersjach wierszy
Struktura przechowywania wersji wierszy jest zawsze włączona i jest używana przez wiele funkcji. Oprócz zapewniania poziomów izolacji bazujących na wersjonowaniu wierszy, służy do obsługi modyfikacji wykonywanych w wyzwalaczach oraz wielu jednoczesnych sesji wyników (MARS) oraz do obsługi odczytów danych podczas operacji indeksowania online.
Poziomy izolacji opartej na wersjach wierszy są włączone na poziomie bazy danych. Każda aplikacja, która uzyskuje dostęp do obiektów z włączonych baz danych, może uruchamiać zapytania przy użyciu następujących poziomów izolacji:
READ COMMITTED
, który używa wersjonowania wierszy, ustawiając w bazie danych opcjęREAD_COMMITTED_SNAPSHOT
naON
, jak pokazano w poniższym przykładzie kodu:ALTER DATABASE AdventureWorks2022 SET READ_COMMITTED_SNAPSHOT ON;
Gdy baza danych obsługuje
READ_COMMITTED_SNAPSHOT
, wszystkie zapytania uruchamiane na poziomie izolacjiREAD COMMITTED
używają wersjonowania wierszy, co oznacza, że operacje odczytu nie blokują operacji aktualizacji.Izolowanie
SNAPSHOT
przez ustawienie opcji bazy danychALLOW_SNAPSHOT_ISOLATION
naON
, jak pokazano w poniższym przykładzie kodu:ALTER DATABASE AdventureWorks2022 SET ALLOW_SNAPSHOT_ISOLATION ON;
W przypadku używania zapytań obejmujących wiele baz danych, transakcja uruchomiona w izolacji
SNAPSHOT
może mieć dostęp do tabel w bazach danych z opcją bazy danychALLOW_SNAPSHOT_ISOLATION
ustawioną naON
. Aby uzyskać dostęp do tabel w bazach danych, które nie mają opcjiALLOW_SNAPSHOT_ISOLATION
bazy danych ustawionej naON
, należy zmienić poziom izolacji. Na przykład poniższy przykład kodu przedstawia instrukcjęSELECT
, która łączy dwie tabele podczas działania w ramach transakcjiSNAPSHOT
. Jedna tabela należy do bazy danych, w której nie włączono izolacjiSNAPSHOT
. Gdy instrukcjaSELECT
działa w izolacjiSNAPSHOT
, nie może zostać wykonana pomyślnie.SET TRANSACTION ISOLATION LEVEL SNAPSHOT; BEGIN TRANSACTION; SELECT t1.col5, t2.col5 FROM Table1 as t1 INNER JOIN SecondDB.dbo.Table2 as t2 ON t1.col1 = t2.col2;
Poniższy przykład kodu przedstawia tę samą instrukcję
SELECT
, która została zmodyfikowana w celu zmiany poziomu izolacji transakcji naREAD COMMITTED
podczas uzyskiwania dostępu do określonej tabeli. Ze względu na tę zmianę instrukcjaSELECT
jest wykonywana pomyślnie.SET TRANSACTION ISOLATION LEVEL SNAPSHOT; BEGIN TRANSACTION; SELECT t1.col5, t2.col5 FROM Table1 as t1 WITH (READCOMMITTED) INNER JOIN SecondDB.dbo.Table2 as t2 ON t1.col1 = t2.col2;
Ograniczenia transakcji przy użyciu poziomów izolacji bazujących na wersjonowaniu wierszy
Podczas pracy z poziomami izolacji opartej na wersjach wierszy należy wziąć pod uwagę następujące ograniczenia:
nie można włączyć
READ_COMMITTED_SNAPSHOT
wtempdb
,msdb
lubmaster
.Globalne tabele tymczasowe są przechowywane w
tempdb
. W przypadku uzyskiwania dostępu do globalnych tabel tymczasowych wewnątrz transakcjiSNAPSHOT
musi wystąpić jedna z następujących czynności:- Ustaw opcję bazy danych
ALLOW_SNAPSHOT_ISOLATION
naON
wtempdb
. - Użyj zasugerowania izolacji, aby zmienić poziom izolacji dla zapytania.
- Ustaw opcję bazy danych
transakcje
SNAPSHOT
kończą się niepowodzeniem, gdy:- Baza danych jest ustawiana jako tylko do odczytu po rozpoczęciu transakcji
SNAPSHOT
, ale przed uzyskaniem dostępu przez transakcjęSNAPSHOT
do bazy danych. - W przypadku uzyskiwania dostępu do obiektów z wielu baz danych, stan bazy danych został zmieniony w taki sposób, że odzyskiwanie bazy danych miało miejsce po rozpoczęciu transakcji
SNAPSHOT
, ale przed tym, jak transakcjaSNAPSHOT
uzyska dostęp do bazy danych. Na przykład: baza danych została ustawiona naOFFLINE
, a następnie naONLINE
baza danych została automatycznie zamknięta i ponownie otwarta ze względu na opcjęAUTO_CLOSE
ustawioną naON
lub baza danych została odłączona i ponownie dołączona.
- Baza danych jest ustawiana jako tylko do odczytu po rozpoczęciu transakcji
Transakcje rozproszone, w tym zapytania w rozproszonych partycjonowanych bazach danych, nie są obsługiwane w izolacji
SNAPSHOT
.Silnik bazodanowy nie przechowuje wielu wersji metadanych systemu. Instrukcje języka definicji danych (DDL) dotyczące tabel i innych obiektów bazy danych (indeksy, widoki, typy danych, procedury składowane i funkcje środowiska uruchomieniowego języka wspólnego) zmieniają metadane. Jeśli instrukcja DDL modyfikuje obiekt, każde współbieżne odwołanie do obiektu w izolacji
SNAPSHOT
powoduje niepowodzenie transakcjiSNAPSHOT
.READ COMMITTED
transakcje nie mają tego ograniczenia, gdy opcjaREAD_COMMITTED_SNAPSHOT
bazy danych jest ustawiona naON
.Na przykład administrator bazy danych wykonuje następującą instrukcję
ALTER INDEX
.USE AdventureWorks2022; GO ALTER INDEX AK_Employee_LoginID ON HumanResources.Employee REBUILD; GO
Każda transakcja migawki, która jest aktywna w momencie wykonania instrukcji
ALTER INDEX
, otrzymuje błąd, jeśli próbuje odwołać się do tabeliHumanResources.Employee
po wykonaniu instrukcjiALTER INDEX
.READ COMMITTED
transakcje korzystające z przechowywania wersji wierszy nie są dotknięte.Notatka
BULK INSERT
operacje mogą spowodować zmiany metadanych tabeli docelowej (na przykład podczas wyłączania kontroli ograniczeń). W takim przypadku jednoczesne transakcje izolacyjneSNAPSHOT
uzyskujące dostęp do tabel ze zbiorczo wstawionymi danymi kończą się niepowodzeniem.
Dostosowywanie blokowania i wersjonowania wierszy
Dostosowywanie limitu czasu blokady
Gdy instancja silnika bazy danych nie może udzielić blokady transakcji, ponieważ inna transakcja posiada już blokadę powodującą konflikt na zasobie, pierwsza transakcja zostaje zablokowana, czekając na zwolnienie istniejącej blokady. Domyślnie nie ma limitu czasu oczekiwania na blokadę, dlatego transakcja może zostać zablokowana na czas nieokreślony.
Notatka
Użyj dynamicznego widoku zarządzania sys.dm_os_waiting_tasks
, aby określić, czy zadanie jest blokowane i co go blokuje. Aby uzyskać więcej informacji i przykładów, zobacz Omówienie i rozwiązywanie problemów z blokowaniem programu SQL Server.
Ustawienie LOCK_TIMEOUT
umożliwia aplikacji ustawienie maksymalnego czasu oczekiwania instrukcji na zablokowanym zasobie. Gdy instrukcja czeka dłużej niż ustawienie LOCK_TIMEOUT
, zablokowana instrukcja zostaje anulowana automatycznie, a zwrócony zostaje komunikat o błędzie 1222 (Lock request time-out period exceeded
). Każda transakcja zawierająca stwierdzenie nie zostaje jednak cofnięta. W związku z tym aplikacja musi mieć program obsługi błędów, który może wychwytować komunikat o błędzie 1222. Jeśli aplikacja nie wychwytuje błędu, aplikacja może kontynuować nieświadomie, że pojedyncza instrukcja w ramach transakcji została anulowana, ale transakcja pozostaje aktywna. Błędy mogą wystąpić, ponieważ instrukcje w dalszej części transakcji mogą zależeć od instrukcji, która nigdy nie została wykonana.
Zaimplementowanie procedury obsługi błędów, która wychwyci komunikat o błędzie 1222 umożliwia aplikacji obsługę sytuacji przekroczenia limitu czasu i podjęcie akcji naprawczej, takich jak: automatyczne ponowne przesłanie instrukcji, która została zablokowana lub cofnięta cała transakcja.
Ważny
Aplikacje korzystające z jawnych transakcji i wymagają zakończenia transakcji po otrzymaniu błędu 1222, muszą jawnie wycofać transakcję w ramach obsługi błędów. Bez tego inne instrukcje mogą zostać przypadkowo wykonane w tej samej sesji, podczas gdy transakcja pozostaje aktywna, co może prowadzić do nieograniczonego wzrostu dziennika transakcji i utraty danych, jeśli transakcja zostanie później wycofana.
Aby określić bieżące ustawienie LOCK_TIMEOUT
, wykonaj funkcję @@LOCK_TIMEOUT
:
SELECT @@LOCK_TIMEOUT;
GO
Dostosowywanie poziomu izolacji transakcji
READ COMMITTED
jest domyślnym poziomem izolacji dla silnika bazy danych. Jeśli aplikacja musi działać na innym poziomie izolacji, może użyć następujących metod, aby ustawić poziom izolacji:
- Uruchom instrukcję SET TRANSACTION ISOLATION LEVEL.
- ADO.NET aplikacje korzystające z przestrzeni nazw
System.Data.SqlClient
mogą określić opcjęIsolationLevel
przy użyciu metodySqlConnection.BeginTransaction
. - Aplikacje korzystające z usługi ADO mogą ustawiać właściwość
Autocommit Isolation Levels
. - Podczas uruchamiania transakcji aplikacje korzystające z OLE DB mogą wywoływać
ITransactionLocal::StartTransaction
, ustawiającisoLevel
na żądany poziom izolacji transakcji. Podczas określania poziomu izolacji w trybie automatycznego zatwierdzania aplikacje korzystające z ole DB mogą ustawić właściwośćDBPROPSET_SESSION
DBPROP_SESS_AUTOCOMMITISOLEVELS
na żądany poziom izolacji transakcji. - Aplikacje korzystające z odBC mogą ustawić atrybut
SQL_COPT_SS_TXN_ISOLATION
przy użyciuSQLSetConnectAttr
.
Po określeniu poziomu izolacji zachowanie blokowania dla wszystkich instrukcji języka manipulowania zapytaniami i danymi (DML) w sesji działa na tym poziomie izolacji. Poziom izolacji pozostaje w mocy do momentu zakończenia sesji lub do momentu ustawienia poziomu izolacji na inny poziom.
W poniższym przykładzie ustawiono poziom izolacji SERIALIZABLE
:
USE AdventureWorks2022;
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
GO
BEGIN TRANSACTION;
SELECT BusinessEntityID
FROM HumanResources.Employee;
COMMIT;
GO
W razie potrzeby poziom izolacji można zmienić dla poszczególnych zapytań lub instrukcji DML, określając wskazówkę na poziomie tabeli. Określanie wskazówki na poziomie tabeli nie ma wpływu na inne instrukcje w sesji.
Aby określić aktualnie ustawiony poziom izolacji transakcji, użyj instrukcji DBCC USEROPTIONS
, jak pokazano w poniższym przykładzie. Zestaw wyników może się różnić od zestawu wyników w Twoim systemie.
USE AdventureWorks2022;
GO
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
GO
DBCC USEROPTIONS;
GO
Oto zestaw wyników.
Set Option Value
---------------------------- -------------------------------------------
textsize 2147483647
language us_english
dateformat mdy
datefirst 7
... ...
Isolation level repeatable read
(14 row(s) affected)
DBCC execution completed. If DBCC printed error messages, contact your system administrator.
Wskazówki dotyczące blokowania
Wskazówki dotyczące blokowania można określić dla poszczególnych odwołań do tabeli w instrukcjach SELECT
, INSERT
, UPDATE
, DELETE
i MERGE
. Sugestie określają typ blokowania lub wersjonowania wierszy, które silnik bazy danych używa dla danych tabeli. Wskazówki dotyczące blokowania na poziomie tabeli mogą być używane, gdy wymagana jest dokładnsza kontrola typów blokad nabytych na obiekcie. Te wskazówki dotyczące blokowania zastępują bieżący poziom izolacji transakcji dla sesji.
Notatka
Wskazówki dotyczące blokowania nie są zalecane do użycia w przypadku włączenia zoptymalizowanego blokowania. Podczas gdy wskazówki dotyczące tabel i zapytań są przestrzegane, zmniejszają one zalety zoptymalizowanego blokowania. Aby uzyskać więcej informacji, zobacz Unikaj wskazówek dotyczących blokowania z użyciem zoptymalizowanej blokady.
Aby uzyskać więcej informacji na temat konkretnych wskazówek dotyczących blokowania i ich działania, zobacz Wskazówki dotyczące tabel (Transact-SQL).
Notatka
Zalecamy, aby wskazówki dotyczące blokowania na poziomie tabeli były używane do zmiany domyślnego zachowania blokowania tylko wtedy, gdy jest to konieczne. Wymuszanie poziomu blokowania może niekorzystnie wpływać na współbieżność.
Silnik bazy danych może potrzebować uzyskać blokady podczas odczytywania metadanych, nawet podczas przetwarzania instrukcji ze wskazówką dotyczącą blokady, która uniemożliwia żądania dotyczące udostępnionych blokad podczas odczytywania danych. Na przykład instrukcja SELECT
uruchomiona na poziomie izolacji READ UNCOMMITTED
lub użycie wskazówki NOLOCK
nie uzyskuje blokad współdzielenia podczas odczytywania danych, ale może czasami żądać blokad podczas odczytywania widoku katalogu systemowego. Oznacza to, że istnieje możliwość zablokowania takiej instrukcji SELECT
, gdy współbieżna transakcja modyfikuje metadane tabeli.
Jak pokazano w poniższym przykładzie, jeśli poziom izolacji transakcji jest ustawiony na SERIALIZABLE
, a wskazówka blokady na poziomie tabeli NOLOCK
jest używana z instrukcją SELECT
, blokady zakresu kluczy, które są zazwyczaj używane do utrzymania transakcji SERIALIZABLE
, nie są uzyskiwane.
USE AdventureWorks2022;
GO
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
GO
BEGIN TRANSACTION;
GO
SELECT JobTitle
FROM HumanResources.Employee WITH (NOLOCK);
GO
-- Get information about the locks held by
-- the transaction.
SELECT resource_type,
resource_subtype,
request_mode
FROM sys.dm_tran_locks
WHERE request_session_id = @@SPID;
-- End the transaction.
ROLLBACK;
GO
Jedyną uzyskaną blokadą, która odwołuje się do HumanResources.Employee
, jest blokada stabilności schematu (Sch-S
). W takim przypadku serializacja nie jest już gwarantowana.
Opcja LOCK_ESCALATION
ALTER TABLE
unika blokad tabeli podczas eskalacji blokady i włącza blokady HoBT (partycja) w tabelach podzielonych na partycje. Ta opcja nie jest wskazówką blokującą i może służyć do zmniejszenia eskalacji blokady. Aby uzyskać więcej informacji, zobacz ALTER TABLE (Transact-SQL).
Dostosuj blokowanie dla indeksu
Aparat bazy danych używa dynamicznej strategii blokowania, która automatycznie wybiera najlepszy stopień szczegółowości blokowania zapytań w większości przypadków. Zalecamy, aby nie zastąpić domyślnych poziomów blokowania, chyba że wzorce dostępu do tabel lub indeksów są dobrze zrozumiałe i spójne, i istnieje problem z rywalizacją o zasoby do rozwiązania. Zastępowanie poziomu blokowania może znacząco utrudniać współbieżny dostęp do tabeli lub indeksu. Na przykład określenie tylko blokad na poziomie dużej tabeli, z których użytkownicy korzystają często, może powodować wąskie gardła, ponieważ użytkownicy muszą czekać, aż blokada na poziomie tabeli zostanie zwolniona, zanim uzyskają dostęp.
Istnieje kilka przypadków, w których wyłączenie blokowania stron lub wierszy może być korzystne, jeśli wzorce dostępu są dobrze zrozumiałe i spójne. Na przykład aplikacja bazy danych używa tabeli wyszukiwania, która jest aktualizowana co tydzień w procesie wsadowym. Czytniki współbieżne uzyskują dostęp do tabeli za pomocą blokady udostępnionej (S
), a cotygodniowe aktualizacje wsadowe uzyskują dostęp do tabeli z blokadą wyłączną (X
). Wyłączenie blokady stron i wierszy w tabeli zmniejsza obciążenie związane z blokowaniem przez cały tydzień, umożliwiając czytelnikom równoczesny dostęp do tabeli za pośrednictwem udostępnionych blokad tabeli. Po uruchomieniu zadania wsadowego można wydajnie ukończyć aktualizację, ponieważ uzyskuje ona wyłączną blokadę tabeli.
Wyłączenie blokady stron i wierszy może być akceptowalne lub nie, ponieważ cotygodniowa aktualizacja wsadowa blokuje równoczesnym czytelnikom dostęp do tabeli podczas uruchamiania aktualizacji. Jeśli zadanie wsadowe zmienia tylko kilka wierszy lub stron, można zmienić poziom blokowania, aby zezwolić na blokowanie na poziomie wiersza lub strony, co umożliwi odczytywanie innych sesji z tabeli bez blokowania. Jeśli zadanie wsadowe ma dużą liczbę aktualizacji, uzyskanie wyłącznej blokady w tabeli może być najlepszym sposobem zapewnienia wydajnego uruchomienia zadania wsadowego.
W niektórych obciążeniach może wystąpić typ zakleszczenia, gdy dwie współbieżne operacje uzyskują blokady wierszy w tej samej tabeli, a następnie blokują się nawzajem, ponieważ obie muszą zablokować stronę. Zabranianie blokad wierszy wymusza oczekiwanie jednej z operacji, unikając zakleszczenia. Aby uzyskać więcej informacji na temat zakleszczeń, zapoznaj się z przewodnikiem Zakleszczenia.
Stopień szczegółowości blokowania użytego w indeksie można ustawić przy użyciu instrukcji CREATE INDEX
i ALTER INDEX
. Ponadto instrukcje CREATE TABLE
i ALTER TABLE
mogą służyć do ustawiania stopnia szczegółowości blokowania PRIMARY KEY
i ograniczeń UNIQUE
. W celu zapewnienia zgodności z poprzednimi wersjami procedura składowana systemu sp_indexoption
może również ustawić stopień szczegółowości. Aby wyświetlić bieżącą opcję blokowania dla danego indeksu, użyj funkcji INDEXPROPERTY
. Blokady na poziomie strony, blokady na poziomie wiersza lub blokady na poziomie strony i na poziomie wiersza mogą być niedozwolone dla danego indeksu.
Niedozwolone blokady | Indeks uzyskiwany przez |
---|---|
Poziom strony | Blokady na poziomie wiersza i na poziomie tabeli |
Poziom wiersza | Blokady na poziomie strony i na poziomie tabeli |
Poziom strony i poziom wiersza | Blokady na poziomie tabeli |
Zaawansowane informacje o transakcji
Transakcje zagnieżdżone
Jawne transakcje można zagnieżdżać. Ma to na celu przede wszystkim obsługę transakcji w procedurach składowanych, które mogą być wywoływane z procesu już w transakcji lub z procesów, które nie mają aktywnej transakcji.
Na poniższym przykładzie pokazano, jak używać zagnieżdżonych transakcji. Jeśli TransProc
jest wywoływana, gdy transakcja jest aktywna, wynik zagnieżdżonej transakcji w TransProc
jest kontrolowany przez transakcję zewnętrzną, a jej instrukcje INSERT
są zarówno zatwierdzane, jak i wycofywane na podstawie zatwierdzenia lub wycofywania zewnętrznej transakcji. Jeśli TransProc
jest wykonywany przez proces, który nie ma zaległej transakcji, COMMIT TRANSACTION
na końcu procedury zatwierdza instrukcje INSERT
.
SET QUOTED_IDENTIFIER OFF;
GO
SET NOCOUNT OFF;
GO
CREATE TABLE TestTrans
(
ColA INT PRIMARY KEY,
ColB CHAR(3) NOT NULL
);
GO
CREATE PROCEDURE TransProc
@PriKey INT,
@CharCol CHAR(3)
AS
BEGIN TRANSACTION InProc;
INSERT INTO TestTrans VALUES (@PriKey, @CharCol);
INSERT INTO TestTrans VALUES (@PriKey + 1, @CharCol);
COMMIT TRANSACTION InProc;
GO
/* Start a transaction and execute TransProc. */
BEGIN TRANSACTION OutOfProc;
GO
EXEC TransProc 1, 'aaa';
GO
/* Roll back the outer transaction, this will
roll back TransProc's nested transaction. */
ROLLBACK TRANSACTION OutOfProc;
GO
EXECUTE TransProc 3,'bbb';
GO
/*
The following SELECT statement shows only rows 3 and 4 are
still in the table. This indicates that the commit
of the inner transaction from the first EXECUTE statement of
TransProc was overridden by the subsequent roll back of the
outer transaction.
*/
SELECT *
FROM TestTrans;
GO
Zatwierdzanie transakcji wewnętrznych jest ignorowane przez silnik bazy danych, gdy transakcja zewnętrzna jest aktywna. Transakcja jest zatwierdzana lub wycofywana na podstawie zatwierdzenia lub wycofania na końcu najbardziej zewnętrznej transakcji. Jeśli transakcja zewnętrzna zostanie zatwierdzona, to transakcje zagnieżdżone również zostaną zatwierdzone. Jeśli transakcja zewnętrzna zostanie wycofana, wszystkie transakcje wewnętrzne również zostaną wycofane, niezależnie od tego, czy transakcje wewnętrzne zostały zatwierdzone indywidualnie.
Każde wywołanie COMMIT TRANSACTION
lub COMMIT WORK
odnosi się do ostatniego uruchomionego BEGIN TRANSACTION
. Jeśli instrukcje BEGIN TRANSACTION
są zagnieżdżone, instrukcja COMMIT
ma zastosowanie tylko do ostatniej transakcji zagnieżdżonej, która jest najbardziej wewnętrzną transakcją. Nawet jeśli instrukcja COMMIT TRANSACTION transaction_name
w transakcji zagnieżdżonej odwołuje się do nazwy transakcji zewnętrznej, zatwierdzenie dotyczy tylko najbardziej wewnętrznej transakcji.
Parametr transaction_name
instrukcji ROLLBACK TRANSACTION
nie może odwoływać się do transakcji wewnętrznej w zestawie nazwanych transakcji zagnieżdżonych.
transaction_name
może odwoływać się tylko do nazwy najbardziej zewnętrznej transakcji. Jeśli instrukcja ROLLBACK TRANSACTION transaction_name
używająca nazwy transakcji zewnętrznej jest wykonywana na dowolnym poziomie zestawu zagnieżdżonych transakcji, wszystkie zagnieżdżone transakcje zostaną wycofane. Jeśli instrukcja ROLLBACK WORK
lub ROLLBACK TRANSACTION
bez parametru transaction_name
jest wykonywana na dowolnym poziomie zestawu zagnieżdżonych transakcji, cofa wszystkie zagnieżdżone transakcje, w tym najbardziej zewnętrzną transakcję.
Funkcja @@TRANCOUNT
rejestruje bieżący poziom zagnieżdżania transakcji. Każda instrukcja BEGIN TRANSACTION
zwiększa @@TRANCOUNT
o jeden. Każda instrukcja COMMIT TRANSACTION
lub COMMIT WORK
dekrementuje @@TRANCOUNT
o jeden. Instrukcja ROLLBACK WORK
lub ROLLBACK TRANSACTION
, która nie ma nazwy transakcji, powoduje wycofanie wszystkich zagnieżdżonych transakcji i dekrementuje @@TRANCOUNT
do 0.
ROLLBACK TRANSACTION
która używa nazwy najbardziej zewnętrznej transakcji w zestawie zagnieżdżonych transakcji cofa wszystkie zagnieżdżone transakcje i zmniejsza @@TRANCOUNT
do 0. Aby określić, czy jesteś już w transakcji, użyj SELECT @@TRANCOUNT
, aby sprawdzić, czy jest to 1 lub więcej. Jeśli @@TRANCOUNT
ma wartość 0, nie jesteś w transakcji.
Korzystanie z sesji powiązanych
Powiązane sesje ułatwiają koordynację działań między wieloma sesjami na tym samym serwerze. Sesje powiązane umożliwiają dwóm lub więcej sesjom dzielenie tej samej transakcji i blokad, i mogą działać na tych samych danych bez konfliktów związanych z blokadą. Powiązane sesje można tworzyć na podstawie wielu sesji w tej samej aplikacji lub z wielu aplikacji z oddzielnymi sesjami.
Aby wziąć udział w sesji powiązanej, sesja wykonuje wywołanie sp_getbindtoken lub srv_getbindtoken (za pośrednictwem usług Open Data Services), aby otrzymać token powiązania. Token powiązania to ciąg znaków, który jednoznacznie identyfikuje każdą powiązaną transakcję. Token powiązania jest następnie wysyłany do innych sesji, które mają być powiązane z bieżącą sesją. Inne sesje wiążą się z transakcją przez wywołanie sp_bindsession
, przy użyciu tokenu powiązania otrzymanego z pierwszej sesji.
Notatka
Aby sp_getbindtoken
lub srv_getbindtoken
zakończyło się sukcesem, sesja musi mieć aktywną transakcję użytkownika.
Tokeny powiązania muszą być przesyłane z kodu aplikacji, który tworzy pierwszą sesję, do kodu aplikacji, który następnie wiąże swoje sesje z tą pierwszą sesją. Nie ma instrukcji Transact-SQL ani funkcji interfejsu API, za pomocą których aplikacja może uzyskać token powiązania dla transakcji rozpoczętej przez inny proces. Niektóre metody, których można użyć do przesyłania tokenu powiązania, obejmują następujące elementy:
Jeśli wszystkie sesje są inicjowane z tej samej aplikacji, tokeny powiązania mogą być przechowywane w pamięci globalnej lub przekazywane do funkcji jako parametr.
Jeśli sesje są wykonywane z oddzielnych procesów aplikacji, tokeny powiązania mogą być przesyłane przy użyciu komunikacji międzyprocesowej (IPC), takiej jak zdalne wywołanie procedury (RPC) lub dynamiczna wymiana danych (DDE).
Tokeny powiązania mogą być przechowywane w tabeli w wystąpieniu aparatu bazy danych, które mogą być odczytywane przez procesy chcące się powiązać z pierwszą sesją.
Tylko jedna sesja w zestawie powiązanych sesji może być aktywna w dowolnym momencie. Jeśli jedna sesja wykonuje instrukcję na wystąpieniu lub ma oczekujące wyniki z wystąpienia, żadna inna sesja powiązana z tym samym tokenem nie może uzyskać dostępu do wystąpienia, dopóki bieżąca sesja nie zakończy przetwarzania lub anuluje bieżącą instrukcję. Jeśli wystąpienie jest zajęte przetwarzaniem instrukcji z innej powiązanej sesji, wystąpi błąd wskazujący, że przestrzeń transakcji jest używana, a sesja powinna ponowić próbę później.
Po powiązaniu sesji każda sesja zachowuje ustawienie poziomu izolacji. Zmiana ustawienia poziomu izolacji jednej sesji przy użyciu SET TRANSACTION ISOLATION LEVEL
nie ma wpływu na ustawienie żadnej innej sesji powiązanej z tym samym tokenem.
Typy powiązanych sesji
Dwa typy powiązanych sesji są lokalne i rozproszone.
Lokalna sesja powiązana Zezwala lokalnym powiązanym sesjom na udostępnianie przestrzeni transakcji pojedynczej transakcji w jednym wystąpieniu silnika bazy danych.
sesji powiązanej rozproszonej Umożliwia powiązanym sesjom współużytkowania tej samej transakcji w co najmniej dwóch wystąpieniach, dopóki cała transakcja nie zostanie zatwierdzona lub wycofana przy użyciu koordynatora transakcji rozproszonych firmy Microsoft (MS DTC).
Sesje powiązane rozproszone nie są identyfikowane przez token powiązania w postaci ciągu znaków; są one identyfikowane przez rozproszone numery identyfikacyjne transakcji. Jeśli sesja powiązana jest zaangażowana w transakcję lokalną i wykonuje RPC na serwerze zdalnym z SET REMOTE_PROC_TRANSACTIONS ON
, lokalna powiązana transakcja jest automatycznie promowana do rozproszonej powiązanej transakcji przez usługę MS DTC, a sesja MS DTC zostanie uruchomiona.
Kiedy należy używać powiązanych sesji
We wcześniejszych wersjach programu SQL Server sesje powiązane były używane głównie w tworzeniu rozszerzonych procedur składowanych, które muszą wykonywać Transact-SQL instrukcje w imieniu procesu, który je wywołuje. Przekazanie przez proces wywołujący tokenu powiązania jako jednego z parametrów rozszerzonej procedury składowanej umożliwia tej procedurze dołączenie do przestrzeni transakcji procesu wywołującego, co w ten sposób integruje rozszerzoną procedurę składowaną z procesem wywołującym.
W silniku bazy danych procedury składowane korzystające z CLR są bardziej bezpieczne, skalowalne i stabilne niż procedury składowane rozszerzone. Procedury składowane CLR używają obiektu SqlContext
do połączenia się z kontekstem sesji wywołującej, a nie sp_bindsession
.
Związane sesje mogą służyć do tworzenia aplikacji trójwarstwowych, w których logika biznesowa jest włączona do osobnych programów, które współpracują w ramach jednej transakcji biznesowej. Te programy muszą być kodowane, aby dokładnie koordynować dostęp do bazy danych. Ponieważ obie sesje współdzielą te same blokady, oba programy nie mogą jednocześnie modyfikować tych samych danych. W dowolnym momencie tylko jedna sesja może wykonywać pracę w ramach transakcji; nie może istnieć wykonywanie równoległe. Transakcję można przełączać tylko między sesjami w dobrze zdefiniowanych punktach wydajności, takich jak po zakończeniu wszystkich instrukcji DML i pobraniu ich wyników.
Efektywne kodowanie transakcji
Ważne jest, aby transakcje były jak najkrótsze. Po rozpoczęciu transakcji, system zarządzania bazami danych (DBMS) musi przechowywać wiele zasobów do końca transakcji, aby chronić właściwości transakcji, takie jak niepodzielność, spójność, izolacja i trwałość (ACID). Jeśli dane są modyfikowane, zmodyfikowane wiersze muszą być chronione za pomocą blokad wyłącznych, które uniemożliwiają innym transakcjom odczytywanie wierszy, a blokady wyłączne muszą być przechowywane do momentu zatwierdzenia lub wycofania transakcji. W zależności od ustawień poziomu izolacji transakcji instrukcje SELECT
mogą uzyskiwać blokady, które muszą być przechowywane do momentu zatwierdzenia lub wycofania transakcji. Szczególnie w systemach z wieloma użytkownikami transakcje muszą być przechowywane tak krótko, jak to możliwe, aby zmniejszyć rywalizację o blokowanie zasobów między połączeniami współbieżnymi. Długotrwałe, nieefektywne transakcje mogą nie być problemem z małą liczbą użytkowników, ale są one bardzo problematyczne w systemie z tysiącami użytkowników. Począwszy od programu SQL Server 2014 (12.x), aparat bazy danych obsługuje opóźnione trwałe transakcje. Opóźnione trwałe transakcje mogą zwiększyć skalowalność i wydajność, ale nie gwarantują trwałości. Aby uzyskać więcej informacji, zobacz Kontrola Trwałości Transakcji.
Wytyczne dotyczące kodu
Oto wskazówki dotyczące kodowania wydajnych transakcji:
Nie wymagaj danych wejściowych od użytkowników podczas transakcji. Pobierz wszystkie wymagane dane wejściowe od użytkowników przed rozpoczęciem transakcji. Jeśli podczas transakcji wymagane są dodatkowe dane wejściowe użytkownika, wycofaj bieżącą transakcję i uruchom ponownie transakcję po podaniu danych wejściowych użytkownika. Nawet jeśli użytkownicy reagują natychmiast, czasy reakcji człowieka są znacznie wolniejsze niż szybkość komputera. Wszystkie zasoby przechowywane przez transakcję są utrzymywane przez bardzo długi czas, co może powodować problemy z blokowaniem. Jeśli użytkownicy nie reagują, transakcja pozostaje aktywna, blokuje krytyczne zasoby, dopóki nie zareagują, co może nie nastąpić przez kilka minut, a nawet godzin.
Nie należy otwierać transakcji podczas przeglądania danych, jeśli w ogóle jest to możliwe. Transakcje nie powinny być uruchamiane do momentu ukończenia wszystkich wstępnych analiz danych.
Utrzymaj transakcję możliwie jak najkrótszą. Po zapoznaniu się z modyfikacjami, które należy wprowadzić, rozpocznij transakcję, wykonaj instrukcje modyfikacji, a następnie natychmiast zatwierdź lub wycofaj. Nie otwieraj transakcji, zanim będzie to wymagane.
Aby zmniejszyć blokowanie, rozważ użycie poziomu izolacji opartej na wersjach wierszy dla zapytań tylko do odczytu.
Inteligentne wykorzystanie niższych poziomów izolacji transakcji. Wiele aplikacji można kodować, aby używać
READ COMMITTED
poziomu izolacji transakcji. Niewiele transakcji wymaga poziomu izolacji transakcjiSERIALIZABLE
.Inteligentne korzystanie z optymistycznych opcji współbieżności. W systemie z niskim prawdopodobieństwem współbieżnych aktualizacji, obciążenie związane z obsługą okazjonalnego błędu, gdy "ktoś inny zmienił dane po ich odczytaniu", może być znacznie niższe niż obciążenie związane z blokowaniem wierszy podczas każdego odczytu.
Uzyskaj dostęp do najmniejszej możliwej ilości danych podczas transakcji. Zmniejsza to liczbę zablokowanych wierszy, co w rezultacie redukuje konflikt między transakcjami.
Unikaj zawsze, gdy jest to możliwe, pesymistycznych wskazówek dotyczących blokowania, takich jak
HOLDLOCK
. Wskazówki, takie jak poziom izolacjiHOLDLOCK
lubSERIALIZABLE
, mogą powodować, że procesy oczekują nawet na udostępnionych blokadach, i zmniejszyć współbieżność.Unikaj używania transakcji niejawnych, jeśli to możliwe. Niejawne transakcje mogą wprowadzać nieprzewidywalne zachowanie ze względu na ich charakter. Zobacz Niejawne transakcje i problemy ze współbieżnością.
Niejawne transakcje i unikanie problemów ze współbieżnością i zasobami
Aby zapobiec problemom ze współbieżnością i zasobami, dokładnie zarządzaj niejawnymi transakcjami. W przypadku korzystania z niejawnych transakcji kolejna instrukcja Transact-SQL po COMMIT
lub ROLLBACK
automatycznie uruchamia nową transakcję. Może to spowodować otwarcie nowej transakcji podczas przeglądania danych przez aplikację, a nawet wtedy, gdy wymaga danych wejściowych od użytkownika. Po zakończeniu ostatniej transakcji wymaganej do ochrony modyfikacji danych wyłącz niejawne transakcje, dopóki transakcja nie zostanie ponownie wymagana do ochrony modyfikacji danych. Ten proces umożliwia aparatowi bazy danych korzystanie z trybu automatycznego zatwierdzania podczas przeglądania danych przez aplikację i pobierania danych wejściowych od użytkownika.
Ponadto po włączeniu poziomu izolacji SNAPSHOT
, chociaż nowa transakcja nie będzie zawierać blokad, długotrwała transakcja uniemożliwi usunięcie starych wersji z magazynu wersji.
Zarządzanie długotrwałych transakcji
Długotrwała transakcja jest aktywną transakcją, która nie została zatwierdzona ani wycofana w odpowiednim czasie. Na przykład, jeśli początek i koniec transakcji są kontrolowane przez użytkownika, typową przyczyną długotrwałej transakcji jest sytuacja, gdy użytkownik rozpoczyna transakcję i następnie opuszcza ją, podczas gdy transakcja czeka na jego odpowiedź.
Długotrwała transakcja może powodować poważne problemy z bazą danych w następujący sposób:
Jeśli instancja serwera zostanie zamknięta po tym, jak aktywna transakcja wykona wiele niezatwierdzonych modyfikacji, faza odzyskiwania podczas następnego ponownego uruchomienia może trwać znacznie dłużej niż czas określony przez opcję konfiguracji serwera
recovery interval
lub opcjęALTER DATABASE ... SET TARGET_RECOVERY_TIME
. Te opcje kontrolują odpowiednio aktywne i pośrednie punkty kontrolne. Aby uzyskać więcej informacji na temat typów punktów kontrolnych, zobacz Database checkpoints (SQL Server).Co ważniejsze jednak, mimo że oczekujące transakcje mogą generować bardzo mało dziennika, opóźniają przycinanie dziennika na czas nieokreślony, powodując wzrost dziennika transakcji i ewentualnie możliwością wypełnienia. Jeśli dziennik transakcji zostanie wypełniony, baza danych nie może wykonać więcej operacji zapisu. Aby uzyskać więcej informacji, zobacz architektura dziennika transakcji programu SQL Server i przewodnik zarządzania, Rozwiązywanie problemów z pełnym dziennikiem transakcji (błąd programu SQL Server 9002)i dziennik transakcji.
Ważny
W usłudze Azure SQL Database transakcje bezczynne (transakcje, które nie zostały zapisane w dzienniku transakcji przez sześć godzin) są automatycznie przerywane w celu zwolnienia zasobów.
Odnajdywanie długotrwałych transakcji
Aby wyszukać długotrwałe transakcje, użyj jednego z następujących elementów:
sys.dm_tran_database_transactions
Ten dynamiczny widok zarządzania zwraca informacje o transakcjach na poziomie bazy danych. W przypadku długotrwałej transakcji kolumny o szczególnym znaczeniu obejmują czas pierwszego rekordu dziennika (
database_transaction_begin_time
), bieżący stan transakcji (database_transaction_state
) oraz numer sekwencji dziennika (LSN) rozpocząć rekord w dzienniku transakcji (database_transaction_begin_lsn
).Aby uzyskać więcej informacji, zobacz sys.dm_tran_database_transactions (Transact-SQL).
DBCC OPENTRAN
Ta instrukcja umożliwia zidentyfikowanie identyfikatora właściciela użytkownika transakcji, dzięki czemu można potencjalnie śledzić źródło transakcji w celu odpowiedniego zakończenia (zatwierdzenie lub wycofanie). Aby uzyskać więcej informacji, zobacz DBCC OPENTRAN (Transact-SQL).
Kończenie transakcji
Aby zakończyć transakcję w określonej sesji, użyj instrukcji KILL
. Użyj tej instrukcji bardzo ostrożnie, zwłaszcza gdy działają krytyczne procesy. Aby uzyskać więcej informacji, zobacz KILL (Transact-SQL).
Zakleszczenia
Zakleszczenia są złożonym tematem związanym z blokadami, ale różnią się od blokowania.
- Aby uzyskać więcej informacji na temat zakleszczeń, w tym monitorowania, diagnostyki i próbek, zobacz przewodnik Zakleszczenia.
- Aby uzyskać więcej informacji na temat zakleszczeń specyficznych dla usługi Azure SQL Database, zobacz Analizowanie i zapobieganie zakleszczeniom w usłudze Azure SQL Database.
Powiązana zawartość
- Informacje i rozwiązywanie problemów z blokowaniem programu SQL Server
- Omówienie i rozwiązywanie problemów z blokowaniem usługi Azure SQL Database
- Dynamiczne Widoki Zarządzania i Funkcje Związane z Transakcjami (Transact-SQL)
- Koszt wersjonowania wierszy
- sys.dm_tran_locks (Transact-SQL)