Перевод статьи: The COMPRESS() TSQL Function in SQL Server 2016+
Ещё одно полезное нововведение в SQL Server 2016 — это функция COMPRESS(). Она доступна во всех редакциях и выполняет сжатие данных по средствам GZIP алгоритма (документация)
Что известно о COMPRESS()
- Сжатые данные хранятся в VARBINARY(MAX)
- Распаковка данных происходит с помощью функции DECOMPRESS(), которая так же получает данные в VARBINARY(MAX)
- Вы не можете создавать индексы на колонке VARBINARY(MAX), но в некоторых случаях вы можете использовать эту колонку для фильтра в фильтрованных индексах
Давайте рассмотрим пример
Для самостоятельно воспроизведения примера, вы можете скачать следующий здесь
Предположим что у нас есть таблица с полем «Заметки», поле позволяет использовать NULL, длина заметки может существенно отличается (от 0 до огромного количества символов).
Первым делом я создаю 2 таблицы, почти везде «Заметки» в значении NULL, но в 10 000 строк они имеют значение от 3 байт до 29 Кб.
Как сильно сжимаются данные?
В нашем случае данные будут сжиматься очень хорошо, так как в них используются часто повторяющиеся символы. Вот как это будет выглядеть:
В таблице без сжатия из строки, которая не помещаются на 8Кб странице будет вынесена колонка «Заметки» в LOB хранилище (хранилище больших данных). В таблице со сжатием, все строки поместились на 8Кб страницу, по этой причине в LOB хранилище ничего не попало.
Тип данных имеет значение
Если вы используете COMPRESS(), вы должны быть уверены, что помните тип данных, который использовался во время компрессии. Может так случиться, что после распаковки (DECOMPRESS()), вы получите не те данные, что ожидали.
Давайте рассмотрим пример (не забывайте, что COMPRESS() и DECOMPRESS() возвращаются данные в VARBINARY(MAX)).
Перед занесением данных в таблицу, они были в формате VARCHAR, но если после распаковки мы укажем NVARCHAR(), то получим неверные значения:
Особенности
В документации по COMPRESS() сказано: «Сжатые данные не могут быть проиндексированы», это на 100% верно. Однако, мы можем использовать сжатую колонку в условии WHERE фильтрованного индекса.
CREATE INDEX ix_filtertest on dbo.Compressed (CompressedId) INCLUDE (Notes) WHERE (Notes IS NOT NULL);
Но чтобы SQL Server мог использовать такой индекс, нам необходимо ему помочь. Если мы просто передадим нужный индекс в подсказке SQL Server, то получим ошибку: