SQL SERVER Хранилище TinyInt

12

В SQL Server почему tinyint хранится с 9B в строке. По какой-то причине, кажется, есть дополнительный один байт в конце маски битовой карты NULL.

    ИСПОЛЬЗОВАТЬ tempdb;
    ИДТИ

    СОЗДАТЬ СТОЛ TBL
    (
        я TINYINT НЕ NULL
    );
    ИДТИ

    INSERT INTO tbl (i)
        ЦЕННОСТИ (1);
    ИДТИ

    DBCC IND ('tempdb', 'tbl', - 1);
    ИДТИ

    DBCC TRACEON (3604); - Дамп страницы уйдет в консоль
    ИДТИ

    DBCC PAGE ('tempdb', 1 168,3);
    ИДТИ

Результаты (я поменял местами байты из-за того, что DBCC PAGE сначала отображал младший байт):

Record Size = 9B
10000500 01010000 00
TagA = 0x10 = 1B
TagB = 0x00 = 1B
Null Bitmap Offset = 0x0005 = 2B
Our integer column = 0x01 = 1B
Column Count = 0x0001 = 2B
NULL Bitmap = 0x0000 = 2B (what!?)
ooutwire
источник
1
Это просто образовательный? Я все для обрезки места, где это необходимо, но это, вероятно, не тот байт, о котором я буду беспокоиться ...
Аарон Бертран
Это познавательно. Мой следующий доклад по SQLSaturday посвящен сжатию; Итак, я создал примеры для каждого типа данных, чтобы помочь людям понять последствия их выбора типов данных и показать влияние сжатия на все типы данных.
ooutwire
Я предполагал, что tinyint будет храниться как 1B (так и есть) с 7B накладных расходов. Интересно, что за дополнительный байт в конце записи ???
ooutwire
Я вижу разные результаты (хотя и не уверен, что они больше соответствуют ожидаемым), когда столбец TINYINT - не единственный столбец в таблице. Похоже, довольно редкий случай использования.
Аарон Бертран
Конечно, это не общая проблема варианта использования. Я просто пытался показать каждый тип данных по отдельности, чтобы снизить затраты на хранение и дать новичкам понять, как выглядит столбец на странице. Я нахожу странным иметь дополнительный байт ... сводит меня с ума, чтобы увидеть его там и без причины.
ooutwire

Ответы:

12

Если вы вычисляете запись, используя простое добавление размера, вы действительно получите 8: 4 + 1 + 2 + 1 (заголовок + фиксированный размер + счетчик нулевого растрового изображения + само нулевое растровое изображение). Но запись кучи не может быть меньше размера заглушки пересылки , которая составляет 9 байтов, поскольку запись должна гарантировать, что ее можно заменить заглушкой пересылки. Следовательно, запись будет фактически на 9 байтов. A smallintбудет 9 байтов как с помощью вычисления, так и с минимальным размером. Все, что больше, уже больше заглушки для пересылки, поэтому ваш размер вычислений соответствует размеру записи.

Ремус Русану
источник
9 байтов также применимы к этому определению, CREATE TABLE tbl (i TINYINT NOT NULL PRIMARY KEY)так что это просто общее правило для всех строк, являются ли они частью кучи или нет?
Мартин Смит
1
B-дерево может быть преобразовано в кучу ( alter table ... drop constraint), и операция не является полной перестройкой (верхние страницы b-дерева отбрасываются, оставшиеся листовые страницы не связываются, а в результате получается куча), поэтому логика резервирования по-прежнему применяется. ,
Ремус Русану
Я думаю, что это подтверждает то, что сказал Ремус ... Improve.DK/archive/2011/06/07/…
ooutwire
6

Приятно иметь ухо автора. :-) Kalen подозревает, что это просто применение некоторой минимальной длины строки, где все <9 дополняется до 9. Конечно, есть только несколько случаев, когда это возможно. Вы найдете этот фантомный байт для TINYINT и BIT, а также для VARCHAR (1) / CHAR (1). Если вы перейдете к SMALLINT или CHAR (2), оно не увеличится больше 9, но увеличится, если вы перейдете, скажем, к CHAR (3).

По сути, вы можете указать на эффективность, которую вы можете получить, мудро выбирая типы данных, но отметьте, что есть некоторые крайние случаи, когда правила не выполняются из-за других факторов на уровне хранения.

РЕДАКТИРОВАТЬ Я надеюсь иметь более конкретную информацию для вас. Просто хотел сообщить, что именно об этом сейчас думает автор книги Internals. Она не уверена на 100%.

Аарон Бертран
источник
Спасибо, Аарон, за то, что обратились к Калену. Прошлой ночью я копался в этой книге и вырывал волосы. Это похоже на дополнительные байты метаданных для sql_variant, за исключением того, что здесь я не могу объяснить фантомный байт, за исключением того, что он машет рукой и выкрикивает: «Так оно и есть, приятель!»
ooutwire
1
Хорошо, вы можете связать этот комментарий с «крайним крайним случаем, так как не так много таблиц, разработанных для того, чтобы попытаться сохранить один tinyint или char (1) в каждой строке».
Аарон Бертран