sql >> Database teknologi >  >> RDS >> Database

DBCC_OBJECT_METADATA-låsen

For at fortsætte min serie af artikler om låse, vil jeg denne gang diskutere DBCC_OBJECT_METADATA låsen og vise, hvordan den kan være en stor flaskehals for konsistenstjek forud for SQL Server 2016 under visse omstændigheder. Problemet påvirker DBCC CHECKDB, DBCC CHECKTABLE og DBCC CHECKFILEGROUP, men for klarhedens skyld vil jeg blot henvise til DBCC CHECKDB for resten af ​​dette indlæg.

Du undrer dig måske over, hvorfor jeg skriver om et problem, der påvirker ældre versioner, men der er stadig et stort antal SQL Server 2014 og ældre forekomster derude, så det er et gyldigt emne for min serie.

Jeg anbefaler stærkt, at du læser det første indlæg i serien før dette, så du har al den generelle baggrundsviden om låse.

Hvad er DBCC_OBJECT_METADATA-låsen?

For at forklare denne lås, er jeg nødt til at forklare lidt om, hvordan DBCC CHECKDB fungerer.

Blandt det enorme antal konsistenstjek, som DBCC CHECKDB udfører, er en kontrol af rigtigheden af ​​ikke-klyngede indekser. Specifikt sørger DBCC CHECKDB for:

  1. For hver ikke-klyngede indekspost i hvert ikke-klyngede indeks er der nøjagtig én "matchende" datapost i basistabellen (enten en heap eller et klynget indeks)
  2. For hver datapost i en tabel er der nøjagtig én "matchende" ikke-klyngede indekspost i hvert ikke-klyngede indeks, der er defineret for tabellen, under hensyntagen til filtrerede indekser

Uden at gå for meget i dybden i detaljerne om, hvordan dette gøres, for hver datapost i en tabel konstruerer DBCC CHECKDB hver ikke-klyngede indekspost, der skulle eksistere for hvert ikke-klyngede indeks, og sørger for, at den konstruerede ikke-klyngede indekspost nøjagtigt matcher den faktiske ikke-klyngede indekspost. Hvis det ikke-klyngede indeks har en beregnet kolonne i sig (enten som en del af den ikke-klyngede indeksnøgle eller som en INCLUDED-kolonne), skal DBCC CHECKDB finde ud af den beregnede kolonneværdi, der skal bruges, når indeksposterne konstrueres.

Ud over de ikke-klyngede indekskorrekthedskontroller, hvis der er en vedvarende beregnet kolonne i definitionen af ​​en tabel, og for hver datapost i tabellen skal DBCC CHECKDB kontrollere, at den vedvarende værdi er korrekt, uanset om denne kolonne er en del af et ikke-klynget indeks eller ej.

Så hvordan finder den ud af de beregnede kolonneværdier?

Forespørgselsprocessoren giver en mekanisme til at beregne beregnede kolonneværdier, kaldet "udtryksevaluatoren". DBCC CHECKDB kalder denne funktion og giver passende metadataoplysninger og dataposten, og udtryksevaluatoren bruger den lagrede definition af den beregnede kolonne i metadataene og værdierne fra dataposten og returnerer værdien af ​​den beregnede kolonne, som DBCC CHECKDB kan bruge . Den interne funktion af udtryksevaluatoren er uden for DBCC-kodens kontrol, men for at kunne bruge udtryksevaluatoren skal der først anskaffes en lås; DBCC_OBJECT_METADATA låsen.

Hvordan bliver låsen en flaskehals?

Her er problemet:der er kun én acceptabel tilstand, hvor DBCC_OBJECT_METADATA-låsen kan erhverves, før du bruger udtryksevaluatoren, og det er EX-tilstand (eksklusiv). Og som du ved fra at læse introindlægget til serien, kan kun én tråd ad gangen holde låsen i EX-tilstand.

Trækker alle disse oplysninger sammen:Når en database har vedvarende beregnede kolonner eller ikke-klyngede indekser, der har beregnede kolonner i dem, skal udtryksevaluatoren bruges. Hvis SQL Server-udgaven er Enterprise, er DBCC CHECKDB i stand til at bruge parallelisme, og det har flere tråde, der udfører de forskellige kontroller. Og så snart du har flere tråde, der forsøger at erhverve en lås i EX-tilstand, bliver den lås en flaskehals. Hvor stor en flaskehals det bliver, afhænger af, hvor meget udtryksevaluatoren skal bruges, så jo mere vedvarende beregnede kolonner eller ikke-klyngede indekser, der bruger beregnede kolonner, og jo større antal tabelrækker der er i disse tabeller, større flaskehals bliver DBCC _OBJECT_METADATA låsen.

Men husk, denne flaskehals sker kun for versioner af SQL Server, der er tidligere end SQL Server 2016. I SQL Server 2016 besluttede Microsoft at "rette" flaskehalsen ved at deaktivere tjek af ikke-klyngede indekser ved at bruge beregnede kolonner som standard og kun gøre dem, når MED EXTENDED_LOGICAL_CHECKS er brugt.

Viser flaskehalsen

Du kan nemt genskabe flaskehalsen for dig selv ved at køre DBCC CHECKDB på en database, der enten har vedvarende beregnede kolonner eller ikke-klyngede indekser med beregnede kolonner i, og den Microsoft-leverede AdventureWorks-database er et godt eksempel. Du kan downloade sikkerhedskopier af AdventureWorks til din version af SQL Server herfra. Jeg kørte nogle test ved hjælp af en AdventureWorks2014-database på en SQL Server 2014-instans (på en 32-core Dell R720), og jeg forstørrede databasen til et par hundrede GB ved hjælp af Jonathans scripts.

Da jeg kørte DBCC CHECKDB, med server MAXDOP sat til 0, tog det mere end 5 timer at køre. Ventetypen LATCH_EX tegnede sig for omkring 30 % af ventetiden, hvor hver ventetid kun var 1 millisekund, og 99 % af ventetiden på LATCH_EX var for DBCC_OBJECT_METADATA-låsen.

Jeg ledte efter ikke-klyngede indekser indeholdende beregnede kolonner ved hjælp af følgende kode:

SELECT
      [s].[name] AS [Schema],
      [o].[name] AS [Object],
      [i].[name] AS [Index],
      [c].[name] AS [Column],
      [ic].*
  FROM sys.columns [c]
  JOIN sys.index_columns [ic]
      ON [ic].[object_id] = [c].[object_id]
      AND [ic].[column_id] = [c].[column_id]
  JOIN sys.indexes [i]
      ON [i].[object_id] = [ic].[object_id]
      AND [i].[index_id] = [ic].[index_id]
  JOIN sys.objects [o]
      ON [i].[object_id] = [o].[object_id]
  JOIN sys.schemas [s]
      ON [o].[schema_id] = [s].[schema_id]
  WHERE [c].[is_computed] = 1;

Denne kode fandt seks ikke-klyngede indekser i AdventureWorks2014-databasen. Jeg deaktiverede alle seks indekser (ved hjælp af ALTER INDEX ... DISABLE) og kørte DBCC CHECKDB igen, og det blev afsluttet på omkring 18 minutter. Så DBCC_OBJECT_METADATA-låseflaskehalsen var en vigtig faktor i at få DBCC CHECKDB til at køre mere end 16 gange langsommere!

Oversigt

Desværre er deaktivering af ikke-klyngede indekser ved hjælp af beregnede kolonner (og senere genaktivering af dem ved hjælp af ALTER INDEX … REBUILD) den *eneste* måde at fjerne DBCC_OBJECT_METADATA låseflaskehalsen i versioner før SQL Server 2016, mens alle andre funktioner i DBCC stadig bevares CHECKDB. Deaktivering af ikke-klyngede indekser er sandsynligvis ikke noget, du vil gøre i et produktionsmiljø, medmindre du har et vedligeholdelsesvindue uden aktivitet. Dette betyder, at du sandsynligvis kun vil deaktivere disse ikke-klyngede indekser for at fjerne flaskehalsen, hvis dine konsistenstjek overføres til en anden server ved hjælp af backup-copy-restore-CHECKDB-metoden.

En anden måde at gøre det på er at bruge indstillingen MED PHYSICAL_ONLY, når du kører DBCC CHECKDB, men så går du glip af alle de dybdegående logiske kontroller, så jeg er ikke en stor fan af at anbefale det som løsningen.


  1. SqlDataSourceEnumerator.Instance.GetDataSources() finder ikke lokal SQL-server 2008-instans

  2. Sådan fungerer QUOTE() i MariaDB

  3. Kan ikke indsætte Unicode ved hjælp af cx-Oracle

  4. Eksempler på konvertering af 'dato' til 'datetime' i SQL Server (T-SQL)