У меня есть список уведомлений (заметок), которые отправляются пользователям для проверки. Эти заметки могут быть связаны друг с другом родительским / дочерним образом, где одно уведомление является дочерним по отношению к более раннему уведомлению. Не у каждой заметки есть родитель. Всего около 22 000 записей.
Note Parent Note
1 NULL
2 NULL
3 1
4 NULL
5 NULL
6 3
7 4
Я хотел бы построить дерево этих уведомлений, проследив до самого начала, чтобы показать, насколько глубоки «дочерние» уведомления и сколько других уведомлений применяются к этому конкретному. Желаемый результат работы приведенной выше таблицы будет выглядеть примерно так:
Note Parent Note Level Full List
1 NULL 1 1
2 NULL 1 2
3 1 2 1/3
4 NULL 1 4
5 NULL 1 5
6 3 3 1/3/6
7 4 2 4/7
Каждый раз, когда открывается новое дочернее уведомление, уровень увеличивается на единицу и объединяется с предыдущим списком уведомлений.
Я пытался использовать рекурсивный CTE для достижения этой цели. Вот как выглядит запрос.
WITH CTE AS (
SELECT Note,
Parent_Note,
1 as Level,
--Cast as nvarchar to keep data types the same
CAST(QNote as nvarchar(MAX)) as Full_List
FROM Notifications
WHERE Parent_Note IS NULL
UNION ALL
SELECT Notifications.Note,
CTE.Note as Parent_Note,
Level = CTE.Level + 1,
CAST(Full_List + '/' + Notifications.Note as nvarchar(MAX)) as Full_List
FROM CTE INNER JOIN Notifications ON CTE.Note = Notifications.Parent_Note)
SELECT * FROM CTE
К сожалению, этот запрос занимает около 15 минут, чтобы пройти через 5 записей на втором «уровне» уведомлений.
Однако, если я жестко закодирую каждую рекурсию, я могу получить полный набор данных для загрузки менее чем за 30 секунд.
WITH CTE1 AS (
SELECT Note,
Parent_Note,
1 as Level,
--Cast as nvarchar to keep data types the same
CAST(QNote as nvarchar(MAX)) as Full_List
FROM Notifications
WHERE Parent_Note IS NULL
),
CTE2 AS (
SELECT Notifications.Note,
CTE1.Note as Parent_Note,
Level = CTE1.Level + 1,
CAST(Full_List + '/' + Notifications.Note as nvarchar(MAX)) as Full_List
FROM CTE1 INNER JOIN Notifications ON CTE1.Note = Notifications.Parent_Note
),
CTE3 AS (
SELECT Notifications.Note,
CTE2.Note as Parent_Note,
Level = CTE2.Level + 1,
CAST(Full_List + '/' + Notifications.Note as nvarchar(MAX)) as Full_List
FROM CTE2 INNER JOIN Notifications ON CTE2.Note = Notifications.Parent_Note
)
SELECT * FROM CTE1 UNION SELECT * FROM CTE2 UNION SELECT * FROM CTE3
Я не совсем понимаю, почему рекурсивный запрос настолько медленный, что не загружается, а жестко запрограммированный запрос загружает данные менее чем за 30 секунд. Я также не хочу использовать жестко запрограммированный запрос, потому что я не уверен, сколько «уровней» в конечном итоге будет существовать, хотя текущий максимум составляет всего шесть.
Буду признателен за любую информацию, которой может поделиться кто-либо, и, хотя я, возможно, не смогу полностью предоставить информацию, чтобы помочь ответить на вопрос (задавая этот вопрос для запросов на работе, поэтому не могу поделиться данными / планами запросов), я буду обязательно предоставлю то, что могу.