Я не думаю, что вы можете достичь этого, используя CTE и LEFT JOIN, потому что существует множество ограничений , использующих индексированные представления .
Обходной путь
Я предлагаю разделить запрос на две части:
- Создать индексированное представление вместо общего табличного выражения (CTE)
- Создайте неиндексированное представление, которое выполняет LEFT JOIN
Помимо этого, создайте некластеризованный индекс для столбца Entity
в таблице Example
.
Затем при запросенеиндексированное представление, оно будет использовать индексы
--CREATE TABLE
CREATE TABLE Example (
Id INT primary key,
Entity varchar(50),
Parent varchar(50)
)
--INSERT VALUES
INSERT INTO Example
VALUES
(1, 'A', NULL)
,(2, 'AA', 'A')
,(3, 'AB','A')
,(4, 'ABA', 'AB')
,(5, 'ABB', 'AB')
,(6, 'AAA', 'AA')
,(7, 'AAB', 'AA')
,(8, 'AAC', 'AA')
--CREATE NON CLUSTERED INDEX
CREATE NONCLUSTERED INDEX idx1 ON dbo.Example(Entity);
--CREATE Indexed View
CREATE VIEW dbo.ExampleView_1
WITH SCHEMABINDING
AS
SELECT Parent, COUNT_BIG(*) as Count
FROM dbo.Example
GROUP BY Parent
CREATE UNIQUE CLUSTERED INDEX idx ON dbo.ExampleView_1(Parent);
--Create non-indexed view
CREATE VIEW dbo.ExampleView_2
WITH SCHEMABINDING
AS
SELECT e.Entity, COALESCE(Count,0) Count
FROM dbo.Example e
LEFT JOIN dbo.ExampleView_1 g
ON e.Entity = g.Parent
Таким образом, когда вы выполняете следующий запрос:
SELECT * FROM dbo.ExampleView_2 WHERE Entity = 'A'
Вы можете видеть, что представление Кластеризованный индекс и Таблица Некластеризованный индексиспользуются в плане выполнения:
Дополнительная информация
Не найдено дополнительных обходных путей для замены использования LEFT JOIN
или UNION
или CTE
в индексированных представлениях вы можете проверить много похожих вопросов Stackoverflow:
Обновление 1 - Представление с разделением по сравнению с декартовым объединением
Чтобы определить лучший подход, я попытался сравнить оба предложенных подхода.
--The other approach (cartesian join)
CREATE TABLE TwoRows (
N INT primary key
)
INSERT INTO TwoRows
VALUES (1),(2)
CREATE VIEW dbo.indexedView WITH SCHEMABINDING AS
SELECT
IIF(T.N = 2, Entity, Parent) as Entity
, COUNT_BIG(*) as CountPlusOne
, COUNT_BIG(ALL IIF(T.N = 2, NULL, 1)) as Count
FROM dbo.Example E1
INNER JOIN dbo.TwoRows T
ON 1=1
WHERE IIF(T.N = 2, Entity, Parent) IS NOT NULL
GROUP BY IIF(T.N = 2, Entity, Parent)
GO
CREATE UNIQUE CLUSTERED INDEX testIndex ON indexedView(Entity)
Я создал каждое индексированное представление для отдельных баз данных и выполнил следующий запрос:
SELECT * FROM View WHERE Entity = 'AA'
Представление с разделением
Декартово соединение
Статистика времени
Статистика времени показывает, что время выполнения подхода декартового объединения больше, чем подхода представления расщепления, как показано на рисунке ниже (декартовое соединение справа):
Добавление WITH (NOEXPAND)
Также я попытался добавить опцию WITH(NOEXPAND)
для подхода декартового объединения, чтобы заставить базу данныхмеханизм для использования индексированного представления кластеризованного индекса, и результат был следующим:
I cПосле того, как все кэши были выполнены и проведено сравнение, сравнение статистики времени показывает, что подход представления с разделением по-прежнему быстрее, чем подход декартового объединения (WITH(NOEXPAND)
подход справа) :