Создание некластеризованного индекса на непостоянном вычисляемом столбце SQL Server

10

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

Возьмите следующий пример:

--SCHEMA
CREATE TABLE dbo.Invoice
(
    InvoiceID INT IDENTITY(1, 1) PRIMARY KEY,
    CustomerID INT FOREIGN KEY REFERENCES dbo.Customer(CustomerID),
    InvoiceStatus NVARCHAR(50) NOT NULL,
    InvoiceStatusID AS CASE InvoiceStatus 
                         WHEN 'Sent' THEN 1 
                         WHEN 'Complete' THEN 2
                         WHEN 'Received' THEN 3
                       END
)
GO

--INDEX
CREATE NONCLUSTERED INDEX IX_Invoice ON Invoice
(
    CustomerID ASC
)
INCLUDE
(
    InvoiceStatusID
)
GO

Я получаю, что оно хранится на уровне листьев, но если значение не сохраняется, как что-либо хранится вообще? Как индекс помогает SQL Server найти эти строки в этой ситуации?

Любая помощь с благодарностью,

Большое спасибо,

РЕДАКТИРОВАТЬ:

Спасибо Brent & Aaron за ответ, вот PasteThePlan, ясно показывающий, что они объяснили.

Uberzen1
источник
5
Он не сохраняется на страницах данных таблицы, но сохраняется на страницах индекса .
Аарон Бертран
Непостоянные вычисляемые столбцы физически не сохраняются в таблице. Это виртуальные столбцы. Их значения пересчитываются каждый раз, когда на них ссылаются в запросе. см этот реф .
Кин Шах

Ответы:

11

Когда SQL Server создает индекс для вычисляемого поля, вычисляемое поле записывается на диск в это время - но только на 8К-страницах этого индекса. SQL Server может вычислить InvoiceStatusID, когда он читает кластерный индекс - нет необходимости записывать эти данные в кластерный индекс.

При удалении / обновлении / вставке строк в dbo.Invoice данные в индексах обновляются. (При изменении InvoiceStatus SQL Server также знает, как обновить IX_Invoice.)

Лучший способ убедиться в этом самому - это сделать это: создать эти объекты и выполнить обновления, которые касаются поля InvoiceStatusID. Опубликуйте план выполнения (для этого полезно PasteThePlan.com), если вам нужна помощь, чтобы увидеть, где происходят обновления индекса.

Брент Озар
источник
1
@ Uberzen1 Нет, как он объяснил, он записывается на страницы индекса во время вставки / обновления. Не нужно ничего пересчитывать, если индекс используется для доступа к столбцу.
Аарон Бертран
Ах! Я с тобой сейчас, прости!
Uberzen1
6
@ Хорошо, без обид, но я не думаю, что это на Бренте. Они могут вставить тот же XML в Dropbox, на форумах MSDN, здесь, в основном, где угодно в сети ... Разве каждый онлайн-сервис теперь должен отвечать за секреты, которые могут быть разглашены людьми, которые загружают туда файлы?
Аарон Бертран
2
@blobbles да, вы просто не можете остановить людей от чрезмерного обмена. Привет, кстати, подписывайтесь на меня в Instagram - я BrentO - и я делюсь там фотографиями моего завтрака. ;-)
Брент Озар
4
@blobbles в ссылке «Конфиденциальность» гласит: « Данные, которые вы копируете / вставляете, являются общедоступными . Любой может прочитать это. Там нет безопасности.
ypercubeᵀᴹ
8

Значение для индексированного непостоянного вычисляемого столбца не сохраняется на страницах данных таблицы , но сохраняется на страницах индекса . Он не сохраняется в таблице независимо от того, сохраняется ли он в 0, 1 или нескольких индексах.

Просто чтобы проиллюстрировать описание Брента на примере, который вы привели, давайте вставим строку:

INSERT dbo.Invoice(CustomerID, InvoiceStatus) VALUES(1,N'Sent');

Теперь давайте посмотрим на страницы индекса:

DBCC TRACEON(3604, -1);
DBCC IND(N'dbname', N'dbo.Invoice', 2);

(Очевидно, изменится dbname, и идентификатор индекса не может быть 2 в вашем случае.)

Вывод (ваш обязательно будет отличаться):

введите описание изображения здесь

И, наконец, давайте проверим страницу на PageType2:

DBCC PAGE(7, 1, 584, 3);

(Вам, вероятно, потребуется изменить 7, чтобы соответствовать идентификатору базы данных, и если у вас есть несколько файлов данных, вам может потребоваться изменить второй аргумент, чтобы он совпадал PageFIDс первым результатом.)

Вывод:

введите описание изображения здесь

Это на странице индекса.

Аарон Бертран
источник
Очень круто, спасибо Аарон. Причина, по которой я сначала задал вопрос, заключается в том, что у меня возникли реальные проблемы с развертыванием аналогичного индекса в реальном мире, и я хотел точно понять, что происходит под капотом, чтобы я мог разобраться в проблеме. Это очень помогает, спасибо!
Uberzen1
1
@ Uberzen1 Можете ли вы определить "настоящая проблема"? Собираетесь ли вы опубликовать вопрос об этой проблеме?
Аарон Бертран
Я мог бы сделать, я собирался сначала углубиться в это сам, но просто хотел понять, что именно делает оператор создания индекса. TLDR есть; У меня есть большая таблица, похожая на таблицу счетов-фактур выше, в ней около 400 м записей и, к сожалению, столбец OrderStatus вставлен прямо посередине, что делает индексацию и т. Д. Немного болезненной. На данный момент мы добавили вычисляемый столбец, чтобы в конечном итоге сохранить его и переместить поле varchar в его собственную таблицу. 1/2
Uberzen1
5
@ Uberzen1 Да, поскольку вычисляемый столбец фактически записывается на диск при записи в индекс, все эти действия должны регистрироваться. Обходной путь может заключаться в том, чтобы прекратить полагаться на вычисляемый столбец - либо поместить это выражение в представление, либо в специальные запросы, и, если это не вариант, вы можете создать новый столбец, допускающий пустые значения, обновите его порциями (чтобы избежать уничтожения журнала) , затем опустите вычисляемый столбец, переименуйте новый столбец и измените свой DML, чтобы написать его вручную. Но на самом деле, поскольку это избыточная информация, которую вы можете получить из существующих данных, я бы выбрал первый вариант.
Аарон Бертран
2
Большое спасибо, Аарон. Я рад, что вы упомянули о том, что вы рассматриваете этот вопрос, потому что это был и мой путь к решению, возможно, пришло время вернуться к этой идее!
Uberzen1
7

Атрибут PERSISTEDдля вычисляемого столбца относится к тому, сохраняются ли значения в таблице (кластеризованный индекс или куча), а не к тому, сохраняются ли значения в индексе.

CREATE INDEXИмеет требование к ограничениям в отношении вычисляемых столбцов и индексов:

Вычисляемые столбцы, которые являются детерминированными и точными или неточными, могут быть включены в столбцы. Вычисляемые столбцы, полученные из типов данных image, ntext, text, varchar (max), nvarchar (max), varbinary (max) и xml, могут быть включены в неключевые столбцы, если типы данных вычисляемых столбцов допустимы как включенные колонка. Для получения дополнительной информации см. Индексы для вычисляемых столбцов.

Нет ограничений относительно того, сохраняется ли вычисляемый столбец или нет.

и далее (не о включенных, а о вычисляемых столбцах в основной части индекса):

Индексы могут быть созданы на вычисляемых столбцах. Кроме того, вычисляемые столбцы могут иметь свойство PERSISTED. Это означает, что компонент Database Engine сохраняет вычисленные значения в таблице и обновляет их при обновлении любых других столбцов, от которых зависит вычисляемый столбец. Компонент Database Engine использует эти постоянные значения при создании индекса для столбца и при ссылке на индекс в запросе.

Чтобы индексировать вычисляемый столбец, вычисляемый столбец должен (быть) детерминированным и точным. Однако использование PERSISTEDсвойства расширяет тип индексируемых вычисляемых столбцов и включает:

...

ypercubeᵀᴹ
источник