Get Average Data/Index Row Size

Applicability:

SQL Server 2000: Not Supported

SQL Server 2005: Tested

SQL Server 2008: Tested

SQL Server 2008R2: Tested

SQL Server 2012: Not Tested

Credits:

Author: Unknown/ChillyDBA

Date: 24 Dec 2010/26 Jun 2012

Description

Retrieves the average row size for all data and indexes on one or all tables in a database.

The code is reasonably well commented, but please note that there may be one or many rows returned for each table/index combination. From SQL BOL:

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.

Code

Function:

DROP FUNCTION dbo.udf_GetAverageRowSize

Go

CREATE FUNCTION dbo.udf_GetAverageRowSize (@TableName SYSNAME)

RETURNS @AverageRowSize TABLE

(

DatabaseName SYSNAME,

TableName SYSNAME,

IndexName SYSNAME NULL,

IndexID INT NULL,

IndexTypeDesc VARCHAR(50) NULL,

AllocUnitTypeDesc VARCHAR(50) NULL,

MinRecordSizeInBytes INT NULL,

MaxRecordSizeInBytes INT NULL,

AvgRecordSizeInBytes DECIMAL(18,2) NULL

)

AS

/***************************************************************

Purpose: To retrieve row size statistics from the DMV

SYS.DM_DB_INDEX_PHYSICAL_STATS for one or all

tables in a DB

From SQl BOL

"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."

Author: Unknown/ChillyDBA

History: 24 Dec 2010 - Initial Issue

26 Jun 2012 - ChillyDBA - Converted to a table valued function

with optional table name parameter

****************************************************************/

BEGIN

INSERT @AverageRowSize

(

DatabaseName,

TableName,

IndexName,

IndexID,

IndexTypeDesc,

AllocUnitTypeDesc,

MinRecordSizeInBytes,

MaxRecordSizeInBytes,

AvgRecordSizeInBytes

)

SELECT

CAST(DB_NAME() AS VARCHAR(20)) AS 'DatabaseName',

CAST(OBJECT_NAME(ips.object_id) AS VARCHAR(20)) AS 'TableName',

si.name AS 'IndexName',

ips.index_id AS 'IndexID',

ips.index_type_desc AS 'IndexTypeDesc',

ips.alloc_unit_type_desc AS 'AllocUnitTypeDesc',

ips.min_record_size_in_bytes AS 'MinRecordSizeInBytes',

ips.max_record_size_in_bytes AS 'MaxRecordSizeInBytes',

ips.avg_record_size_in_bytes AS 'AvgRecordSizeInBytes'

FROM SYS.DM_DB_INDEX_PHYSICAL_STATS(DB_ID(),NULL,NULL,NULL,'DETAILED') ips

INNER JOIN sys.indexes si

ON ips.object_id = si.object_ID

AND ips.index_id = si.index_id

WHERE ips.object_id = ISNULL(OBJECT_ID(@TableName), ips.object_id)

ORDER BY

OBJECT_NAME(ips.object_id),

ips.index_id,

ips.avg_record_size_in_bytes DESC

RETURN

END

GO

Test Code:

USE Adventureworks

GO

SELECT * FROM dbo.udf_GetAverageRowSize(NULL)

SELECT * FROM dbo.udf_GetAverageRowSize('DimCustomer')