Улучшить производительность запросов SQL CTE - PullRequest
3 голосов
/ 19 декабря 2011

Есть ли способ улучшить производительность следующего запроса CTE (@E и @R - это таблицы с индексами в реальной системе):

DECLARE @id bigint = 1

DECLARE @E TABLE
(
id bigint,
name varchar(50)
)

DECLARE @R TABLE
(
child_id bigint,
parent_id bigint
)

INSERT INTO @E SELECT 1, 'one'
INSERT INTO @E SELECT 2, 'two'
INSERT INTO @E SELECT 3, 'three'
INSERT INTO @E SELECT 4, 'four'
INSERT INTO @E SELECT 5, 'five'
INSERT INTO @E SELECT 6, 'six'
INSERT INTO @E SELECT 7, 'seven'

INSERT INTO @R SELECT 1, 2
INSERT INTO @R SELECT 1, 3
INSERT INTO @R SELECT 3, 4
INSERT INTO @R SELECT 5, 4
INSERT INTO @R SELECT 3, 6
INSERT INTO @R SELECT 7, 4

; WITH cte
(
child_id,
parent_id
)

AS (

SELECT * FROM @R R
WHERE R.child_id = @id

UNION ALL
SELECT R.* FROM @R R
INNER JOIN cte ON CTE.parent_id = R.child_id

)
SELECT * FROM @E E
WHERE e.id = @id
UNION ALL
SELECT P.* FROM @E E
INNER JOIN cte ON 1=1
INNER JOIN @E P ON P.id = cte.parent_id
WHERE e.id = @id
ORDER BY 1

Ожидаемые результаты:

id | name
1  | one 
2  | two
3  | three
4  | four
6  | six

В реальных данных я буду иметь дело со многими миллионами строк в @R и около ста тысяч строк в @E.Так что я смотрю, могу ли я что-нибудь сделать, чтобы немного повысить производительность.

Редактировать: просто чтобы прояснить и подвести итог, есть кластерный pk-индекс для R с child_id, parent_id идобавление индекса к @r.parent_id также улучшит производительность соединения.

Есть ли что-то, что улучшит это?Немного после CTE с inner join 1=1 есть что-нибудь, что можно было бы улучшить здесь, это настолько хорошо, насколько это возможно?Есть ли какой-нибудь другой дизайн схемы, который я мог бы сделать, чтобы получить подобное сопоставление родитель-потомок с лучшей производительностью?

Ответы [ 2 ]

3 голосов
/ 08 января 2012

Как указал marc_s

кластерный индекс на [child_id, parent_id] для этой таблицы недостаточно хорош - у вас должны быть отдельные индексы на (child_id) и (parent_id) для ускорения работы JOIN.Если у вас есть составной индекс на (child_id, parent_id) в этом порядке, то это можно использовать только для child_id - но не только для parent_id (и для него потребуются оба) - marc_s 19 декабря 11 в 12: 35

Это значительно улучшило производительность запроса и помогло мне понять, как запросы CTE работают внутри.

0 голосов
/ 19 декабря 2011

Для самого начала:

DECLARE @E TABLE
(
    id BIGINT PRIMARY KEY,
    name varchar(50)
)

DECLARE @R TABLE
(
    child_id bigint,
    parent_id BIGINT,
    PRIMARY KEY(child_id, parent_id),
    UNIQUE (parent_id, child_id)
)

Но имейте в виду, что Sql Server очень плохо оптимизирует CTE.

...