Typowym wymaganiem w ETL i różnych scenariuszach raportowania jest ciche ładowanie tabeli tymczasowej programu SQL Server w tle, dzięki czemu użytkownicy wykonujący zapytania o dane nie mają wpływu na zapisy i na odwrót. Sztuczka polega na tym, jak i kiedy wskazujesz użytkownikom nową, odświeżoną wersję danych.
Uproszczony przykład tabeli inscenizacji:analogia rynkowa rolnika
Czym więc jest tabela pomostowa w SQL? Stół pomostowy można łatwiej zrozumieć na przykładzie ze świata rzeczywistego:załóżmy, że masz stół pełen warzyw, które sprzedajesz na lokalnym targu. Gdy twoje warzywa sprzedają się i przyniesiesz nowe zapasy:
- Gdy przyniesiesz ładunek nowych warzyw, usunięcie ze stołu i zastąpienie pozostałego zapasu nowszym produktem zajmie Ci 20 minut.
- Nie chcesz, aby klienci siedzieli tam i czekali 20 minut na zmianę, ponieważ większość z nich dostanie warzywa gdzie indziej.
A co by było, gdybyś miał drugi pusty stół, na którym ładujesz nowe warzywa, a gdy to robisz, klienci nadal mogą kupować starsze warzywa z pierwszego stołu? (Załóżmy, że to nie dlatego, że starsze warzywa zepsuły się lub są mniej pożądane).
Odświeżanie tabel w SQL Server
Istnieje kilka metod ponownego ładowania całych tabel, gdy są aktywnie odpytywane; dwie dekady temu wykorzystałem nieokiełznanie sp_rename
— Grałbym w grę typu shell z pustą kopią w tle tabeli, szczęśliwie przeładowując kopię w tle, a następnie przeprowadzając tylko zmianę nazwy w ramach transakcji.
W SQL Server 2005 zacząłem używać schematów do przechowywania kopii w tle tabel, które po prostu przeniosłem przy użyciu tej samej techniki gry w powłokę, o której pisałem w tych dwóch postach:
- Sztuczne strzały:schemat zamiany w roo
- Schemat Switch-a-Roo, część 2
Jedyną zaletą przesyłania obiektów między schematami nad zmienianiem ich nazwy jest brak komunikatów ostrzegawczych o zmianie nazwy obiektu – co samo w sobie nie stanowi problemu, z wyjątkiem komunikatów ostrzegawczych, które znacznie szybciej wypełniają dzienniki historii agentów.
Oba podejścia nadal wymagają blokady modyfikacji schematu (Sch-M), więc muszą czekać, aż istniejące transakcje zwolnią własne blokady. Po uzyskaniu blokady Sch-M blokują wszelkie kolejne zapytania wymagające blokad stabilności schematu (Sch-S)… co jest prawie każdym zapytaniem. Może szybko stać się koszmarem łańcucha blokującego, ponieważ wszelkie nowe zapytania wymagające Sch-S muszą stać w kolejce za Sch-M. (I nie, nie możesz tego obejść za pomocą RCSI lub NOLOCK
wszędzie, ponieważ nawet te zapytania nadal wymagają Sch-S. Nie możesz nabyć Sch-S z Sch-M na miejscu, ponieważ są one niekompatybilne — mówi o tym tutaj Michael J. Swart.)
Kendra Little naprawdę otworzyła mi oczy na niebezpieczeństwa związane z transferem schematów w swoim poście „Dane inscenizacji:blokowanie niebezpieczeństwa za pomocą ALTER SCHEMA TRANSFER”. Tam pokazuje, dlaczego transfer schematu może być gorszy niż zmiana nazwy. Później opisała trzeci i znacznie mniej wpływowy sposób zamiany tabel, z którego teraz korzystam wyłącznie:przełączanie partycji. Ta metoda pozwala przełącznikowi czekać z niższym priorytetem, co nie jest nawet opcją w przypadku technik zmiany nazwy lub transferu schematu. Joe Sack szczegółowo omówił to ulepszenie dodane w SQL Server 2014:„Eksploracja opcji oczekiwania na blokadę o niskim priorytecie w SQL Server 2014 CTP1”.
Przykład przełączania partycji serwera SQL
Przyjrzyjmy się prostemu przykładowi, podążając za dokładnym przesłaniem Kendry. Najpierw utworzymy dwie nowe bazy danych:
UTWÓRZ BAZĘ DANYCH NewWay;UTWÓRZ BAZĘ DANYCH OldWay;GO
W nowej bazie danych utworzymy tabelę do przechowywania naszych zapasów warzyw oraz dwie kopie tabeli do naszej gry w powłoki:
UŻYJ NewWay;GO CREATE TABLE dbo.Vegetables_NewWay( VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar(max));GO — musimy utworzyć dwie dodatkowe kopie tabeli. CREATE TABLE dbo.Vegetables_NewWay_prev(Vegetables_NewWay_prev(Vegetables_NewWay_hold(VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar(max));GO CREATE TABEL dbo.Vegetables_NewWay_hold(Vegetables_NewWay_hold( VegetableID int, Name sysname, WhenPicked datevarchar(max)));Tworzymy procedurę, która ładuje kopię pomostową tabeli, a następnie używa transakcji, aby wyłączyć bieżącą kopię.
UTWÓRZ PROCEDURĘ dbo.DoTheVeggieSwap_NewWayASBEGIN USTAWIĆ NOCOUNT ON; OBCIĄĆ TABELĘ dbo.Vegetables_NewWay_prev; INSERT dbo.Vegetables_NewWay_prev SELECT TOP (1000000) s.session_id, o.name, s.last_successful_logon, LEFT(m.definition, 500) FROM sys.dm_exec_sessions AS s CROSS JOIN model.sys.all.sys.OBjects AS o model. all_sql_modules AS m ON o.[object_id] =m.[object_id]; -- trzeba wziąć blokady Sch-M tutaj:ROZPOCZNIJ TRANSAKCJĘ; ALTER TABELA dbo.Vegetables_NewWay PRZEŁĄCZ NA dbo.Vegetables_NewWay_hold WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION =1 MINUTA, ABORT_AFTER_WAIT =BLOCKERS)); ALTER TABLE dbo.Vegetables_NewWay_prev PRZEŁĄCZ NA dbo.Vegetables_NewWay; POTWIERDZENIE TRANSAKCJI; -- a teraz użytkownicy będą wysyłać zapytania o nowe dane w dbo -- mogą przełączyć starą kopię z powrotem i obciąć ją -- bez zakłócania innych zapytań ALTER TABLE dbo.Vegetables_NewWay_hold PRZEŁĄCZ NA dbo.Vegetables_NewWay_prev; OBCIĄĆ TABELĘ dbo.Vegetables_NewWay_prev;ENDGOPiękno
WAIT_AT_LOW_PRIORITY
czy możesz całkowicie kontrolować zachowanie za pomocąABORT_AFTER_WAIT
opcja:
ABORT_AFTER_WAIT ustawienie | Opis/objawy |
---|---|
SAMO | Oznacza to, że przełącznik podda się po n minuty. W przypadku sesji, która próbuje dokonać przełączenia, pojawi się komunikat o błędzie: Przekroczono limit czasu żądania blokady. |
BLOKUJĄCE | To dyktuje, że przełącznik będzie czekać do n minut, a następnie zmusić się do wyjścia na początek linii, zabijając wszystkich blokujących przed nią . Sesje, które próbują wchodzić w interakcję z tabelą, która została uderzona przez operację przełącznika, zobaczą kombinację tych komunikatów o błędach: Twoja sesja została rozłączona z powodu operacji DDL o wysokim priorytecie.Nie można kontynuować wykonywania, ponieważ sesja jest w stanie „zabicia”. W bieżącym poleceniu wystąpił poważny błąd. Ewentualne wyniki należy odrzucić. |
BRAK | To oznacza, że przełącznik z radością poczeka na swoją kolej, niezależnie od MAX_DURATION .
Jest to takie samo zachowanie, jakie można uzyskać w przypadku zmiany nazwy, transferu schematu lub przełączania partycji bez |
BLOCKERS
opcja nie jest najbardziej przyjaznym sposobem radzenia sobie z rzeczami, ponieważ już mówisz, że dzięki tej operacji przemieszczania/przełączania użytkownicy mogą zobaczyć dane, które są trochę nieaktualne. Prawdopodobnie wolałbym używać SELF
i poproś operację ponownie w przypadkach, gdy nie może uzyskać wymaganych blokad w wyznaczonym czasie. Śledziłbym jednak, jak często zawodzi, zwłaszcza kolejne awarie, ponieważ chcesz mieć pewność, że dane nigdy nie staną się zbyt stare.
W porównaniu ze starym sposobem przełączania między schematami
Oto jak radziłbym sobie wcześniej z przełączaniem:
USE OldWay;GO -- utwórz dwa schematy i dwie kopie tabeli CREATE SCHEMA prev AUTHORIZATION dbo;GO CREATE SCHEMA hold AUTHORIZATION dbo;GO CREATE TABLE dbo.Vegetables_OldWay( VegetableID int, Name sysname, WhenPicked datevarn max));GO CREATE TABLE prev.Vegetables_OldWay(Vegetables_OldWay(VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar(max));GO CREATE PROCEDURE dbo.DoTheVeggieSwap_OldWayASBEGIN USTAWIĆ NOCOUNT ON); OBCIĄŻ TABELĘ prev.Vegetables_OldWay; INSERT prev.Vegetables_OldWay SELECT TOP (1000000) s.session_id, o.name, s.last_successful_logon, LEFT(m.definition, 500) FROM sys.dm_exec_sessions AS s CROSS JOIN model.sys.all_objectJOIN AS o INNER. all_sql_modules AS m ON o.[object_id] =m.[object_id]; -- trzeba wziąć blokady Sch-M tutaj:ROZPOCZNIJ TRANSAKCJĘ; ALTER SCHEMA przytrzymaj TRANSFER dbo.Vegetables_OldWay; ALTER SCHEMA dbo TRANSFER prev.Vegetables_OldWay; POTWIERDZENIE TRANSAKCJI; -- a teraz użytkownicy będą wysyłać zapytania o nowe dane w dbo -- mogą przenieść starą kopię z powrotem i obciąć ją bez -- zakłócania innych zapytań:ALTER SCHEMA prev TRANSFER hold.Vegetables_OldWay; OBCIĄŻ TABELĘ prev.Vegetables_OldWay;ENDGO
Przeprowadziłem testy współbieżności, używając dwóch okien SQLQueryStress Erika Ejlskova Jensena:jednego do powtarzania wywołania procedury co minutę, a drugiego do uruchamiania 16 wątków w ten sposób, tysiące razy:
ROZPOCZNIJ TRANSAKCJĘ; UPDATE TOP (1) dbo.
Czas trwania i wskaźniki błędów | Przenoszenie schematu | ABORT_AFTER_WAIT: SELF | ABORT_AFTER_WAIT: BLOKUJĄCE |
---|---|---|---|
Średni czas trwania — transfer/przełączanie | 96,4 sekundy | 68,4 sekundy | 20,8 sekundy |
Średni czas trwania — DML | 18,7 sekundy | 2,7 sekundy | 2,9 sekundy |
Wyjątki – transfer/przełączanie | 0 | 0,5/minutę | 0 |
Wyjątki — DML | 0 | 0 | 25,5/minutę |
Pamiętaj, że czas trwania i liczba wyjątków będą w dużym stopniu zależne od specyfikacji twojego serwera i tego, co jeszcze dzieje się w twoim środowisku. Należy również zauważyć, że chociaż nie było wyjątków dla testów transferu schematu podczas korzystania z SQLQueryStress, w zależności od używanej aplikacji mogą wystąpić bardziej rygorystyczne limity czasu. I średnio było o tyle wolniej, ponieważ blokowanie narastało znacznie bardziej agresywnie. Nikt nigdy nie chce wyjątków, ale kiedy pojawia się taki kompromis, możesz preferować kilka wyjątków tu i tam (w zależności od częstotliwości operacji odświeżania) niż wszyscy, którzy przez cały czas czekają dłużej.
Przełączanie partycji a transfer zmiany nazwy/schematu w celu odświeżenia tabel SQL Server
Przełączanie partycji pozwala wybrać, która część procesu ponosi koszt współbieżności. Możesz dać pierwszeństwo procesowi przełączania, aby dane były bardziej niezawodnie świeże, ale oznacza to, że niektóre zapytania zakończą się niepowodzeniem. Odwrotnie, możesz ustalić priorytety zapytań, kosztem wolniejszego procesu odświeżania (i okazjonalnych awarii). Głównym celem jest przełączanie partycji SQL Server, które jest lepszą metodą odświeżania tabel SQL Server w porównaniu z poprzednimi technikami zmiany nazwy/schematu w prawie wszystkich punktach i można użyć bardziej niezawodnej logiki ponawiania prób lub eksperymentować z tolerancjami czasu trwania, aby wylądować w optymalnym miejscu dla Twojego obciążenia pracą.
-
datetime vs datetime2 w SQL Server:jaka jest różnica?
-
Czy można określić warunek w Count()?
-
Jak mogę utworzyć użytkownika w bazie danych SQL Server Express dodanej do mojego projektu?
-
Jak używać sortowania (Order By) w instrukcji Select w SQL Server — samouczek SQL Server / TSQL, część 109
-
Jak usunąć kolumnę z ograniczeniem w SQL Server