Использование разреженных столбцов

Разреженные столбцы — это обычные столбцы, имеющие оптимизированное хранилище для значений NULL. Разреженные столбцы уменьшают пространство, необходимое для хранения значений NULL, однако увеличивается стоимость получения значений, отличных от NULL. Разреженные столбцы следует использовать только в том случае, если экономится не менее чем от 20 до 40 процентов места. Наборы столбцов и разреженные столбцы определяются с помощью инструкций CREATE TABLE и ALTER TABLE.

Разреженные столбцы можно использовать совместно с наборами столбцов и фильтруемыми индексами.

  • Наборы столбцов

    Инструкции INSERT, UPDATE и DELETE могут ссылаться на разреженные столбцы по именам. Также можно просматривать и работать со всеми разреженными столбцами таблицы, объединенными в один XML-столбец. Такой столбец называется набором столбцов. Дополнительные сведения о наборах столбцов см. в разделе Использование наборов столбцов.

  • Фильтруемые индексы

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

Разреженные столбцы и фильтруемые индексы позволяют приложениям, таким как Windows SharePoint Services, эффективно хранить и получать доступ к большому числу определяемых пользователем свойств с помощью SQL Server.

Свойства разреженных столбцов

Разреженные столбцы имеют следующие характеристики.

  • Компонент SQL Server Database Engine использует ключевое слово SPARSE в определении столбца, чтобы оптимизировать хранение значений в этом столбце. Следовательно, если в любой строке таблицы этот столбец содержит значение NULL, место для хранения этих значений не требуется.

  • Представления каталога таблицы, имеющей разреженные столбцы, идентичны представлениям обычной таблицы. Представление каталога sys.columns содержит по одной строке для каждого столбца в таблице, включая набор столбцов, если он был определен.

  • Разреженные столбцы являются свойством уровня хранилища, а не логической таблицы. Поэтому инструкция SELECT…INTO не копирует свойство разреженного столбца в новую таблицу.

  • Функция COLUMNS_UPDATED возвращает значение типа varbinary, показывающее все столбцы, которые были обновлены в процессе DML-действия. Функция COLUMNS_UPDATED возвращает следующие биты.

    • Если разреженный столбец был явно обновлен, соответствующий бит, представляющий этот столбец, и бит, представляющий набор столбцов, устанавливаются в 1.

    • Если набор столбцов был явно обновлен, бит, представляющий набор столбцов, и биты, представляющие все разреженные столбцы в таблице, устанавливаются в 1.

    • При операциях вставки всем битам присваивается значение 1.

    Дополнительные сведения о наборах столбцов см. в разделе Использование наборов столбцов.

Столбцы следующих типов данных не могут быть указаны как SPARSE.

geography

text

geometry

timestamp

image

user-defined data types

ntext

Предполагаемая экономия места по типам данных

Для хранения значений, отличных от NULL, в разреженных столбцах требуется больше места, чем для хранения идентичных данных, но не отмеченных, как SPARSE. В следующих таблицах показано использование пространства для каждого типа данных. Столбец Процент значений NULL показывает, какой процент данных должен содержать значения NULL для достижения общей экономии пространства в 40 процентов.

Типы данных фиксированной длины

Тип данных

Неразреженные байты

Разреженные байты

Процент значений NULL

bit

0.125

5

98%

tinyint

1

5

86%

smallint

2

6

76%

int

4

8

64%

bigint

8

12

52%

real

4

8

64%

float

8

12

52%

smallmoney

4

8

64%

money

8

12

52%

smalldatetime

4

8

64%

datetime

8

12

52%

uniqueidentifier

16

20

43%

date

3

7

69%

Типы данных с длиной, зависящей от точности

Тип данных

Неразреженные байты

Разреженные байты

Процент значений NULL

datetime2(0)

6

10

57%

datetime2(7)

8

12

52%

time(0)

3

7

69%

time(7)

5

9

60%

datetimetoffset(0)

8

12

52%

datetimetoffset (7)

10

14

49%

decimal/numeric(1,s)

5

9

60%

decimal/numeric(38,s)

17

21

42%

vardecimal(p,s)

В качестве консервативной оценки используйте тип decimal.

Типы данных с длиной, зависящей от данных

Тип данных

Неразреженные байты

Разреженные байты

Процент значений NULL

sql_variant

Зависит от базового типа данных.

varchar или char

2*

4*

60%

nvarchar или nchar

2*

4*+

60%

varbinary или binary

2*

4*

60%

xml

2*

4*

60%

hierarchyid

2*

4*

60%

*Длина равна средней длине данных, содержащихся в типе, плюс 2 или 4 байта.

Издержки в памяти при выполнении операций обновления разреженных столбцов

При проектировании таблиц с разреженными столбцами не забывайте о том, что при выполнении операции обновления строки требуется 2 дополнительных байта на каждый разреженный ненулевой столбец в таблице. Из-за этого операция обновления может непредвиденно завершиться ошибкой 576 в том случае, если общий размер строки, включая дополнительную память, превысит 8019 байт и будут отсутствовать столбцы, которые можно будет принудительно разместить вне строки.

Рассмотрим пример таблицы, которая содержит 600 разреженных столбцов типа bigint. При наличии 571-го ненулевого столбца общий размер на диске составит 571 * 12 = 6852 байт. После добавления дополнительного размера строки и заголовка разреженного столбца размер увеличится до 6895 байт. Страница по-прежнему занимает около 1124 байт на диске. При этом создается впечатление, что дополнительные столбцы могут быть успешно обновлены. Но во время обновления появляются дополнительные издержки в памяти, которые составят 2 * (число разреженных ненулевых столбцов). В данном примере размер строки на диске увеличится приблизительно до 8037 байт, включая дополнительные издержки 2 * 571 = 1142 байта. Это значение превышает максимально допустимый размер 8019 байт. Так как все столбцы содержат тип данных фиксированной длины, они не могут быть принудительно отправлены вне строки. В результате этого операция обновления завершится ошибкой 576.

Ограничения на использование разреженных столбцов

Разреженные столбцы могут иметь любой тип данных SQL Server. Они работают так же, как и другие столбцы, но со следующими ограничениями.

  • Разреженный столбец должен допускать значения NULL и не может иметь свойств ROWGUIDCOL или IDENTITY.

  • Разреженный столбец не может иметь следующие типы данных: text, ntext, image, timestamp, определяемый пользователем тип данных, geometry или geography; также он не может иметь атрибут FILESTREAM.

  • Разреженный столбец не может иметь значения по умолчанию.

  • Разреженный столбец не может быть привязан к правилу.

  • Хотя вычисляемый столбец и может содержать разреженный столбец, но сам вычисляемый столбец не может быть отмечен как SPARSE.

  • Разреженный столбец не может быть частью кластеризованного индекса или индекса уникального первичного ключа. Однако материализованные и нематериализованные вычисляемые столбцы, определенные для разреженных столбцов, могут быть частью кластеризованного ключа.

  • Разреженный столбец не может быть использован в качестве ключа секции для кластеризованного индекса или кучи. Однако разреженный столбец может быть использован в качестве ключа секции для некластеризованного индекса.

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

  • Разреженные столбцы несовместимы со сжатием данных. Поэтому разреженные столбцы нельзя добавить в сжатые таблицы, а таблицы с разреженными столбцами нельзя сжать.

  • Преобразование столбца из разреженного в неразреженный (или наоборот) требует изменения формата хранения столбца. Для внесения этого изменения компонент SQL Server Database Engine использует следующую процедуру.

    1. В таблицу добавляется новый столбец с новым размером хранения и форматом.

    2. Для каждой строки в таблице производится обновление и копирование значений, хранимых в старом столбце, в новый столбец.

    3. Из схемы таблицы удаляется старый столбец.

    4. Производится перестроение таблицы для освобождения места, используемого старым столбцом.

    ПримечаниеПримечание

    Шаг 2 может завершиться неудачно, если размер данных в строке превышает максимально допустимый размер строки. Этот размер включает размер данных, хранимых в старом столбце, и обновленных данных, хранимых в новом столбце. Данное ограничение составляет 8 060 байт для таблиц, не содержащих разреженные столбцы, и 8 018 байт для таблиц, содержащих их. Данная ошибка может возникнуть, даже если все подходящие столбцы включают внестрочные данные. Дополнительные сведения см. в разделе Превышающие размер страницы данные строки, превышающие 8 КБ.

  • При преобразовании неразреженного столбца в разреженный возрастет пространство, необходимое для хранения значений, отличных от NULL. Если строка имеет длину, близкую к максимальной, операция может завершиться неудачно.

Технологии SQL Server, поддерживающие разреженные столбцы

В этом разделе описывается поддержка разреженных столбцов в следующих технологиях SQL Server.

  • Репликация транзакций

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

    Репликация атрибута SPARSE определяется параметром схемы, задаваемым с помощью процедуры sp_addarticle либо с помощью диалогового окна Свойства статьи в среде Среда SQL Server Management Studio. Более ранние версии SQL Server не поддерживают разреженные столбцы. Если необходимо реплицировать данные в более раннюю версию, следует указать, что атрибут SPARSE не подлежит репликации.

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

  • Репликация слиянием

    Репликация слиянием не поддерживает разреженные столбцы и наборы столбцов.

  • Отслеживание изменений

    Отслеживание изменений поддерживает разреженные столбцы и наборы столбцов. Если в таблице обновляется набор столбцов, система отслеживания изменений считает это обновлением целой строки. Более подробное отслеживание изменений для определения точного набора разреженных столбцов, который был изменен в ходе операции обновления набора столбцов, не осуществляется. Если разреженные столбцы обновляются явно с помощью инструкции DML, система отслеживания изменений обрабатывает их обычным образом и можно идентифицировать точный набор измененных столбцов.

  • Система отслеживания измененных данных

    Система отслеживания измененных данных поддерживает разреженные столбцы, но не поддерживает наборы столбцов.

  • При копировании таблицы свойство разреженности столбца не сохраняется.

Примеры

В данном примере таблица документа содержит обычный набор со столбцами DocID и Title. Производственной группе необходимы столбцы ProductionSpecification и ProductionLocation для всех рабочих документов. Группе сбыта необходим столбец MarketingSurveyGroup для документов сбыта. Код из этого примера создает таблицу, использующую разреженные столбцы, вставляет в таблицу две строки, затем выбирает из таблицы данные.

ПримечаниеПримечание

Эта таблица насчитывает лишь пять столбцов, что упрощает ее отображение и чтение. При установленном параметре ANSI_NULL_DFLT_ON объявлять разреженные столбцы допускающими значения NULL необязательно.

USE AdventureWorks2008R2;
GO

CREATE TABLE dbo.DocumentStore
(DocID int PRIMARY KEY,
Title varchar(200) NOT NULL,
ProductionSpecification varchar(20) SPARSE NULL,
ProductionLocation smallint SPARSE NULL,
MarketingSurveyGroup varchar(20) SPARSE NULL ) ;
GO

INSERT dbo.DocumentStore(DocID, Title, ProductionSpecification, ProductionLocation)
VALUES (1, 'Tire Spec 1', 'AXZZ217', 27);
GO

INSERT dbo.DocumentStore(DocID, Title, MarketingSurveyGroup)
VALUES (2, 'Survey 2142', 'Men 25 - 35');
GO

При выборе всех столбцов таблицы возвращается обычный результирующий набор.

SELECT DocID, Title, ProductionSpecification, ProductionLocation, MarketingSurveyGroup
FROM DocumentStore ;

Ниже приводится результирующий набор.

DocID  Title        ProductionSpecification  ProductionLocation  MarketingSurveyGroup

------ ------------ ----------------------- ------------------- ---------------------

1      Tire Spec 1  AXZZ217                  27                  NULL

2      Survey 2142  NULL                     NULL                Men 25-35

Поскольку производственному отделу не нужны маркетинговые данные, должен быть предоставлен список столбцов, содержащих только необходимые данные, как это показано в следующем запросе.

SELECT DocID, Title, ProductionSpecification, ProductionLocation 
FROM DocumentStore 
WHERE ProductionSpecification IS NOT NULL ;

Ниже приводится результирующий набор.

DocID  Title        ProductionSpecification  ProductionLocation

----- ------------ ----------------------- ------------------

1      Tire Spec 1  AXZZ217                  27