Каковы издержки строки при использовании сжатия страницы?

10

Я создал таблицу с 650 числовыми (19,4) столбцами. Когда я включаю Page Compression, запустив

ALTER TABLE fct.MyTable REBUILD  WITH (DATA_COMPRESSION = PAGE);

я получил

Сообщение 1975, уровень 16, состояние 1
Индекс Длина строки PK_Mytable превышает максимально допустимую длину в 8060 байтов.

но 650 умножить на 9 байтов - это только 5850 байтов, что довольно далеко от заявленного предела в 8060 байтов.

Сервер работает под управлением Windows 2012 r2 с SQL Server 2016 SP1 CU2

Каковы издержки строки при использовании сжатия страницы?

Вот некоторый код, чтобы показать, что я имею в виду:

/* test script to demo MSG 1975 */
DECLARE @sql NVARCHAR(max)='', @i INT =0
drop table if exists dbo.mytable;

SET @sql = 'Create table dbo.Mytable (MyTableID bigint not null 
  identity(1,1) primary key clustered, '

WHILE @i < 593 BEGIN
    SET @sql += ' Column' + LTRIM(@i) + ' numeric(19,4) null, '
    SET @i +=1
END

SET @sql += ' LastColumn int) '
--SET @sql += ' with (DATA_COMPRESSION = ROW) '
SET @sql += ' with (DATA_COMPRESSION = PAGE) '

SELECT @sql
EXEC sys.sp_executesql @sql

SELECT top 10000 * FROM dbo.MyTable MT

Сжатие строк также не выполняется, но при другом количестве строк.

Хенрик Стаун Поулсен
источник
Насколько велик ваш первичный ключ? Если это таблица фактов, и вы хотите сжимать и повышать производительность, я предлагаю вам ознакомиться с индексами columnstore, они могут оказать существенное влияние. Накладные расходы на сжатие страниц - это большее использование процессора для распаковки.
Стейн
@StijnWynants; 8 байтов используется для BigInts. Это действительно факт, но недостаточно строк, чтобы гарантировать индекс columnstore.
Хенрик Стаун Поульсен,

Ответы:

13

Если вы попытаетесь создать свою таблицу без кластерного ограничения PK, и вы получите немного другую ошибку:

Сообщение 1701, уровень 16, состояние 1, строка 1 Создание или изменение таблицы «Mytable» не удалось, так как минимальный размер строки составил бы 8067, включая 1530 байтов внутренних издержек. Это превышает максимально допустимый размер строки таблицы в 8060 байт.

В этом сообщении об ошибке вы можете увидеть, что для сжатия страниц существует 1530 байт внутренних издержек.

Теперь вы можете сделать математику:

  • 8 байтов для bigintMyTableID
  • 4 байта для intLastColumn
  • 9 байтов для каждого из 593 numeric(19,4)столбцов (всего 5337 байтов)
  • 1530 байтов накладных расходов на сжатие

Итак, 8 + 4 + (593 * 9) + 1530 = 6879. Подождите секунду ... Это все еще ниже 8060. Что с этим ?!


Алгоритм сжатия страниц фактически объединяет несколько алгоритмов сжатия. Первый шаг - применить сжатие ROW. Накладные расходы на сжатие строк не включаются в 1530 байтов служебных данных, перечисленных в этом сообщении об ошибке.

Вы можете узнать больше о том, как работает сжатие строк, здесь, в моем блоге и здесь, в BOL . В статье BOL вы заметите, что она описывает numericхранилище как «Это хранилище точно такое же, как формат хранения vardecimal», но не объясняет vardecimal. Этот пост охватывает vardecimalнемного больше - по сути, он добавляет 2 байта служебной информации на столбец для хранения фактической длины (аналогично тому, что varcharделает).

Сжатие строки потребует дополнительных 2 байтов для каждого из 593 numericстолбцов, а также bigintи intпотребуется 1 байт служебной информации каждый.

В строках сжатых требований к хранению будут:

  • 8 байтов + 1 байт для bigintMyTableID
  • 4 байта + 1 байт для intLastColumn
  • 9 байтов + 2 байта для каждого из 593 numeric(19,4)столбцов
  • 1188 байтов накладных расходов на сжатие ROW

8 + 4 + (593 * 9) = 5349 байт данных

1 + 1 + (593 * 2) = 1188 байт для сжатия строки

Всего 6537 байт для схемы со сжатием строк


Теперь, когда у нас есть размер строки для схемы со сжатием строк, мы можем вернуться к нашей математике. Размер строки со сжатием страницы будет равен размеру данных + накладные расходы на сжатие строк + накладные расходы на сжатие страниц:

  • 8 байтов для bigintMyTableID
  • 4 байта для intLastColumn
  • 9 байтов для каждого из 593 numeric(19,4)столбцов
  • 1188 байтов накладных расходов на сжатие ROW
  • 1530 байтов служебных данных сжатия PAGE
  5349 байт данных 
+ 1188 байтов на сжатие строк 
+ 1530 байтов на сжатие страницы 

Всего 8067 байт

AMtwo
источник
1
Мне нравится ваш вывод: «В большинстве случаев вы обнаружите, что сжатие строк может сэкономить некоторое пространство - но не всегда». 2718 байт - это намного больше, чем я ожидал. Большое спасибо, что нашли время написать такой подробный ответ.
Хенрик Стаун Поульсен,
1
@HenrikStaunPoulsen Еще одна важная вещь, которую следует помнить, - это то, что SQL Server должен предполагать, что ваши данные не могут быть сжаты. Таким образом, даже если ваши данные будут сжаты до размера менее 8060 байт, SQL Server должен рассчитывать размер строки на основе теоретического максимального размера строки для несжимаемых данных.
AMtwo
Через 3 дня я все еще поражен количеством байтов, необходимых для сжатия строк; 2 байта на столбец. Сжатие страницы добавляет к этому почти 3 байта. Но; Спасибо за помощь. Это было очень полезно.
Хенрик Стаун Поульсен,