Académique Documents
Professionnel Documents
Culture Documents
Returns size and fragmentation information for the data and indexes of the specified table or view in SQL Server. For an
index, one row is returned for each level of the B-tree in each partition. For a heap, one row is returned for the IN_ROW_DATA
allocation unit of each partition. For large object (LOB) data, one row is returned for the LOB_DATA allocation unit of each
partition. If row-overflow data exists in the table, one row is returned for the ROW_OVERFLOW_DATA allocation unit in each
partition. Does not return information about xVelocity memory optimized columnstore indexes.
Important
If you query sys.dm_db_index_physical_stats on a server instance that is hosting an AlwaysOn readable secondary
replica, you might encounter a REDO blocking issue. This is because this dynamic management view acquires an IS lock on
the specified user table or view that can block requests by a REDO thread for an X lock on that user table or view.
sys.dm_db_index_physical_stats does not return information about memory-optimized indexes. For information about
memory-optimized index use, see sys.dm_db_xtp_index_stats (Transact-SQL).
Applies to: SQL Server (SQL Server 2008 through current version), Azure SQL Database.
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}
)
database_id | NULL | 0 | DEFAULT
Is the ID of the database. database_id is smallint. Valid inputs are the ID number of a database, NULL, 0, or
DEFAULT. The default is 0. NULL, 0, and DEFAULT are equivalent values in this context.
Specify NULL to return information for all databases in the instance of SQL Server. If you specify NULL for
database_id, you must also specify NULL for object_id, index_id, and partition_number.
The built-in function DB_ID can be specified. When using DB_ID without specifying a database name, the
compatibility level of the current database must be 90 or greater.
Valid inputs are the ID number of a table and view, NULL, 0, or DEFAULT. The default is 0. NULL, 0, and DEFAULT are
equivalent values in this context. As of SQL Server 2016 Community Technology Preview 3.2 (CTP 3.2), valid inputs
also include the service broker queue name or the queue internal table name. When default parameters are applied
(i.e. all objects, all indexes, etc), fragmentation information for all queues are included in the result set.
Specify NULL to return information for all tables and views in the specified database. If you specify NULL for
object_id, you must also specify NULL for index_id and partition_number.
Specify NULL to return information for all indexes for a base table or view. If you specify NULL for index_id, you
must also specify NULL for partition_number.
Specify NULL to return information for all partitions of the owning object.
0 = Heap.
partition_number int 1-based partition number within the owning object; a table,
view, or index.
HEAP
CLUSTERED INDEX
NONCLUSTERED INDEX
SPATIAL INDEX
XML INDEX
IN_ROW_DATA
LOB_DATA
ROW_OVERFLOW_DATA
avg_fragment_size_in_pages float Average number of pages in one fragment in the leaf level of
an IN_ROW_DATA allocation unit.
avg_page_space_used_in_percent float Average percentage of available data storage space used in all
pages.
Note
ghost_record_count bigint Number of ghost records ready for removal by the ghost
cleanup task in the allocation unit.
hobt_id bigint
NULL if
column_store_delete_buffer_state tinyint
0 = NOT_APPLICABLE
1 = OPEN
2 = DRAINING
3 = FLUSHING
4 = RETIRING
5 = READY
column_store_delete_buff_state_desc
DRAINING deleters are draining out but scanners still use it.
The sys.dm_db_index_physical_stats dynamic management function replaces the DBCC SHOWCONTIG statement.
Scanning Modes
The mode in which the function is executed determines the level of scanning performed to obtain the statistical data
that is used by the function. mode is specified as LIMITED, SAMPLED, or DETAILED. The function traverses the page
chains for the allocation units that make up the specified partitions of the table or index. sys.dm_db_index_physical_stats
requires only an Intent-Shared (IS) table lock, regardless of the mode that it runs in.
The LIMITED mode is the fastest mode and scans the smallest number of pages. For an index, only the parent-level
pages of the B-tree (that is, the pages above the leaf level) are scanned. For a heap, the associated PFS and IAM pages
are examined and the data pages of a heap are scanned in LIMITED mode.
With LIMITED mode, compressed_page_count is NULL because the Database Engine only scans non-leaf pages of the
B-tree and the IAM and PFS pages of the heap. Use SAMPLED mode to get an estimated value for
compressed_page_count, and use DETAILED mode to get the actual value for compressed_page_count. The SAMPLED
mode returns statistics based on a 1 percent sample of all the pages in the index or heap. Results in SAMPLED mode
should be regarded as approximate. If the index or heap has fewer than 10,000 pages, DETAILED mode is used instead
of SAMPLED.
The DETAILED mode scans all pages and returns all statistics.
The modes are progressively slower from LIMITED to DETAILED, because more work is performed in each mode. To
quickly gauge the size or fragmentation level of a table or index, use the LIMITED mode. It is the fastest and will not
return a row for each nonleaf level in the IN_ROW_DATA allocation unit of the index.
Using System Functions to Specify Parameter Values
You can use the Transact-SQL functions DB_ID and OBJECT_ID to specify a value for the database_id and object_id
parameters. However, passing values that are not valid to these functions may cause unintended results. For example, if
the database or object name cannot be found because they do not exist or are spelled incorrectly, both functions will
return NULL. The sys.dm_db_index_physical_stats function interprets NULL as a wildcard value specifying all databases or
all objects.
Additionally, the OBJECT_ID function is processed before the sys.dm_db_index_physical_stats function is called and is
therefore evaluated in the context of the current database, not the database specified in database_id. This behavior may
cause the OBJECT_ID function to return a NULL value; or, if the object name exists in both the current database context
and the specified database, an error message may be returned. The following examples demonstrate these unintended
results.
USEmaster;
GO
Inthisexample,OBJECT_IDisevaluatedinthecontextofthemasterdatabase.
BecausePerson.Addressdoesnotexistinmaster,thefunctionreturnsNULL.
WhenNULLisspecifiedasanobject_id,allobjectsinthedatabasearereturned.
Thesameresultsarereturnedwhenanobjectthatisnotvalidisspecified.
SELECT*FROMsys.dm_db_index_physical_stats
(DB_ID(N'AdventureWorks'),OBJECT_ID(N'Person.Address'),NULL,NULL,'DETAILED');
GO
Thisexampledemonstratestheresultsofspecifyingavalidobjectname
thatexistsinboththecurrentdatabasecontextand
inthedatabasespecifiedinthedatabase_idparameterofthe
sys.dm_db_index_physical_statsfunction.
AnerrorisreturnedbecausetheIDvaluereturnedbyOBJECT_IDdoesnot
matchtheIDvalueoftheobjectinthespecifieddatabase.
CREATEDATABASETest;
GO
USETest;
GO
CREATESCHEMAPerson;
GO
CREATETablePerson.Address(c1int);
GO
USEAdventureWorks2012;
GO
SELECT*FROMsys.dm_db_index_physical_stats
(DB_ID(N'Test'),OBJECT_ID(N'Person.Address'),NULL,NULL,'DETAILED');
GO
Cleanuptemporarydatabase.
DROPDATABASETest;
GO
Best Practice
Always make sure that a valid ID is returned when you use DB_ID or OBJECT_ID. For example, when you use
OBJECT_ID, specify a three-part name such as OBJECT_ID(N'AdventureWorks2012.Person.Address'), or test the
value returned by the functions before you use them in the sys.dm_db_index_physical_stats function. Examples A and
B that follow demonstrate a safe way to specify database and object IDs.
Detecting Fragmentation
Fragmentation occurs through the process of data modifications (INSERT, UPDATE, and DELETE statements) that are
made against the table and, therefore, to the indexes defined on the table. Because these modifications are not
ordinarily distributed equally among the rows of the table and indexes, the fullness of each page can vary over time. For
queries that scan part or all of the indexes of a table, this kind of fragmentation can cause additional page reads. This
hinders parallel scanning of data.
The fragmentation level of an index or heap is shown in the avg_fragmentation_in_percent column. For heaps, the value
represents the extent fragmentation of the heap. For indexes, the value represents the logical fragmentation of the
index. Unlike DBCC SHOWCONTIG, the fragmentation calculation algorithms in both cases consider storage that spans
multiple files and, therefore, are accurate.
Logical Fragmentation
This is the percentage of out-of-order pages in the leaf pages of an index. An out-of-order page is a page for which the
next physical page allocated to the index is not the page pointed to by the next-page pointer in the current leaf page.
Extent Fragmentation
This is the percentage of out-of-order extents in the leaf pages of a heap. An out-of-order extent is one for which the
extent that contains the current page for a heap is not physically the next extent after the extent that contains the
previous page.
The value for avg_fragmentation_in_percent should be as close to zero as possible for maximum performance. However,
values from 0 percent through 10 percent may be acceptable. All methods of reducing fragmentation, such as
rebuilding, reorganizing, or re-creating, can be used to reduce these values. For more information about how to analyze
the degree of fragmentation in an index, see Reorganize and Rebuild Indexes.
Re-creating a clustered index redistributes the data and results in full data pages. The level of fullness can be
configured by using the FILLFACTOR option in CREATE INDEX. The drawbacks in this method are that the index is
offline during the drop and re-create cycle, and that the operation is atomic. If the index creation is interrupted,
the index is not re-created. For more information, see CREATE INDEX (Transact-SQL).
Use ALTER INDEX REORGANIZE, the replacement for DBCC INDEXDEFRAG, to reorder the leaf level pages of the
index in a logical order. Because this is an online operation, the index is available while the statement is running.
The operation can also be interrupted without losing work already completed. The drawback in this method is
that it does not do as good a job of reorganizing the data as an index rebuild operation, and it does not update
statistics.
Use ALTER INDEX REBUILD, the replacement for DBCC DBREINDEX, to rebuild the index online or offline. For
more information, see ALTER INDEX (Transact-SQL).
Fragmentation alone is not a sufficient reason to reorganize or rebuild an index. The main effect of fragmentation is that
it slows down page read-ahead throughput during index scans. This causes slower response times. If the query workload
on a fragmented table or index does not involve scans, because the workload is primarily singleton lookups, removing
fragmentation may have no effect. For more information, see this Microsoft Web site.
Note
Running DBCC SHRINKFILE or DBCC SHRINKDATABASE may introduce fragmentation if an index is partly or
completely moved during the shrink operation. Therefore, if a shrink operation must be performed, you should do it
before fragmentation is removed.
Caution
Creating and dropping a clustered index on a table, rebuilds all non-clustered indexes on that table twice.
Reorganizing a specified clustered index compacts all LOB columns that are contained in the clustered index.
Reorganizing a nonclustered index compacts all LOB columns that are nonkey (included) columns in the index. When
ALL is specified in the statement, all indexes that are associated with the specified table or view are reorganized.
Additionally, all LOB columns that are associated with the clustered index, underlying table, or nonclustered index with
included columns are compacted.
VIEW DATABASE STATE permission to return information about all objects within the specified database, by using
the object wildcard @object_id=NULL.
VIEW SERVER STATE permission to return information about all databases, by using the database wildcard
@database_id = NULL.
Granting VIEW DATABASE STATE allows all objects in the database to be returned, regardless of any CONTROL permissions
denied on specific objects.
Denying VIEW DATABASE STATE disallows all objects in the database to be returned, regardless of any CONTROL
permissions granted on specific objects. Also, when the database wildcard @database_id=NULL is specified, the database is
omitted.
For more information, see Dynamic Management Views and Functions (Transact-SQL).
A. Returning information about a specified table
The following example returns size and fragmentation statistics for all indexes and partitions of the Person.Address
table. The scan mode is set to 'LIMITED' for best performance and to limit the statistics that are returned. Executing
this query requires, at a minimum, CONTROL permission on the Person.Address table.
DECLARE@db_idSMALLINT;
DECLARE@object_idINT;
SET@db_id=DB_ID(N'AdventureWorks2012');
SET@object_id=OBJECT_ID(N'AdventureWorks2012.Person.Address');
IF@db_idISNULL
BEGIN;
PRINTN'Invaliddatabase';
END;
ELSEIF@object_idISNULL
BEGIN;
PRINTN'Invalidobject';
END;
ELSE
BEGIN;
SELECT*FROMsys.dm_db_index_physical_stats(@db_id,@object_id,NULL,NULL,'LIMITED
END;
GO
DECLARE@db_idSMALLINT;
DECLARE@object_idINT;
SET@db_id=DB_ID(N'AdventureWorks2012');
SET@object_id=OBJECT_ID(N'AdventureWorks2012.dbo.DatabaseLog');
IF@object_idISNULL
BEGIN;
PRINTN'Invalidobject';
END;
ELSE
BEGIN;
SELECT*FROMsys.dm_db_index_physical_stats(@db_id,@object_id,0,NULL,'DETAILED')
END;
GO
SELECT*FROMsys.dm_db_index_physical_stats(NULL,NULL,NULL,NULL,NULL);
GO
EnsureaUSE<databasename>statementhasbeenexecutedfirst.
SETNOCOUNTON;
DECLARE@objectidint;
DECLARE@indexidint;
DECLARE@partitioncountbigint;
DECLARE@schemanamenvarchar(130);
DECLARE@objectnamenvarchar(130);
DECLARE@indexnamenvarchar(130);
DECLARE@partitionnumbigint;
DECLARE@partitionsbigint;
DECLARE@fragfloat;
DECLARE@commandnvarchar(4000);
Conditionallyselecttablesandindexesfromthesys.dm_db_index_physical_statsfunctio
andconvertobjectandindexIDstonames.
SELECT
object_idASobjectid,
index_idASindexid,
partition_numberASpartitionnum,
avg_fragmentation_in_percentASfrag
INTO#work_to_do
FROMsys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'LIMITED')
WHEREavg_fragmentation_in_percent>10.0ANDindex_id>0;
Declarethecursorforthelistofpartitionstobeprocessed.
DECLAREpartitionsCURSORFORSELECT*FROM#work_to_do;
Openthecursor.
OPENpartitions;
Loopthroughthepartitions.
WHILE(1=1)
BEGIN;
FETCHNEXT
FROMpartitions
INTO@objectid,@indexid,@partitionnum,@frag;
IF@@FETCH_STATUS<0BREAK;
SELECT@objectname=QUOTENAME(o.name),@schemaname=QUOTENAME(s.name)
FROMsys.objectsASo
JOINsys.schemasassONs.schema_id=o.schema_id
WHEREo.object_id=@objectid;
SELECT@indexname=QUOTENAME(name)
FROMsys.indexes
WHEREobject_id=@objectidANDindex_id=@indexid;
SELECT@partitioncount=count(*)
FROMsys.partitions
WHEREobject_id=@objectidANDindex_id=@indexid;
30isanarbitrarydecisionpointatwhichtoswitchbetweenreorganizingandrebuildin
IF@frag<30.0
SET@command=N'ALTERINDEX'+@indexname+N'ON'+@schemaname+N'.'+@
IF@frag>=30.0
SET@command=N'ALTERINDEX'+@indexname+N'ON'+@schemaname+N'.'+@
IF@partitioncount>1
SET@command=@command+N'PARTITION='+CAST(@partitionnumASnvarchar(10))
EXEC(@command);
PRINTN'Executed:'+@command;
END;
Closeanddeallocatethecursor.
CLOSEpartitions;
DEALLOCATEpartitions;
Dropthetemporarytable.
DROPTABLE#work_to_do;
GO
CREATETABLEt3(col1intPRIMARYKEY,col2varchar(500))WITH(DATA_COMPRESSION=PAGE);
GO
BEGINTRAN
DECLARE@idxint=0;
WHILE@idx<1000000
BEGIN
INSERTINTOt3(col1,col2)
VALUES(@idx,
REPLICATE('a',100)+CAST(@idxasvarchar(10))+REPLICATE('a',380))
SET@idx=@idx+1
END
COMMIT;
GO
SELECTpage_count,compressed_page_count,forwarded_record_count,*
FROMsys.dm_db_index_physical_stats(db_id(),
object_id('t3'),null,null,'SAMPLED');
SELECTpage_count,compressed_page_count,forwarded_record_count,*
FROMsys.dm_db_index_physical_stats(db_id(),
object_id('t3'),null,null,'DETAILED');
Applies to: SQL Server 2016 Community Technology Preview 3.2 (CTP 3.2) through SQL Server.
The following examples shows how to query server broker queues for fragmentation.
Usingqueueinternaltablename
select*fromsys.dm_db_index_physical_stats(db_id(),object_id('sys.queue_messages_5495
Usingqueuenamedirectly
select*fromsys.dm_db_index_physical_stats(db_id(),object_id('ExpenseQueue'),default
Community Additions
2016 Microsoft