Подтвердить что ты не робот

SQL Server: размер записи больше, чем ожидалось

Моя таблица состоит из 3 столбцов

| Column Name | Data Type | Size
| Value       | real      | 4
| LogId       | int       | 4
| SigId       | smallint  | 2

Для столбцов LogId, SigId устанавливается один первичный ключ.

Сумма всего размера 4+4+2=10, однако, используя sys.dm_db_index_physical_stats, я получаю, что средний (и min/max) размер записи в байтах равен 25. Может ли кто-нибудь объяснить? Я сравниваю яблоки и апельсины?

4b9b3361

Ответ 1

Длина физической записи включает служебные данные строки в дополнение к пространству, необходимому для фактических значений столбца. В моем экземпляре SQL Server я получаю среднюю длину записи 17, указанную в следующей таблице:

CREATE TABLE dbo.Example1(
      Value real NOT NULL
    , LogId int NOT NULL
    , SigId smallint NOT NULL
    , CONSTRAINT PK_Example1 PRIMARY KEY CLUSTERED(LogId, SigId)
);
GO
INSERT INTO dbo.Example1 (Value, LogId, SigId) VALUES(1, 2, 3);
GO
SELECT avg_record_size_in_bytes
FROM sys.dm_db_index_physical_stats(DB_ID(), OBJECT_ID(N'dbo.Example1'),1,0,'DETAILED')
WHERE index_level = 0;
GO

Длина записи длиной в 17 байт, сообщенная sys.dm_db_index_physical_stats, включает 10 байтов для данных, 4 байта для заголовка записи, 2 байта для подсчета столбцов и 1 байт для растрового изображения NULL. См. Пол Рэндал Анатомия записи статьи для подробной информации о структуре записи.

Ниже приведена script, чтобы сбрасывать первую страницу данных кластерных индексов с использованием DBCC_PAGE, как определено недокументированным (не использовать его в процессе производства) sys.dm_db_database_page_allocations табличная функция:

DECLARE
      @database_id int = DB_ID()
    , @object_id int = OBJECT_ID(N'dbo.Example1')
    , @allocated_page_file_id int
    , @allocated_page_page_id int;
--get first clustered index data page
SELECT
      @allocated_page_file_id = allocated_page_file_id
    , @allocated_page_page_id = allocated_page_page_id
FROM sys.dm_db_database_page_allocations(@database_id, @object_id, 1, 1, 'DETAILED')
WHERE
    page_type_desc = N'DATA_PAGE'
    AND previous_page_page_id IS NULL --first page of clustered index;
--dump record
DBCC TRACEON(3604);
DBCC PAGE(@database_id,@allocated_page_file_id,@allocated_page_page_id,1);
DBCC TRACEOFF(3604);
GO

Вот выдержка из результатов моего экземпляра с полями физической структуры записи:

DATA:


Slot 0, Offset 0x60, Length 17, DumpStyle BYTE

Record Type = PRIMARY_RECORD        Record Attributes =  NULL_BITMAP    Record Size = 17

Memory Dump @0x0000002262C7A060

0000000000000000:   10000e00 02000000 03000000 803f0300 00        .............?...
                    |        |        |   |        |    |null bitmap (1 byte)
                    |        |        |   |        |column count (2 bytes)
                    |        |        |   |Value column data (4-byte real)
                    |        |        |SigId column data (2-byte smallint)
                    |        |LogId column data (4-byte int)
                    |Record header (2-byte record type and 2 byte offset to null bitmap)

Что касается того, почему ваша фактическая длина записи составляет 25 вместо 17, как в этом примере, вероятная причина заключается в том, что изменения схемы были сделаны после того, как таблица была первоначально создана, как предположил Мартин в своем комментарии. Если в базе данных включен уровень изоляции версий строк, будут дополнительные накладные расходы, как указано в блоге Paul, но я сомневаюсь, что причина здесь в том, что эти накладные расходы превышают 8 байтов.