sql >> Databasteknik >  >> RDS >> Database

DBCC_OBJECT_METADATA-spärren

För att fortsätta min serie artiklar om låsningar, den här gången ska jag diskutera DBCC_OBJECT_METADATA-låset och visa hur det kan vara en stor flaskhals för konsistenskontroller före SQL Server 2016 under vissa omständigheter. Problemet påverkar DBCC CHECKDB, DBCC CHECKTABLE och DBCC CHECKFILEGROUP, men för tydlighetens skull hänvisar jag bara till DBCC CHECKDB för resten av det här inlägget.

Du kanske undrar varför jag skriver om ett problem som påverkar äldre versioner, men det finns fortfarande ett stort antal SQL Server 2014 och äldre instanser där ute, så det är ett giltigt ämne för min serie.

Jag rekommenderar starkt att du läser det första inlägget i serien före detta, så att du har all allmän bakgrundskunskap om spärrar.

Vad är DBCC_OBJECT_METADATA-spärren?

För att förklara denna spärr måste jag förklara lite om hur DBCC CHECKDB fungerar.

Bland det enorma antalet konsistenskontroller som DBCC CHECKDB utför är en kontroll av korrektheten hos icke-klustrade index. Specifikt ser DBCC CHECKDB till:

  1. För varje icke-klustrad indexpost i varje icke-klustrat index, finns det exakt en "matchande" datapost i bastabellen (antingen en heap eller ett klustrat index)
  2. För varje datapost i en tabell finns det exakt en "matchande" icke-klustrad indexpost i varje icke-klustrat index som är definierat för tabellen, med hänsyn tagen till filtrerade index.

Utan att gå ner för mycket på djupet i detaljerna om hur detta görs, för varje datapost i en tabell, konstruerar DBCC CHECKDB varje icke-klustrad indexpost som ska finnas för varje icke-klustrad index och ser till att den konstruerade icke-klustrade indexposten exakt matchar den faktiska icke-klustrad indexpost. Om det icke-klustrade indexet har en beräknad kolumn i sig (antingen som en del av den icke-klustrade indexnyckeln eller som en INCLUDED-kolumn), måste DBCC CHECKDB ta reda på det beräknade kolumnvärdet som ska användas när indexposterna konstrueras.

Förutom de icke-klustrade indexets korrekthetskontroller, om det finns en beständig beräknad kolumn i definitionen av en tabell, och för varje datapost i tabellen måste DBCC CHECKDB kontrollera att det kvarstående värdet är korrekt, oavsett om den kolumnen är en del av ett icke-klustrat index eller inte.

Så hur räknar den ut de beräknade kolumnvärdena?

Frågeprocessorn tillhandahåller en mekanism för att beräkna beräknade kolumnvärden, kallad "uttrycksutvärderaren". DBCC CHECKDB anropar den funktionen, tillhandahåller lämplig metadatainformation och dataposten, och uttrycksutvärderaren använder den lagrade definitionen av den beräknade kolumnen i metadata och värdena från dataposten och returnerar värdet på den beräknade kolumnen för DBCC CHECKDB att använda . Uttrycksutvärderarens interna funktion ligger utanför DBCC-kodens kontroll, men för att kunna använda uttrycksutvärderaren måste en spärr först förvärvas; DBCC_OBJECT_METADATA-spärren.

Hur blir spärren en flaskhals?

Här är problemet:det finns bara ett acceptabelt läge där DBCC_OBJECT_METADATA-låset kan erhållas innan uttrycksutvärderaren används, och det är EX-läge (exklusivt). Och som du vet från att läsa introduktionsinlägget till serien, kan bara en tråd åt gången hålla spärren i EX-läge.

Att dra ihop all denna information:när en databas har beständiga beräknade kolumner, eller icke-klustrade index som har beräknade kolumner i dem, måste uttrycksutvärderaren användas. Om SQL Server-utgåvan är Enterprise, kan DBCC CHECKDB använda parallellism och så har flera trådar som utför de olika kontrollerna. Och så fort du har flera trådar som försöker skaffa en spärr i EX-läge, blir den spärren en flaskhals. Hur stor en flaskhals det blir beror på hur mycket uttrycksutvärderaren behöver användas, så ju mer beständiga beräknade kolumner eller icke-klustrade index som använder beräknade kolumner det finns, och ju fler tabellrader det finns i dessa tabeller, större flaskhalsen blir DBCC _OBJECT_METADATA spärren.

Men kom ihåg att den här flaskhalsen bara inträffar för versioner av SQL Server tidigare än SQL Server 2016. I SQL Server 2016 beslutade Microsoft att "åtgärda" flaskhalsen genom att stänga av kontrollerna av icke-klustrade index som använder beräknade kolumner som standard och endast göra dem när MED Alternativet EXTENDED_LOGICAL_CHECKS används.

Visar flaskhalsen

Du kan enkelt återskapa flaskhalsen för dig själv genom att köra DBCC CHECKDB på en databas som har antingen beständiga beräknade kolumner eller icke-klustrade index med beräknade kolumner i, och den av Microsoft tillhandahållna AdventureWorks-databasen är ett bra exempel. Du kan ladda ner säkerhetskopior av AdventureWorks för din version av SQL Server härifrån. Jag körde några tester med hjälp av en AdventureWorks2014-databas på en SQL Server 2014-instans (på en 32-kärnig Dell R720), och jag förstorade databasen till några hundra GB med hjälp av Jonathans skript.

När jag körde DBCC CHECKDB, med servern MAXDOP inställd på 0, tog det mer än 5 timmar att köra. Väntetypen LATCH_EX stod för cirka 30 % av väntetiderna, där varje väntetid bara var 1 millisekund, och 99 % av LATCH_EX-väntningarna var för DBCC_OBJECT_METADATA-låset.

Jag letade efter icke-klustrade index som innehåller beräknade kolumner med hjälp av följande kod:

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;

Den koden hittade sex icke-klustrade index i AdventureWorks2014-databasen. Jag inaktiverade alla sex indexen (med ALTER INDEX ... DISABLE) och körde om DBCC CHECKDB och det slutfördes på cirka 18 minuter. Så DBCC_OBJECT_METADATA spärrflaskhalsen var en viktig faktor för att få DBCC CHECKDB att köra mer än 16 gånger långsammare!

Sammanfattning

Tyvärr är att inaktivera icke-klustrade index med hjälp av beräknade kolumner (och sedan senare återaktivera dem med ALTER INDEX … REBUILD) det *enda* sättet att ta bort DBCC_OBJECT_METADATA-låsflaskhalsen i versioner före SQL Server 2016 samtidigt som alla andra funktioner i DBCC behålls KONTROLLERADB. Att inaktivera icke-klustrade index är sannolikt inte något du kommer att vilja göra i en produktionsmiljö om du inte har ett underhållsfönster för noll aktivitet. Det betyder att du förmodligen bara kommer att inaktivera dessa icke-klustrade index för att ta bort flaskhalsen om dina konsistenskontroller laddas av till en annan server med metoden backup-copy-restore-CHECKDB.

Ett annat sätt att göra det är att använda alternativet MED PHYSICAL_ONLY när du kör DBCC CHECKDB men då går du miste om alla djupgående logiska kontroller, så jag är inte ett stort fan av att rekommendera det som lösningen.


  1. Hur man återställer MySQL root-lösenordet

  2. Ansluter till Oracle 12c Database från Pentaho Data Integration (Kettle) Community Edition

  3. Med sqlalchemy hur man dynamiskt binder till databasmotorn per begäran

  4. Använda endast tangentbordsnavigering i Word, Excel och PowerPoint (Del 1:The Ribbon)