Створення некластеризованого індексу на неперсинованому обчислюваному стовпчику 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 чітко показує, що вони пояснили.


5
Він не зберігається на сторінках даних таблиці, але зберігається на сторінках індексу .
Аарон Бертран

Не збережені обчислювані стовпці фізично не зберігаються в таблиці. Вони є віртуальними колонками. Їх значення перераховуються щоразу, коли вони посилаються на запит. дивись цю реф .
Кін Шах

Відповіді:


11

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

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

Найкращий спосіб переконатися в цьому - це насправді зробити це: створити ці об’єкти та виконати оновлення, що стосуються поля InvoiceStatusID. Опублікуйте план виконання (для цього корисно PasteThePlan.com), якщо ви хочете допомогти побачити, де відбуваються оновлення індексу.


1
@ Uberzen1 Ні, як він пояснив, це записується на індексні сторінки під час вставки / оновлення. Не потрібно нічого перераховувати, якщо індекс використовується для доступу до стовпця.
Аарон Бертран

Ах! Я зараз з тобою, вибач!
Uberzen1

6
@blobbles добре, без образи, але я не думаю, що це на Brent. Вони могли б вставити той самий XML в папки, 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 ляпнув прямо по середині, зробивши індексацію тощо трохи болючим. Зараз ми додали обчислений стовпець, що врешті-решт збережемось і перемістимо поле варчара до власної таблиці. 1/2
Uberzen1

5
@ Uberzen1 Так, оскільки обчислюваний стовпчик насправді матеріалізується на диск під час запису до індексу, всю цю діяльність потрібно реєструвати. Вирішенням проблеми може бути припинення покладання на обчислений стовпець - або помістити це вираз у подання, або на спеціальні запити, і якщо це не варіант, ви можете створити новий зведений стовпчик, оновіть його шматками (щоб уникнути вбивства журналу) , потім опустіть обчислений стовпець, перейменуйте новий стовпець та змініть DML, щоб записати це вручну. Але дійсно, оскільки це зайва інформація, яку ви можете отримати з існуючих даних, я б вибрав перший варіант.
Аарон Бертран

2
Велике спасибі Аарону. Я радий, що ти згадав, що поставив перед ним погляд, тому що це теж мій шлях до вирішення, можливо, саме час переглянути цю ідею!
Uberzen1

7

Атрибут PERSISTEDдля обчислюваного стовпця стосується того, чи зберігаються значення в таблиці (кластерний індекс або купа), а не чи зберігаються значення в індексі.

CREATE INDEXМає вимога до обмежень в відношенні обчислюваних стовпців і індексів:

Обчислювані стовпці, які є детермінованими або точними, або неточними, можуть включати стовпці. Обчислювані стовпці, отримані з зображень, ntext, тексту, varchar (max), nvarchar (max), varbinary (max) та xml, типи даних можуть бути включені до неклавішних стовпців до тих пір, поки обчислювані типи даних стовпців допустимі як включені стовпчик. Для отримання додаткової інформації див. Покажчики обчислених стовпців.

Немає обмежень щодо збереження обчисленої колонки чи ні.

і далі (не про включені, а про обчислені стовпці в основній частині індексу):

Індекси можна створити на обчислених стовпцях. Крім того, обчислювані стовпці можуть мати властивість PERSISTED. Це означає, що Database Engine зберігає обчислені значення в таблиці та оновлює їх, коли оновлюються будь-які інші стовпці, від яких залежить обчислений стовпець. Database Engine використовує ці збережені значення, коли створює індекс у стовпці та коли на індекс посилається запит.

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

...

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.