Я изучаю способы повышения производительности приложения, на которое я могу повлиять лишь в ограниченной степени на уровне базы данных. Версия SQL Server — 2012 SP2, а рассматриваемая структура таблицы и представления (я не могу повлиять на это + обратите внимание, что документ xml может иметь всего несколько сотен элементов):
CREATE TABLE Orders(
id nvarchar(64) NOT NULL,
xmldoc xml NULL,
CONSTRAINT PK_Order_id PRIMARY KEY CLUSTERED (id)
);
CREATE VIEW V_Orders as
SELECT
a.id, a.xmldoc
,a.xmldoc.value('data(/row/c1)[1]', 'nvarchar(max)') "Stuff"
,a.xmldoc.value('data(/row/c2)[1]', 'nvarchar(max)') "OrderType"
etc..... many columns
from Orders a;
Типичный запрос (и тот, который используется для тестирования ниже):
SELECT id FROM V_Orders WHERE OrderType = '30791'
Все запросы выполняются к представлению, и я не могу повлиять ни на запросы, ни на структуру таблицы/представления.
Я думал, что добавление выборочного XML-индекса в таблицу будет моим спасением:
CREATE SELECTIVE XML INDEX I_Orders_OrderType ON Orders(xmldoc)
FOR(
pathOrderType = '/row/c2' as SQL [nvarchar](20)
)
Но даже после обновления статистики план выполнения выглядит странно. Не удалось опубликовать изображение как новую учетную запись, поэтому соответствующие детали в виде текста:
- Поиск кластеризованного индекса из selectedXml (Стоимость: 2% от общей суммы). Ожидаемое количество строк 1, но ожидаемое количество раз выполнения 1269 (количество строк в таблице)
- -> Сортировка Top N (Стоимость: 95% от общей суммы)
-> Вычислить скаляр (Стоимость 0)
Отдельная ветвь: сканирование кластерного индекса PK_Order_id (стоимость: 3% от общей суммы). Ожидаемое количество строк 1269
- -> Слияние скалярных результатов с компьютером с вложенными циклами (левое внешнее соединение)
- -> Фильтр
- -> Окончательный результат (ожидаемое количество строк 1269)
На самом деле с моими тестовыми данными запрос даже не возвращает никаких результатов, но не имеет значения, возвращает ли он один или несколько. Время выполнения поддерживает запрос, действительно занимающий столько времени, сколько можно вывести из плана выполнения, и количество прочтений исчисляется тысячами.
Итак, мой вопрос: почему оптимизатор не использует селективный xml-индекс должным образом? Или у меня что-то не так? Как мне оптимизировать производительность этого конкретного запроса с помощью выборочной индексации xml (или, возможно, сохраняемого столбца)?
Изменить: я провел дополнительное тестирование с большими выборочными данными (~ 274 тыс. строк в таблице с XML-документами, близкими к средним производственным размерам) и сравнил выборочный XML-индекс с продвигаемым столбцом. Результаты взяты из трассировки Profiler с упором на использование ЦП и количество прочтений. План выполнения выборочной индексации xml в основном идентичен описанному выше.
Выборочный XML-индекс и 274 тыс. строк (выполнение запроса выше): ЦП: 6454, чтение: 938521
После того, как я обновил значения в искомом поле, чтобы они были уникальными (всего записей по-прежнему 274 КБ), я получил следующие результаты:
Выборочный XML-индекс и 274 тыс. строк (выполнение запроса выше): CPU: 10077, чтение: 1006466
Затем с помощью продвигаемого (т.е. сохраняемого) отдельно проиндексированного столбца и использования его непосредственно в представлении: CPU: 0, считывает: 23
Производительность выборочного XML-индекса ближе к полному сканированию таблицы, чем к правильной выборке индексированного столбца SQL. Я где-то читал, что использование схемы для таблицы может помочь исключить шаг TOP N из плана выполнения (при условии, что мы ищем неповторяющееся поле), но я не уверен, что это реалистичная возможность в данном случае.