Published on

July 20, 2015

Исследование расчета размера таблицы в SQL Server

SQL Server – мощная технология, которая предлагает много сложностей. Иногда, чтобы понять внутреннее устройство SQL Server, нужно погрузиться в его внутренности. Недавно я оказался в кроличьей норе, пытаясь разобраться, как по умолчанию рассчитывается размер таблицы. В своих предыдущих статьях я давал информацию о нахождении размера таблицы, но обнаружил, что некоторая информация была неверной. Это побудило меня на поиск истины.

Одним из распространенных методов расчета размера таблицы является использование хранимой процедуры sp_spaceused. За годы были внесены изменения в эту хранимую процедуру, и каждое обновление ссылается на системную таблицу sys.internal_tables, чтобы исключить определенные внутренние типы из расчетов. Я хотел знать, какие именно внутренние типы были исключены, но мой поиск в документации и онлайн-ресурсах дал неполную информацию.

Итак, что же я сделал? Я обратился к группе экспертов и попросил их помощи. Несмотря на их помощь, я так и не смог найти полный список внутренних типов, исключенных sp_spaceused. Это заставило меня провести собственные тесты. Я экспериментировал с различными функциями и настройками, пока наконец не составил полный список внутренних типов таблиц, исключенных sp_spaceused.

Теперь вы можете задаться вопросом, почему я столько старался. Ну, это не только для моего собственного удовольствия. У меня скоро будет обновление для скрипта пространства таблицы, и я хотел предоставить точную информацию, а не полагаться на объяснение “потому что так написано в документации”. Это исследование уголков и закоулков движка базы данных было необходимо для обеспечения точности скрипта.

Для тех, кто заинтересован, вот фрагмент скрипта, который я использовал для определения внутренних типов таблиц:


DECLARE @ServerMajorVersion DECIMAL(4, 2)
SELECT @ServerMajorVersion = CONVERT(DECIMAL(4, 2), PARSENAME(dt.fqn, 4) + '.' + PARSENAME(dt.fqn, 3))
FROM ( SELECT CONVERT(VARCHAR(20), SERVERPROPERTY('ProductVersion'))) dt ( fqn );

IF OBJECT_ID('tempdb.dbo.#InternalTables') IS NOT NULL
BEGIN
    DROP TABLE #InternalTables;
END

CREATE TABLE #InternalTables
(
    [internal_type] [TINYINT] NULL INDEX CI_InternalType CLUSTERED,
    [internal_type_desc] [VARCHAR](60) NULL,
    [DBSource] [VARCHAR](16) NULL
)
ON [PRIMARY];

INSERT INTO #InternalTables
( [internal_type], [internal_type_desc], [DBSource] )
VALUES
( 201, N'QUEUE_MESSAGES', N'системная база данных' ),
( 202, N'XML_INDEX_NODES', N'пользовательская база данных' ),
( 203, N'FULLTEXT_CATALOG_FREELIST', N'Пользовательская база данных' ),
( 204, N'FULLTEXT_CATALOG_MAP (BOL)/FULLTEXT_INDEX_MAP (REALITY)', N'Пользовательская база данных' ),
( 205, N'QUERY_NOTIFICATION', N'Пользовательская база данных' ),
( 206, N'SERVICE_BROKER_MAP', N'системная база данных' ),
( 207, N'EXTENDED_INDEXES', N'пользовательская база данных' ),
( 208, N'FILESTREAM_TOMBSTONE', N'системная база данных' ),
( 209, N'CHANGE_TRACKING', N'Пользовательская база данных' ),
( 210, N'TRACKED_COMMITTED_TRANSACTIONS', N'системная база данных' ),
( 211, N'FULLTEXT_AVDL', N'пользовательская база данных' ),
( 212, N'FULLTEXT_COMP_FRAGMENT', N'пользовательская база данных' ),
( 213, N'FULLTEXT_DOCID_STATUS', N'пользовательская база данных' ),
( 214, N'FULLTEXT_INDEXED_DOCID', N'пользовательская база данных' ),
( 215, N'FULLTEXT_DOCID_FILTER', N'пользовательская база данных' ),
( 216, N'FULLTEXT_DOCID_MAP', N'пользовательская база данных' ),
( 217, N'FULLTEXT_THESAURUS_METADATA_TABLE', N'системная база данных' ),
( 218, N'FULLTEXT_THESAURUS_STATE_TABLE', N'системная база данных' ),
( 219, N'FULLTEXT_THESAURUS_PHRASE_TABLE', N'системная база данных' ),
( 220, N'CONTAINED_FEATURES', N'системная база данных' ),
( 221, N'SEMPLAT_DOCUMENT_INDEX_TABLE', N'пользовательская база данных' ),
( 222, N'SEMPLAT_TAG_INDEX_TABLE', N'пользовательская база данных' ),
( 223, N'SEMPLAT_MODEL_MAPPING_TABLE', N'системная база данных' ),
( 224, N'SEMPLAT_LANGUAGE_MODEL_TABLE', N'системная база данных' ),
( 225, N'FILETABLE_UPDATES', N'системная база данных' ),
( 236, N'SELECTIVE_XML_INDEX_NODE_TABLE', N'пользовательская база данных' ),
( 240, N'QUERY_DISK_STORE_QUERY_TEXT', N'системная база данных' ),
( 241, N'QUERY_DISK_STORE_QUERY', N'системная база данных' ),
( 242, N'QUERY_DISK_STORE_PLAN', N'системная база данных' ),
( 243, N'QUERY_DISK_STORE_RUNTIME_STATS', N'системная база данных' ),
( 244, N'QUERY_DISK_STORE_RUNTIME_STATS_INTERVAL', N'системная база данных' ),
( 245, N'QUERY_CONTEXT_SETTINGS', N'системная база данных' );

IF OBJECT_ID('tempdb.dbo.#SpaceVersions') IS NOT NULL
BEGIN
    DROP TABLE #SpaceVersions;
END

CREATE TABLE #SpaceVersions
(
    Product VARCHAR(32),
    ServerMajorVersion DECIMAL(4, 2) INDEX CI_ServerMajorVer CLUSTERED,
    TypesList VARCHAR(256)
);

INSERT INTO #SpaceVersions
( Product, ServerMajorVersion, TypesList )
VALUES
( 'SQL Server 2005', 9.00 , '202,204' ),
( 'SQL Server 2008', 10.00 , '202,204,211,212,213,214,215,216' ),
( 'SQL Server 2008R2', 10.50 , '202,204,211,212,213,214,215,216' ),
( 'SQL Server 2012', 11.00 , '202,204,207,211,212,213,214,215,216,221,222,236' ),
( 'SQL Server 2014', 12.00 , '202,204,207,211,212,213,214,215,216,221,222,236' ),
( 'SQL Server 2016', 13.00 , '202,204,207,211,212,213,214,215,216,221,222,236' );

SELECT sv.Product, myit.internal_type, myit.internal_type_desc
FROM #SpaceVersions sv 
CROSS APPLY AdminDB.dbo.stringsplitter(sv.Types
Click to rate this post!
[Total: 0 Average: 0]

Let's work together

Send us a message or book free introductory meeting with us using button below.