Dela via


sys.dm_db_index_physical_stats (Transact-SQL)

gäller för:SQL ServerAzure SQL DatabaseAzure SQL Managed Instance

Returnerar storleks- och fragmenteringsinformation för data och index för den angivna tabellen eller vyn i SQL Server Database Engine. För ett index returneras en rad för varje nivå i B-trädet i varje partition. För en heap returneras en rad för IN_ROW_DATA allokeringsenhet för varje partition. För stora objektdata returneras en rad för LOB_DATA allokeringsenhet för varje partition. Om rad-overflow-data finns i tabellen returneras en rad för ROW_OVERFLOW_DATA allokeringsenhet i varje partition.

Not

I dokumentationen används termen B-träd vanligtvis som referens till index. I radlagringsindex implementerar databasmotorn ett B+-träd. Detta gäller inte för kolumnlagringsindex eller index i minnesoptimerade tabeller. Mer information finns i arkitekturen och designguiden för SQL Server och Azure SQL-index.

sys.dm_db_index_physical_stats returnerar inte information om minnesoptimerade index. Information om minnesoptimerad indexanvändning finns i sys.dm_db_xtp_index_stats.

Om du frågar sys.dm_db_index_physical_stats på en serverinstans som är värd för en tillgänglighetsgrupp läsbar sekundär replikkan det uppstå ett REDO blockeringsproblem. Detta beror på att den här dynamiska hanteringsvyn hämtar ett Intent-Shared(IS) lås på den angivna användartabellen eller vyn som kan blockera begäranden av en REDO tråd för ett exklusivt (X) lås på användartabellen eller vyn.

Transact-SQL syntaxkonventioner

Syntax

sys.dm_db_index_physical_stats (
    { database_id | NULL | 0 | DEFAULT }
  , { object_id | NULL | 0 | DEFAULT }
  , { index_id | NULL | 0 | -1 | DEFAULT }
  , { partition_number | NULL | 0 | DEFAULT }
  , { mode | NULL | DEFAULT }
)

Argument

database_id | NULL | 0 | STANDARD

Databasens ID. database_id är smallint. Giltiga indata är ID för en databas, NULL, 0eller DEFAULT. Standardvärdet är 0. NULL, 0och DEFAULT är motsvarande värden i den här kontexten.

Ange NULL för att returnera information för alla databaser i SQL Server-instansen. Om du anger NULL för database_idmåste du också ange NULL för object_id, index_idoch partition_number.

Den inbyggda funktionen DB_ID kan anges. När du använder DB_ID utan att ange ett databasnamn måste kompatibilitetsnivån för den aktuella databasen vara 90 eller större.

object_id | NULL | 0 | STANDARD

Objekt-ID för tabellen eller visa indexet är aktiverat. object_id är int. Giltiga indata är ID för en tabell och vy, NULL, 0eller DEFAULT. Standardvärdet är 0. NULL, 0och DEFAULT är motsvarande värden i den här kontexten.

I SQL Server 2016 (13.x) och senare versioner innehåller giltiga indata även könamnet för service broker eller köns interna tabellnamn. När standardparametrar tillämpas (dvs. alla objekt, alla index osv.), ingår fragmenteringsinformation för alla köer i resultatuppsättningen.

Ange NULL för att returnera information för alla tabeller och vyer i den angivna databasen. Om du anger NULL för object_idmåste du också ange NULL för index_id och partition_number.

index_id | 0 | NULL | -1 | STANDARD

Indexets ID. index_id är int. Giltiga indata är ID för ett index, 0 om object_id är en heap, NULL, -1eller DEFAULT. Standardvärdet är -1. NULL, -1och DEFAULT är motsvarande värden i den här kontexten.

Ange NULL för att returnera information för alla index för en bastabell eller vy. Om du anger NULL för index_idmåste du också ange NULL för partition_number.

partition_number | NULL | 0 | STANDARD

Partitionsnumret i objektet. partition_number är int. Giltiga indata är partition_number för ett index eller en heap, NULL, 0eller DEFAULT. Standardvärdet är 0. NULL, 0och DEFAULT är motsvarande värden i den här kontexten.

Ange NULL för att returnera information för alla partitioner i det ägande objektet.

partition_number är 1-baserad. Ett icke-partitionerat index eller en heap har partition_number inställt på 1.

läge | NULL | STANDARD

Namnet på läget. läge anger genomsökningsnivån som används för att hämta statistik. läge är sysname. Giltiga indata är DEFAULT, NULL, LIMITED, SAMPLEDeller DETAILED. Standardvärdet (NULL) är LIMITED.

Tabellen returnerades

Kolumnnamn Datatyp Beskrivning
database_id liten Databas-ID för tabellen eller vyn.

I Azure SQL Database är värdena unika i en enskild databas eller en elastisk pool, men inte inom en logisk server.
object_id int Objekt-ID för tabellen eller vyn som indexet är på.
index_id int Index-ID för ett index.

0 = Heap.
partition_number int 1-baserat partitionsnummer i det ägande objektet. en tabell, vy eller ett index.

1 = Icke-partitionerat index eller heap.
index_type_desc nvarchar(60) Beskrivning av indextypen:

- HEAP
- CLUSTERED INDEX
- NONCLUSTERED INDEX
- PRIMARY XML INDEX
- EXTENDED INDEX
- XML INDEX
- COLUMNSTORE MAPPING INDEX (intern)
- COLUMNSTORE DELETEBUFFER INDEX (intern)
- COLUMNSTORE DELETEBITMAP INDEX (intern)
alloc_unit_type_desc nvarchar(60) Beskrivning av typ av allokeringsenhet:

- IN_ROW_DATA
- LOB_DATA
- ROW_OVERFLOW_DATA

Den LOB_DATA allokeringsenheten innehåller data som lagras i kolumner av typen text, ntext, bild, varchar(max), nvarchar(max), varbinary(max)och xml-. Mer information finns i Datatyper.

Den ROW_OVERFLOW_DATA allokeringsenheten innehåller data som lagras i kolumner av typen varchar(n), nvarchar(n), varbinary(n)och sql_variant som skickas utanför rad.
index_depth pytteliten Antal indexnivåer.

1 = Heap, LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenhet.
index_level pytteliten Aktuell nivå för indexet.

0 för index lövnivåer, heaps och LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter.

Större än 0 för icke-lågnivåindex. index_level är högst på rotnivån för ett index.

Icke-nivånivå för index bearbetas endast när läge är DETAILED.
avg_fragmentation_in_percent flyttal Logisk fragmentering för index eller omfattningsfragmentering för heaps i IN_ROW_DATA allokeringsenhet.

Värdet mäts som en procentandel och tar hänsyn till flera filer. Definitioner av logisk fragmentering och omfattningsfragmentering finns i Kommentarer.

0 för LOB_DATA och ROW_OVERFLOW_DATA allokeringsenheter. NULL för heaps när läge är SAMPLED.
fragment_count bigint Antal fragment i lövnivån för en IN_ROW_DATA allokeringsenhet. Mer information om fragment finns i Kommentarer.

NULL för icke-nivånivåer för ett index och LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter. NULL för heaps när läge är SAMPLED.
avg_fragment_size_in_pages flyttal Genomsnittligt antal sidor i ett fragment i lövnivån för en IN_ROW_DATA allokeringsenhet.

NULL för icke-nivånivåer för ett index och LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter. NULL för heaps när läge är SAMPLED.
page_count bigint Totalt antal index- eller datasidor.

För ett index är det totala antalet indexsidor på den aktuella nivån i B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är det totala antalet datasidor i IN_ROW_DATA allokeringsenhet.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, totalt antal sidor i allokeringsenheten.
avg_page_space_used_in_percent flyttal Genomsnittlig procentandel av tillgängligt lagringsutrymme för data som används på alla sidor.

För ett index gäller medelvärdet för den aktuella nivån för B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är medelvärdet av alla datasidor i IN_ROW_DATA allokeringsenhet.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, medelvärdet av alla sidor i allokeringsenheten. NULL när läge är LIMITED.
record_count bigint Totalt antal poster.

För ett index gäller det totala antalet poster för den aktuella nivån för B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är det totala antalet poster i IN_ROW_DATA allokeringsenhet.

Obs! För en heap kanske antalet poster som returneras från den här funktionen inte matchar antalet rader som returneras genom att köra en SELECT COUNT(*) mot heapen. Det beror på att en rad kan innehålla flera poster. I vissa uppdateringssituationer kan till exempel en enskild heap-rad ha en vidarebefordrande post och en vidarebefordrad post som ett resultat av uppdateringsåtgärden. Dessutom delas de flesta stora LOB-rader upp i flera poster i LOB_DATA lagring.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, det totala antalet poster i den fullständiga allokeringsenheten. NULL när läge är LIMITED.
ghost_record_count bigint Antal spökposter som är redo för borttagning av spökrensningsaktiviteten i allokeringsenheten.

0 för icke-nivånivåer för ett index i IN_ROW_DATA allokeringsenhet. NULL när läge är LIMITED.
version_ghost_record_count bigint Antal spökposter som behålls av en utestående ögonblicksbildisoleringstransaktion i en allokeringsenhet.

0 för icke-nivånivåer för ett index i IN_ROW_DATA allokeringsenhet. NULL när läge är LIMITED.
min_record_size_in_bytes int Minsta poststorlek i byte.

För ett index gäller den minsta poststorleken för den aktuella nivån för B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är den minsta poststorleken i IN_ROW_DATA allokeringsenhet.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, den minsta poststorleken i den fullständiga allokeringsenheten. NULL när läge är LIMITED.
max_record_size_in_bytes int Maximal poststorlek i byte.

För ett index gäller den maximala poststorleken för den aktuella nivån för B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är den maximala poststorleken i IN_ROW_DATA allokeringsenhet.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, den maximala poststorleken i den fullständiga allokeringsenheten. NULL när läge är LIMITED.
avg_record_size_in_bytes flyttal Genomsnittlig poststorlek i byte.

För ett index gäller den genomsnittliga poststorleken för den aktuella nivån för B-trädet i IN_ROW_DATA allokeringsenhet.

För en heap är den genomsnittliga poststorleken i IN_ROW_DATA allokeringsenhet.

För LOB_DATA eller ROW_OVERFLOW_DATA allokeringsenheter, den genomsnittliga poststorleken i den fullständiga allokeringsenheten. NULL när läge är LIMITED.
forwarded_record_count bigint Antal poster i en heap som har framåtriktade pekare till en annan dataplats. (Det här tillståndet inträffar under en uppdatering, när det inte finns tillräckligt med utrymme för att lagra den nya raden på den ursprungliga platsen.)

NULL för allokeringsenheter som inte är IN_ROW_DATA allokeringsenheter för en heap. NULL för heaps när läge är LIMITED.
compressed_page_count bigint Antalet komprimerade sidor.

För heaps komprimeras inte nyligen allokerade sidor PAGE. En heap komprimeras PAGE under två särskilda villkor: när data massimporteras eller när en heap återskapas. Vanliga DML-åtgärder som orsakar sidallokeringar komprimeras inte PAGE. Återskapa en heap när värdet för compressed_page_count växer större än det tröskelvärde du vill ha.

För tabeller som har ett grupperat index anger compressed_page_count-värdet effektiviteten för PAGE komprimering.
hobt_id bigint Heap- eller B-träd-ID för indexet eller partitionen.

För kolumnlagringsindex är detta ID för en raduppsättning som spårar interna kolumnlagringsdata för en partition. Raduppsättningarna lagras som datahögar eller B-träd. De har samma index-ID som det överordnade kolumnlagringsindexet. Mer information finns i sys.internal_partitions.
columnstore_delete_buffer_state pytteliten 0 = NOT_APPLICABLE
1 = OPEN
2 = DRAINING
3 = FLUSHING
4 = RETIRING
5 = READY

gäller för: SQL Server 2016 (13.x) och senare versioner, Azure SQL Database och Azure SQL Managed Instance
columnstore_delete_buffer_state_desc nvarchar(60) NOT VALID – det överordnade indexet är inte ett kolumnlagringsindex.

OPEN – deleters och skannrar använder detta.

DRAINING – borttagarna töms, men skannrar använder det fortfarande.

FLUSHING – bufferten stängs och rader i bufferten skrivs till bitmappen delete.

RETIRING – rader i den stängda borttagningsbufferten skrevs till bitmappen för borttagning, men bufferten har inte trunkerats eftersom skannrar fortfarande använder den. Nya skannrar behöver inte använda den tillbakadragna bufferten eftersom den öppna bufferten räcker.

READY – Den här borttagningsbufferten är klar att användas.

gäller för: SQL Server 2016 (13.x) och senare versioner, Azure SQL Database och Azure SQL Managed Instance
version_record_count bigint Det här är antalet radversionsposter som underhålls i det här indexet. Dessa radversioner underhålls av funktionen Accelererad databasåterställning.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database
inrow_version_record_count bigint Antal adr-versionsposter som sparas på dataraden för snabb hämtning.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database
inrow_diff_version_record_count bigint Antal adr-versionsposter som sparas i form av skillnader från basversionen.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database
total_inrow_version_payload_size_in_bytes bigint Total storlek i byte för poster i radversion för det här indexet.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database
offrow_regular_version_record_count bigint Antal versionsposter som sparas utanför den ursprungliga dataraden.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database
offrow_long_term_version_record_count bigint Antal versionsposter som anses vara långsiktiga.

gäller för: SQL Server 2019 (15.x) och senare versioner och Azure SQL Database

Not

I dokumentationen används termen B-träd vanligtvis som referens till index. I radlagringsindex implementerar databasmotorn ett B+-träd. Detta gäller inte för kolumnlagringsindex eller index i minnesoptimerade tabeller. Mer information finns i arkitekturen och designguiden för SQL Server och Azure SQL-index.

Anmärkningar

Funktionen sys.dm_db_index_physical_stats dynamisk hantering ersätter DBCC SHOWCONTIG-instruktionen.

Genomsökningslägen

Läget där funktionen körs avgör vilken genomsökningsnivå som utförs för att hämta de statistiska data som används av funktionen. läge anges som LIMITED, SAMPLEDeller DETAILED. Funktionen passerar sidkedjorna för de allokeringsenheter som utgör de angivna partitionerna i tabellen eller indexet. sys.dm_db_index_physical_stats kräver endast ett Intent-Shared(IS) tabelllås, oavsett vilket läge det körs i.

Det LIMITED läget är det snabbaste läget och söker igenom det minsta antalet sidor. För ett index genomsöks endast sidorna på överordnad nivå i B-trädet (dvs. sidorna ovanför lövnivån). För en heap granskas de associerade PFS- och IAM-sidorna och datasidorna i en heap genomsöks i LIMITED läge.

Med LIMITED läge är compressed_page_countNULL eftersom databasmotorn endast söker igenom icke-bladsidor i B-trädet och IAM- och PFS-sidorna i heapen. Använd SAMPLED läge för att hämta ett uppskattat värde för compressed_page_countoch använd DETAILED läge för att hämta det faktiska värdet för compressed_page_count. SAMPLED-läget returnerar statistik baserat på ett urval på 1 procent av alla sidor i indexet eller heapen. Resultat i SAMPLED läge ska betraktas som ungefärligt. Om indexet eller heapen har färre än 10 000 sidor används DETAILED läge i stället för SAMPLED.

Läget DETAILED söker igenom alla sidor och returnerar all statistik.

Lägena är progressivt långsammare från LIMITED till DETAILEDeftersom mer arbete utförs i varje läge. Om du snabbt vill mäta storleken eller fragmenteringsnivån för en tabell eller ett index använder du läget LIMITED. Det är snabbast och returnerar inte en rad för varje icke-nivå i IN_ROW_DATA allokeringsenhet för indexet.

Använda systemfunktioner för att ange parametervärden

Du kan använda Transact-SQL-funktionerna DB_ID och OBJECT_ID för att ange ett värde för parametrarna database_id och object_id. Att skicka värden som inte är giltiga för dessa funktioner kan dock orsaka oavsiktliga resultat. Om databasen eller objektnamnet till exempel inte kan hittas eftersom de inte finns eller stavas felaktigt returnerar båda funktionerna NULL. Funktionen sys.dm_db_index_physical_stats tolkar NULL som ett jokerteckenvärde som anger alla databaser eller alla objekt.

Dessutom bearbetas funktionen OBJECT_ID innan funktionen sys.dm_db_index_physical_stats anropas och utvärderas därför i kontexten för den aktuella databasen, inte den databas som anges i database_id. Det här beteendet kan göra att funktionen OBJECT_ID returnerar ett NULL värde. eller, om objektnamnet finns i både den aktuella databaskontexten och den angivna databasen, returneras ett felmeddelande. Följande exempel visar dessa oavsiktliga resultat.

USE master;
GO
-- In this example, OBJECT_ID is evaluated in the context of the master database.
-- Because Person.Address does not exist in master, the function returns NULL.
-- When NULL is specified as an object_id, all objects in the database are returned.
-- The same results are returned when an object that is not valid is specified.
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'AdventureWorks2022'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- This example demonstrates the results of specifying a valid object name
-- that exists in both the current database context and
-- in the database specified in the database_id parameter of the
-- sys.dm_db_index_physical_stats function.
-- An error is returned because the ID value returned by OBJECT_ID does not
-- match the ID value of the object in the specified database.
CREATE DATABASE Test;
GO
USE Test;
GO
CREATE SCHEMA Person;
GO
CREATE Table Person.Address(c1 int);
GO
USE AdventureWorks2022;
GO
SELECT * FROM sys.dm_db_index_physical_stats
    (DB_ID(N'Test'), OBJECT_ID(N'Person.Address'), NULL, NULL , 'DETAILED');
GO
-- Clean up temporary database.
DROP DATABASE Test;
GO

Bästa praxis

Kontrollera alltid att ett giltigt ID returneras när du använder DB_ID eller OBJECT_ID. När du till exempel använder OBJECT_IDanger du ett namn i tre delar, till exempel OBJECT_ID(N'AdventureWorks2022.Person.Address')eller testar värdet som returneras av funktionerna innan du använder dem i funktionen sys.dm_db_index_physical_stats. Exempel A och B som följer visar ett säkert sätt att ange databas- och objekt-ID:n.

Identifiera fragmentering

Fragmentering sker genom processen med dataändringar (INSERT, UPDATEoch DELETE-instruktioner) som görs mot tabellen och därför till de index som definierats i tabellen. Eftersom dessa ändringar vanligtvis inte fördelas lika mellan raderna i tabellen och indexen kan varje sidas fullhet variera över tid. För frågor som genomsöker en del av eller alla index i en tabell kan den här typen av fragmentering orsaka fler sidläsningar, vilket hindrar parallell genomsökning av data.

Fragmenteringsnivån för ett index eller en heap visas i kolumnen avg_fragmentation_in_percent. För heaps representerar värdet omfattningens fragmentering av heapen. För index representerar värdet den logiska fragmenteringen av indexet. Till skillnad från DBCC SHOWCONTIGanser algoritmerna för fragmenteringsberäkning i båda fallen lagring som sträcker sig över flera filer och därför är korrekta.

Logisk fragmentering

Det här är procentandelen oordnade sidor i lövsidorna i ett index. En out-of-order-sida är en sida där nästa fysiska sida som allokeras till indexet inte är den sida som pekas på av nästa sida pekare på den aktuella lövsidan.

Fragmentering av omfattning

Det här är procentandelen out-of-order-omfattningar i lövsidorna i en heap. En out-of-order-omfattning är en för vilken omfattningen som innehåller den aktuella sidan för en heap inte fysiskt är nästa utsträckning efter den omfattning som innehåller föregående sida.

Värdet för avg_fragmentation_in_percent ska vara så nära noll som möjligt för maximal prestanda. Värden från 0 procent till 10 procent kan dock accepteras. Alla metoder för att minska fragmentering, till exempel återskapa, omorganisera eller återskapa, kan användas för att minska dessa värden. Mer information om hur du analyserar fragmenteringsgraden i ett index finns i Optimera indexunderhåll för att förbättra frågeprestanda och minska resursförbrukningen.

Minska fragmentering i ett index

När ett index är fragmenterat på ett sätt som påverkar frågeprestanda finns det tre alternativ för att minska fragmenteringen:

  • Släpp och återskapa det klustrade indexet.

    Om du återskapar ett grupperat index omdistribueras data och resulterar i fullständiga datasidor. Fullhetsnivån kan konfigureras med hjälp av alternativet FILLFACTOR i CREATE INDEX. Nackdelarna med den här metoden är att indexet är offline under släpp- och återskapa-cykeln och att åtgärden är atomisk. Om indexskapandet avbryts återskapas inte indexet. Mer information finns i CREATE INDEX.

  • Använd ALTER INDEX REORGANIZE, ersättningen för DBCC INDEXDEFRAG, för att ordna om bladnivåsidorna i indexet i logisk ordning. Eftersom det här är en onlineåtgärd är indexet tillgängligt medan -instruktionen körs. Åtgärden kan också avbrytas utan att arbetet redan har förlorats. Nackdelen med den här metoden är att den inte gör ett lika bra jobb med att omorganisera data som en indexåterställningsåtgärd, och den uppdaterar inte statistik.

  • Använd ALTER INDEX REBUILD, ersättningen för DBCC DBREINDEX, för att återskapa indexet online eller offline. Mer information finns i ALTER INDEX (Transact-SQL).

Enbart fragmentering är inte en tillräcklig anledning att omorganisera eller återskapa ett index. Den huvudsakliga effekten av fragmentering är att det saktar ned sidläsningsgenomflödet under indexgenomsökningar. Detta orsakar långsammare svarstider. Om frågearbetsbelastningen i en fragmenterad tabell eller ett index inte omfattar genomsökningar, eftersom arbetsbelastningen främst är singleton-sökningar, kan det inte ha någon effekt att ta bort fragmentering.

Not

Att köra DBCC SHRINKFILE eller DBCC SHRINKDATABASE kan leda till fragmentering om ett index delvis eller helt flyttas under krympningsåtgärden. Om en krympningsåtgärd måste utföras bör du därför göra det innan fragmenteringen tas bort.

Minska fragmentering i en heap

Om du vill minska fragmenteringen av en heap skapar du ett klustrat index i tabellen och släpper sedan indexet. Detta omdistribuerar data medan det klustrade indexet skapas. Detta gör det också så optimalt som möjligt med tanke på fördelningen av ledigt utrymme som är tillgängligt i databasen. När det klustrade indexet sedan tas bort för att återskapa heapen flyttas inte data och förblir optimalt på plats. Information om hur du utför dessa åtgärder finns i CREATE INDEX and DROP INDEX.

Försiktighet

När du skapar och släpper ett grupperat index i en tabell återskapas alla icke-grupperade index i tabellen två gånger.

Komprimera stora objektdata

Som standard komprimerar ALTER INDEX REORGANIZE-instruktionen sidor som innehåller stora objektdata (LOB). Eftersom LOB-sidor inte frigörs när de är tomma kan komprimering av dessa data förbättra diskutrymmet om mycket LOB-data tas bort eller om en LOB-kolumn tas bort.

Om du omorganiserar ett angivet grupperat index komprimeras alla LOB-kolumner som finns i det klustrade indexet. Om du omorganiserar ett icke-grupperat index komprimeras alla LOB-kolumner som inte är nyckelkolumner (ingår) i indexet. När ALL anges i -instruktionen omorganiseras alla index som är associerade med den angivna tabellen eller vyn. Dessutom komprimeras alla LOB-kolumner som är associerade med klustrat index, underliggande tabell eller icke-grupperat index med inkluderade kolumner.

Utvärdera diskutrymmesanvändning

Kolumnen avg_page_space_used_in_percent anger sidfullhet. För att uppnå optimal diskutrymmesanvändning bör det här värdet vara nära 100 procent för ett index som inte har många slumpmässiga infogningar. Ett index som har många slumpmässiga infogningar och har mycket fullständiga sidor har dock ett ökat antal siddelningar. Detta orsakar mer fragmentering. För att minska siddelningar bör därför värdet vara mindre än 100 procent. Om du återskapar ett index med det FILLFACTOR angivna alternativet kan sidfullheten ändras så att den passar frågemönstret i indexet. Mer information om fyllningsfaktor finns i Ange fyllningsfaktor för ett index. Dessutom komprimerar ALTER INDEX REORGANIZE ett index genom att försöka fylla sidor till den FILLFACTOR som senast angavs. Detta ökar värdet i avg_space_used_in_percent. ALTER INDEX REORGANIZE kan inte minska sidfullheten. I stället måste en indexrekonstruktion utföras.

Utvärdera indexfragment

Ett fragment består av fysiskt efterföljande lövsidor i samma fil för en allokeringsenhet. Ett index har minst ett fragment. De maximala fragment som ett index kan ha är lika med antalet sidor i indexets lövnivå. Större fragment innebär att mindre disk-I/O krävs för att läsa samma antal sidor. Ju större avg_fragment_size_in_pages värde desto bättre prestanda för intervallgenomsökning. Värdena avg_fragment_size_in_pages och avg_fragmentation_in_percent är omvänt proportionella mot varandra. Därför bör återskapande eller omorganisering av ett index minska mängden fragmentering och öka fragmentstorleken.

Begränsningar

Returnerar inte data för grupperade kolumnlagringsindex.

Behörigheter

Kräver följande behörigheter:

  • CONTROL behörighet för det angivna objektet i databasen.

  • VIEW DATABASE STATE eller VIEW DATABASE PERFORMANCE STATE (SQL Server 2022) behörighet att returnera information om alla objekt i den angivna databasen med hjälp av objektets jokertecken @object_id = NULL.

  • VIEW SERVER STATE eller VIEW SERVER PERFORMANCE STATE (SQL Server 2022) behörighet att returnera information om alla databaser med hjälp av databasens jokertecken @database_id = NULL.

Om du beviljar VIEW DATABASE STATE kan alla objekt i databasen returneras, oavsett vilka CONTROL behörigheter som nekas för specifika objekt.

Om du nekar VIEW DATABASE STATE tillåts inte att alla objekt i databasen returneras, oavsett vilka CONTROL behörigheter som beviljas för specifika objekt. När databasens jokertecken @database_id = NULL anges utelämnas databasen.

Mer information finns i Dynamiska hanteringsvyer för system.

Exempel

I Transact-SQL kodexempel i den här artikeln används AdventureWorks2022- eller AdventureWorksDW2022-exempeldatabasen, som du kan ladda ned från Microsoft SQL Server-exempel och Community Projects startsida.

A. Returnera information om en angiven tabell

I följande exempel returneras storleks- och fragmenteringsstatistik för alla index och partitioner i tabellen Person.Address. Genomsökningsläget är inställt på LIMITED för bästa prestanda och för att begränsa den statistik som returneras. För att köra den här frågan krävs minst CONTROL behörighet i tabellen Person.Address.

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;

SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.Person.Address');

IF @db_id IS NULL
BEGIN;
    PRINT N'Invalid database';
END;
ELSE IF @object_id IS NULL
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, NULL, NULL , 'LIMITED');
END;
GO

B. Returnera information om en heap

I följande exempel returneras all statistik för heap-dbo.DatabaseLog i AdventureWorks2022-databasen. Eftersom tabellen innehåller LOB-data returneras en rad för LOB_DATA allokeringsenhet utöver raden som returneras för IN_ROW_ALLOCATION_UNIT som lagrar datasidorna i heapen. För att köra den här frågan krävs minst CONTROL behörighet i tabellen dbo.DatabaseLog.

DECLARE @db_id SMALLINT;
DECLARE @object_id INT;
SET @db_id = DB_ID(N'AdventureWorks2022');
SET @object_id = OBJECT_ID(N'AdventureWorks2022.dbo.DatabaseLog');
IF @object_id IS NULL
BEGIN;
    PRINT N'Invalid object';
END;
ELSE
BEGIN;
    SELECT * FROM sys.dm_db_index_physical_stats(@db_id, @object_id, 0, NULL , 'DETAILED');
END;
GO

C. Returnera information för alla databaser

I följande exempel returneras all statistik för alla tabeller och index i SQL Server-instansen genom att ange jokertecknet NULL för alla parametrar. För att köra den här frågan krävs behörigheten VIEW SERVER STATE.

SELECT * FROM sys.dm_db_index_physical_stats (NULL, NULL, NULL, NULL, NULL);
GO

D. Använd sys.dm_db_index_physical_stats i ett skript för att återskapa eller omorganisera index

I följande exempel omorganiseras eller återskapas automatiskt alla partitioner i en databas som har en genomsnittlig fragmentering över 10 procent. För att köra den här frågan krävs behörigheten VIEW DATABASE STATE. Det här exemplet anger DB_ID som den första parametern utan att ange ett databasnamn.

-- Ensure a USE <databasename> statement has been executed first.
SET NOCOUNT ON;

DECLARE @objectid INT;
DECLARE @indexid INT;
DECLARE @partitioncount BIGINT;
DECLARE @schemaname NVARCHAR(130);
DECLARE @objectname NVARCHAR(130);
DECLARE @indexname NVARCHAR(130);
DECLARE @partitionnum BIGINT;
DECLARE @partitions BIGINT;
DECLARE @frag FLOAT;
DECLARE @command NVARCHAR(4000);

-- Conditionally select tables and indexes from the sys.dm_db_index_physical_stats function
-- and convert object and index IDs to names.
SELECT object_id AS objectid,
    index_id AS indexid,
    partition_number AS partitionnum,
    avg_fragmentation_in_percent AS frag
INTO #work_to_do
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
WHERE avg_fragmentation_in_percent > 10.0
    AND index_id > 0;

-- Declare the cursor for the list of partitions to be processed.
DECLARE partitions CURSOR
FOR
SELECT *
FROM #work_to_do;

-- Open the cursor.
OPEN partitions;

-- Loop through the partitions.
WHILE (1 = 1)
BEGIN;

    FETCH NEXT
    FROM partitions
    INTO @objectid,
        @indexid,
        @partitionnum,
        @frag;

    IF @@FETCH_STATUS < 0
        BREAK;

    SELECT @objectname = QUOTENAME(o.name),
        @schemaname = QUOTENAME(s.name)
    FROM sys.objects AS o
    INNER JOIN sys.schemas AS s
        ON s.schema_id = o.schema_id
    WHERE o.object_id = @objectid;

    SELECT @indexname = QUOTENAME(name)
    FROM sys.indexes
    WHERE object_id = @objectid
        AND index_id = @indexid;

    SELECT @partitioncount = count(*)
    FROM sys.partitions
    WHERE object_id = @objectid
        AND index_id = @indexid;

    -- 30 is an arbitrary decision point at which to switch between reorganizing and rebuilding.
    IF @frag < 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REORGANIZE';

    IF @frag >= 30.0
        SET @command = N'ALTER INDEX ' + @indexname + N' ON ' + @schemaname + N'.' + @objectname + N' REBUILD';

    IF @partitioncount > 1
        SET @command = @command + N' PARTITION=' + CAST(@partitionnum AS NVARCHAR(10));

    EXEC (@command);

    PRINT N'Executed: ' + @command;
END;

-- Close and deallocate the cursor.
CLOSE partitions;

DEALLOCATE partitions;

-- Drop the temporary table.
DROP TABLE #work_to_do;
GO

E. Använd sys.dm_db_index_physical_stats för att visa antalet sidkomprimerade sidor

I följande exempel visas hur du visar och jämför det totala antalet sidor med de sidor som är rad- och sidkomprimerade. Den här informationen kan användas för att fastställa den fördel som komprimering ger för ett index eller en tabell.

SELECT o.name,
    ips.partition_number,
    ips.index_type_desc,
    ips.record_count,
    ips.avg_record_size_in_bytes,
    ips.min_record_size_in_bytes,
    ips.max_record_size_in_bytes,
    ips.page_count,
    ips.compressed_page_count
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'DETAILED') ips
INNER JOIN sys.objects o
    ON o.object_id = ips.object_id
ORDER BY record_count DESC;

F. Använda sys.dm_db_index_physical_stats i SAMPLED-läge

I följande exempel visas hur SAMPLED-läget returnerar en ungefärlig som skiljer sig från resultatet för DETAILED läge.

CREATE TABLE t3 (
    col1 INT PRIMARY KEY,
    col2 VARCHAR(500)
    )
    WITH (DATA_COMPRESSION = PAGE);
GO

BEGIN TRANSACTION

DECLARE @idx INT = 0;

WHILE @idx < 1000000
BEGIN
    INSERT INTO t3 (col1, col2)
    VALUES (
        @idx,
        REPLICATE('a', 100) + CAST(@idx AS VARCHAR(10)) + REPLICATE('a', 380)
        )

    SET @idx = @idx + 1
END

COMMIT;
GO

SELECT page_count,
    compressed_page_count,
    forwarded_record_count,
    *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'SAMPLED');

SELECT page_count,
    compressed_page_count,
    forwarded_record_count,
    *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('t3'), NULL, NULL, 'DETAILED');

G. Fråga service broker-köer för indexfragmentering

gäller för: SQL Server 2016 (13.x) och senare versioner

I följande exempel visas hur du frågar serverköer om fragmentering.

--Using queue internal table name
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('sys.queue_messages_549576996'), DEFAULT, DEFAULT, DEFAULT);

--Using queue name directly
SELECT *
FROM sys.dm_db_index_physical_stats(db_id(), object_id('ExpenseQueue'), DEFAULT, DEFAULT, DEFAULT);