sql >> Database >  >> RDS >> Sqlserver

Vernieuwen van SQL Server-tabellen met minder onderbrekingen met behulp van Partition Switching

Een veelvoorkomende vereiste in ETL en verschillende rapportagescenario's is om stilletjes een SQL Server-stagingtabel op de achtergrond te laden, zodat gebruikers die de gegevens opvragen niet worden beïnvloed door de schrijfbewerkingen en vice versa. De truc is hoe en wanneer u gebruikers naar de nieuwe, vernieuwde versie van de gegevens wijst.

Vereenvoudigd voorbeeld van een verzameltabel:een boerenmarktanalogie

Dus, wat is een staging-tabel in SQL? Een verzameltafel kan gemakkelijker worden begrepen aan de hand van een praktijkvoorbeeld:laten we zeggen dat je een tafel vol groenten hebt die je op de lokale boerenmarkt verkoopt. Terwijl je groenten verkopen en je nieuwe voorraad binnenhaalt:

  • Als je een lading nieuwe groenten meeneemt, kost het je 20 minuten om de tafel leeg te ruimen en de resterende voorraad te vervangen door het nieuwere product.
  • Je wilt niet dat klanten daar 20 minuten moeten zitten wachten tot de omschakeling plaatsvindt, aangezien de meeste hun groenten elders zullen halen.

Nu, wat als je een tweede lege tafel had waar je de nieuwe groenten laadt, en terwijl je dat doet, kunnen klanten nog steeds de oudere groenten van de eerste tafel kopen? (Laten we net doen alsof het niet is omdat de oudere groenten slecht zijn geworden of anderszins minder wenselijk zijn.)

Tabellen in SQL Server vernieuwen

Er zijn verschillende methoden om hele tabellen opnieuw te laden terwijl ze actief worden ondervraagd; twee decennia geleden maakte ik ongebreideld gebruik van sp_rename — Ik zou een shell-spel spelen met een lege schaduwkopie van de tafel, vrolijk de schaduwkopie herladen en dan alleen de hernoeming uitvoeren binnen een transactie.

In SQL Server 2005 begon ik schema's te gebruiken voor het bewaren van schaduwkopieën van tabellen die ik eenvoudigweg verplaatste met dezelfde shell-speltechniek, waarover ik in deze twee berichten schreef:

  • Trick Shots:Schema Switch-a-Roo
  • Schema Switch-a-Roo, deel 2

Het enige voordeel van het overbrengen van objecten tussen schema's boven het hernoemen ervan, is dat er geen waarschuwingsberichten zijn over het hernoemen van een object - wat op zich niet eens een probleem is, behalve dat de waarschuwingsberichten de geschiedenislogboeken van agenten veel sneller vullen.

Beide benaderingen vereisen nog steeds een Schema Modificatie (Sch-M) vergrendeling, dus ze moeten wachten tot bestaande transacties hun eigen vergrendelingen vrijgeven. Zodra ze hun Sch-M-vergrendeling hebben verkregen, blokkeren ze alle volgende query's waarvoor schema-stabiliteitsvergrendelingen (Sch-S) nodig zijn ... wat bijna elke query is. Het kan snel een blokkeerketen-nachtmerrie worden, omdat nieuwe vragen waarvoor Sch-S nodig is, in een wachtrij achter de Sch-M moeten komen. (En nee, je kunt dit niet omzeilen door RCSI of NOLOCK te gebruiken overal, omdat zelfs die vragen nog steeds Sch-S vereisen. Je kunt Sch-S niet aanschaffen met een Sch-M erop, omdat ze niet compatibel zijn - Michael J. Swart vertelt daar hier over.)

Kendra Little opende echt mijn ogen over de gevaren van schema-overdracht in haar post, "Staging Data:Locking Danger with ALTER SCHEMA TRANSFER." Daar laat ze zien waarom schemaoverdracht erger kan zijn dan hernoemen. Later beschreef ze een derde en veel minder ingrijpende manier om tabellen uit te wisselen, die ik nu uitsluitend gebruik:partitie-omschakeling. Met deze methode kan de switch met een lagere prioriteit wachten, wat niet eens een optie is met de technieken voor hernoemen of schemaoverdracht. Joe Sack ging uitgebreid in op deze verbetering die werd toegevoegd in SQL Server 2014:"Verkenning van wachtopties voor vergrendeling met lage prioriteit in SQL Server 2014 CTP1."

SQL Server Partition Switching Voorbeeld

Laten we eens kijken naar een eenvoudig voorbeeld, in navolging van Kendra's grondige kern hier. Eerst maken we twee nieuwe databases:

DATABASE MAKEN NewWay;DATABASE MAKEN OldWay;GO

In de nieuwe database zullen we een tabel maken om onze groente-inventaris op te slaan, en twee exemplaren van de tafel voor ons shell-spel:

GEBRUIK NewWay;GO MAAK TABEL dbo.Vegetables_NewWay( VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar(max));GO -- we moeten twee extra kopieën van de tabel maken. MAAK TABEL dbo.Vegetables_NewWay_prev( VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar (max));GO CREATE TABLE dbo.Vegetables_NewWay_hold ( VegetableID int, Name sysname, WhenPicked datetime, BackStory 
 We creëren een procedure die de voorbereidingskopie van de tabel laadt en vervolgens een transactie gebruikt om de huidige kopie uit te schakelen.

PROCEDURE MAKEN dbo.DoTheVeggieSwap_NewWayASBEGIN STEL NOCOUNT IN; TRUNCATE 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_objects AS model.sys.all_objects all_sql_modules AS m ON o.[object_id] =m.[object_id]; -- moet hier Sch-M-sluizen nemen:BEGIN TRANSACTIE; WIJZIG TABEL dbo.Vegetables_NewWay SCHAKELEN NAAR dbo.Vegetables_NewWay_hold WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION =1 MINUTES, ABORT_AFTER_WAIT =BLOCKERS)); WIJZIG TABEL dbo.Vegetables_NewWay_prev SCHAKELEN NAAR dbo.Vegetables_NewWay; COMMIT TRANSACTIE; -- en nu zullen gebruikers de nieuwe gegevens in dbo opvragen -- kunnen de oude kopie terugzetten en inkorten -- zonder andere vragen te verstoren ALTER TABLE dbo.Vegetables_NewWay_hold SCHAKELEN NAAR dbo.Vegetables_NewWay_prev; TRUNCATE TABLE dbo.Vegetables_NewWay_prev;ENDGO

De schoonheid van WAIT_AT_LOW_PRIORITY is dat je het gedrag volledig kunt controleren met de ABORT_AFTER_WAIT optie:

ABORT_AFTER_WAIT
instelling
Beschrijving / symptomen
ZELF Dit betekent dat de schakelaar opgeeft na n minuten.

Voor de sessie die de omschakeling probeert uit te voeren, zal dit verschijnen als de foutmelding:

Time-outperiode voor vergrendelingsverzoek overschreden.
BLOKKER Dit dicteert dat de schakelaar wacht tot n minuten, en dwing zichzelf dan naar voren door alle blokkers ervoor te doden .

Sessies die proberen te communiceren met de tafel die worden gestoten door de schakelbewerking, zullen een combinatie van deze foutmeldingen zien:

Uw sessie is afgebroken vanwege een DDL-bewerking met hoge prioriteit.

Kan de uitvoering niet voortzetten omdat de sessie zich in de kill-status bevindt.

Er is een ernstige fout opgetreden in de huidige opdracht. De eventuele resultaten moeten worden weggegooid.

GEEN Dit zegt dat de schakelaar graag wacht tot hij aan de beurt is, ongeacht MAX_DURATION .

Dit is hetzelfde gedrag als bij hernoemen, schemaoverdracht of partitiewisseling zonder WAIT_AT_LOW_PRIORITY .

De BLOCKERS optie is niet de vriendelijkste manier om dingen aan te pakken, omdat je al zegt dat het goed is dat gebruikers door deze fasering / switch-bewerking gegevens zien die een beetje verouderd zijn. Ik gebruik waarschijnlijk liever SELF en laat de bewerking opnieuw proberen in gevallen waarin het de vereiste sloten niet binnen de toegewezen tijd kon krijgen. Ik zou echter bijhouden hoe vaak het mislukt, vooral opeenvolgende fouten, omdat je zeker wilt weten dat de gegevens nooit te oud worden.

Vergeleken met de oude manier van schakelen tussen schema's

Hier is hoe ik de overstap eerder zou hebben afgehandeld:

GEBRUIK OldWay;GO -- maak twee schema's en twee kopieën van de tabel CREATE SCHEMA prev AUTHORIZATION dbo;GO CREATE SCHEMA hold AUTHORIZATION dbo;GO CREATE TABLE dbo.Vegetables_OldWay( VegetableID int, Name sysname, WhenPicked datetimevarchar, (BackStory max));GO CREATE TABLE prev.Vegetables_OldWay( VegetableID int, Name sysname, WhenPicked datetime, BackStory nvarchar(max));GO CREATE PROCEDURE dbo.DoTheVeggieSwap_OldWayASBEGIN STEL NOCOUNT ON in; TRUNCATE TABLE vorige.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_joIN AS model.o INNERLIJKE JOIN AS model all_sql_modules AS m ON o.[object_id] =m.[object_id]; -- moet hier Sch-M-sluizen nemen:BEGIN TRANSACTIE; ALTER SCHEMA hold TRANSFER dbo.Vegetables_OldWay; WIJZIG SCHEMA dbo OVERDRACHT vorige.Vegetables_OldWay; COMMIT TRANSACTIE; -- en nu zullen gebruikers de nieuwe gegevens in dbo opvragen -- kunnen de oude kopie terugzetten en inkorten zonder -- andere vragen te verstoren:ALTER SCHEMA prev TRANSFER hold.Vegetables_OldWay; TRUNCATE TABLE prev.Vegetables_OldWay;ENDGO

Ik heb gelijktijdigheidstests uitgevoerd door twee vensters van Erik Ejlskov Jensen's SQLQueryStress te gebruiken:een om elke minuut een aanroep van de procedure te herhalen en de andere om 16 threads zoals deze duizenden keren uit te voeren:

BEGIN TRANSACTIE; BOVENSTE BIJWERKEN (1) dbo. SET naam +='x';SELECT TOP (10) naam UIT dbo. BESTELLEN OP NEWID();WACHTVERTRAGING '00:00:02'; TRANSACTIE COMMIT;

U kunt kijken naar de uitvoer van SQLQueryStress, of sys.dm_exec_query_stats, of Query Store, en u ziet iets in de trant van de volgende resultaten (maar ik raad ten zeerste aan om een ​​kwalitatief hoogstaand hulpprogramma voor prestatiebewaking van SQL Server te gebruiken als u serieus bent over proactief database-omgevingen optimaliseren):

Duur- en foutpercentages Schemaoverdracht ABORT_AFTER_WAIT:
SELF
ABORT_AFTER_WAIT:
BLOCKERS
Gemiddelde duur – Overzetten/wisselen 96,4 seconden 68,4 seconden 20,8 seconden
Gem. duur – DML 18,7 seconden 2,7 seconden 2,9 seconden
Uitzonderingen – Overzetten/wisselen 0 0,5/minuut 0
Uitzonderingen – DML 0 0 25,5/minuut

Houd er rekening mee dat de duur en het aantal uitzonderingen sterk afhankelijk zijn van uw serverspecificaties en wat er nog meer in uw omgeving gebeurt. Houd er ook rekening mee dat, hoewel er geen uitzonderingen waren voor de schemaoverdrachtstests bij het gebruik van SQLQueryStress, u mogelijk wat striktere time-outs krijgt, afhankelijk van de verbruikende toepassing. En het was gemiddeld zo veel langzamer, omdat de blokkering zich veel agressiever opstapelde. Niemand wil ooit uitzonderingen, maar als er een afweging als deze is, heb je misschien liever hier en daar een paar uitzonderingen (afhankelijk van de frequentie van de vernieuwingsbewerking) dan dat iedereen de hele tijd langer moet wachten.

Partitiewisseling versus hernoemen/schemaoverdracht om SQL Server-tabellen te vernieuwen

Met het wisselen van partities kunt u kiezen welk deel van uw proces de kosten van gelijktijdigheid draagt. U kunt de voorkeur geven aan het schakelproces, zodat de gegevens betrouwbaarder vers zijn, maar dit betekent dat sommige van uw zoekopdrachten zullen mislukken. Omgekeerd kunt u de query's prioriteren, ten koste van een langzamer verversingsproces (en af ​​en toe een storing daar). De belangrijkste drijfveer is dat SQL Server-partitiewisseling een superieure methode is om SQL Server-tabellen te vernieuwen in vergelijking met de vorige technieken voor hernoemen / schemaoverdracht op bijna alle punten, en u kunt robuustere logica voor opnieuw proberen gebruiken of experimenteren met duurtoleranties om op de goede plek te landen voor uw werklast.


  1. Hoe u Foreign Key Check in MySQL uitschakelt?

  2. Heroku Rails 4 kon geen verbinding maken met de server:verbinding geweigerd

  3. cx_Oracle:Hoe kan ik elke rij als een woordenboek ontvangen?

  4. MySQL Verwijder dubbele records