Время прочтения: 5 мин.

Начиная с версии SQL Server 2016, пользователям стали доступны функции сжатия данных COMPRESS и DECOMPRESS, с обширным набором примеров.

Функция COMPRESS – сжимает входные данные с использованием алгоритма GZIP и возвращает массив байтов типа varbinary(max).

Функция DECOMPRESS — распаковывает сжатые входные двоичные данные с использованием алгоритма GZIP и возвращает двоичные данные типа Varbinary(max). Но получим ли мы данные в исходном выражении или нет?

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

Пример 1: Базовые функции сжатия и распаковки

SELECT COMPRESS ('Котик')

Результат:

0x1F8B08000000000004003BF5EED38B570050E41F3305000000

SELECT DECOMPRESS(
0x1F8B08000000000004003BF5EED38B570050E41F3305000000)

Результат:

0xCAEEF2E8EA

Как видим, результатом функции DECOMPRESS является не фактическое значение, а двоичные данные. Нам нужно явно привести результат функции DECOMPRESS к типу данных сжимаемой строки.

Давайте приведем результат функции DECOMPRESS к типу Varchar с помощью следующего запроса.

SELECT CAST(0xCAEEF2E8EA AS VARCHAR(MAX))

Результат:

Котик

Пример 2: Теперь выполним действия из 1-ого примера в одном запросе

SELECT 'Котик' '1.Исходные данные',
	COMPRESS('Котик') '2.Сжатые данные', 
	DECOMPRESS(COMPRESS('Котик')) '3.Распакованные данные',
	CAST(DECOMPRESS(COMPRESS('Котик')) AS VARCHAR(MAX))
AS '4.Преобразованный тип данных'

Результат:

Пример 3: Сделаем тоже самое, через переменную

DECLARE @Cat VARCHAR(MAX) = 'Котик'
SELECT @Cat '1.Исходные данные',
	COMPRESS(@Cat) '2.Сжатые данные', 
	DECOMPRESS(COMPRESS(@Cat)) '3.Распакованные данные',
	CAST(DECOMPRESS(COMPRESS(@Cat)) AS VARCHAR(MAX))
		AS '4.Преобразованный тип данных'

Результат:

Пример 4: Далее разберём важность правильного выбора типа возвращаемого закодированного значения

DECLARE @Cat VARCHAR(MAX) = 'Котик', 
        @nCat NVARCHAR(MAX) = N'Котик'
SELECT COMPRESS (@Cat) 'Данные типа Varchar'
SELECT COMPRESS (@nCat) 'Данные типа NVarchar'

Результат:

Из приведенного выше результата видно, что обе переменные были установлены с одинаковыми значениями, но сжатый результат отличается, потому что одна переменная имеет тип Varchar, а другая переменная имеет тип NVarchar.

Пример 5: В примере разберём важность выбора правильного типа данных при преобразовании распакованного значения.

DECLARE @varcharCat VARCHAR(MAX) = 'Котик', 
        @compressedCat VARBINARY(MAX)
--Сжатие исходных данных типа VARCHAR
SET @compressedCat = COMPRESS(@varcharCat) 
--Преобразовываем распакованные данные в тип данных VARCHAR и NVARCHAR
SELECT @varcharCat 'Исходные данные VARCHAR',  
 CAST(DECOMPRESS(@compressedCat) AS VARCHAR(MAX)) 
         AS 'Данные типа Varchar',  
 CAST(DECOMPRESS(@compressedCat) AS NVARCHAR(MAX)) 
         AS 'Данные типа NVarchar'

Результат:

DECLARE @nVarCharCat NVARCHAR(MAX) = 'Котик', 
        @compressedCat VARBINARY(MAX)
--Сжатие исходных данных типа NVARCHAR
SET @compressedCat = COMPRESS(@nVarCharCat) 
--Try to CAST the decompressed value as VARCHAR and NVARCHAR
SELECT @nVarCharCat 'Исходные данные NVARCHAR',  
 CAST(DECOMPRESS(@compressedCat) AS VARCHAR(MAX))
         AS 'Данные типа Varchar',  
 CAST(DECOMPRESS(@compressedCat) AS NVARCHAR(MAX))
         AS 'Данные типа NVarchar'

Результат:

Из приведенных выше результатов ясно, что нам нужно преобразовать распакованное значение в тип фактического исходного типа строки, чтобы получить правильное значение.

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

DECLARE @CatToCompress VARCHAR(MAX) = 'COMPRESS и DECOMPRESS'
SELECT DATALENGTH(@CatToCompress) '1.Длина данных ДО сжатия', 
DATALENGTH(COMPRESS(@CatToCompress)) '1.Длина данных ПОСЛЕ сжатия'
GO
DECLARE @CatToCompress VARCHAR(MAX) 
 = 'Начиная с версии SQL Server 2016, пользователям стали доступны функции
сжатия данных COMPRESS и DECOMPRESS, с обширным набором примеров.
Функция COMPRESS – сжимает входные данные с использованием алгоритма GZIP
и возвращает массив байтов типа varbinary(max).'
SELECT DATALENGTH(@CatToCompress) '2.Длина данных ДО сжатия', 
DATALENGTH(COMPRESS(@CatToCompress)) '2.Длина данных ПОСЛЕ сжатия'
GO
DECLARE @CatToCompress VARCHAR(MAX) 
 = 'Функция DECOMPRESS - распаковывает сжатые входные двоичные данные с 
использованием алгоритма GZIP и возвращает двоичные данные типа Varbinary(max).
Но получим ли мы данные в исходном выражении или нет? Данные функции используют
стандартные алгоритм GZIP, поэтому значение, сжатое на уровне приложения, может
быть распаковано на сервере SQL, а значение, сжатое на сервере SQL, может быть
распаковано на уровне приложения. В этой статье, попробуем на примерах
разобрать работу алгоритма GZIP и его эффективность.'
SELECT DATALENGTH(@CatToCompress) '3.Длина данных ДО сжатия', 
 DATALENGTH(COMPRESS(@CatToCompress)) '3.Длина данных ПОСЛЕ сжатия'

Результат:

Из приведенных выше результатов ясно, что по мере увеличения длины сжимаемой строки, эффективность сжатия увеличивается.

Пример 7: Осталось рассмотреть, как использовать функции COMPRESS и DECOMPRESS при вставке и извлечении данных в столбец таблицы или из него.

Создадим таблицу Cats, выполнив следующий скрипт. В этой таблице столбец Discriptions. которые будет содержать значение, сжатое функцией COMPRESS.

CREATE TABLE dbo.Cats
(Id INT IDENTITY(1,1), Nickname NVARCHAR(100),
  Discriptions VARBINARY(MAX))

Далее вставим запись в таблицу, используя следующий скрипт. Здесь мы сжимаем значение для столбца Discriptions перед сохранением в нем.

INSERT INTO dbo.Cats (Nickname, Discriptions)
VALUES('Tom', 
	COMPRESS(N'Особой похвалы удостоилась пародия на заставку компании MGM,
	в которой кот Том изображал рычание льва Лео.'))

Следующим запросом мы получим вставленную запись из таблицы Cats. Здесь мы используем функцию DECOMPRESS для возврата распакованного значения столбца Discriptions.

SELECT Id, Nickname, Discriptions 'Сжатые данные', 
  CAST( DECOMPRESS(Discriptions) AS NVARCHAR(MAX))
                AS 'Распакованные данные'
FROM dbo.Cats

Результат:

Выводы:

  • При распаковке, важно выбирать тип данных согласно исходным
  • Сжатие эффективно при большой длине строк