您好我有一个存储数据映射的表,例如
Data Map
id | letter | type l | r
------------------ -----
1 | AA | HEAD 5 | 1
2 | BB | HEAD 2 | 1
3 | CC | HEAD 6 | 2
4 | DD | HEAD 3 | 2
5 | END-1 | END 7 | 3
6 | END-2 | END 8 | 4
7 | END-3 | END
8 | END-4 | END
请参阅http://sqlfiddle.com/#!3/4eccfe/5
我想找出来自给定来源的所有END类型链接,例如对于AA,我得到END-1,END-2,END-3;对于BB,我得到END-1,END-2,END-3;对于CC,我得到END-1,END-2,END-3;对于DD,我得到END-4
我用递归CTE写了我想要的东西:
;WITH data(id, letter, type) AS (
SELECT '1', 'AA', 'HEAD' UNION SELECT '2', 'BB', 'HEAD' UNION SELECT '3', 'CC', 'HEAD' UNION
SELECT '4', 'DD', 'HEAD' UNION SELECT '5', 'END-1', 'END' UNION SELECT '6', 'END-2', 'END' UNION
SELECT '7', 'END-3', 'END' UNION SELECT '8', 'END-4', 'END'
), map (l, r) AS (
SELECT '5', '1' UNION SELECT '2', '1' UNION
SELECT '6', '2' UNION SELECT '3', '2' UNION
SELECT '7', '3' UNION SELECT '8', '4'
), my_list (origin, source, target, target_type, sid, tid, level) AS (
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s JOIN map ON (s.id = l OR s.id = r)
JOIN data t ON (t.id = l OR t.id = r)
WHERE t.id <> s.id AND s.type <> 'END'
UNION ALL
SELECT my_list.origin, s.letter, t.letter, t.type, s.id, t.id, level + 1
FROM data s JOIN map ON (s.id = l OR s.id = r)
JOIN data t ON (t.id = l OR t.id = r) JOIN my_list ON s.id = my_list.tid
WHERE t.id <> s.id AND s.type <> 'END' AND t.id <> my_list.sid
)
SELECT * FROM my_list
WHERE origin = 'BB' AND target_type = 'END'
ORDER BY level
GO
但表现并不是很好(在我真实的桌子上)。然后我意识到连接条件中的OR是导致问题的,然后我尝试使用UNION
my_list (origin, source, target, target_type, sid, tid, level) AS (
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s JOIN map ON s.id = l JOIN data t ON t.id = r
WHERE s.type <> 'END'
UNION ALL
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s JOIN map ON s.id = r JOIN data t ON t.id = l
WHERE s.type <> 'END'
UNION ALL
SELECT my_list.origin, s.letter, t.letter, t.type, s.id, t.id, level + 1
FROM data s JOIN map ON (s.id = l OR s.id = r)
JOIN data t ON (t.id = l OR t.id = r) JOIN my_list ON s.id = my_list.tid
WHERE t.id <> s.id AND s.type <> 'END' AND t.id <> my_list.sid
)
差别很大(在我的真实桌子上,时间缩短了一半)。对于上面的例子,我得到了
Table 'Worktable'. Scan count 6, logical reads 100
VS
Table 'Worktable'. Scan count 5, logical reads 75
但是当我尝试为递归部分做同样的事情时,例如
my_list (origin, source, target, target_type, sid, tid, level) AS (
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s JOIN map ON s.id = l JOIN data t ON t.id = r
WHERE s.type <> 'END'
UNION ALL
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s JOIN map ON s.id = r JOIN data t ON t.id = l
WHERE s.type <> 'END'
UNION ALL
SELECT my_list.origin, s.letter, t.letter, t.type, s.id, t.id, level + 1
FROM data s JOIN map ON s.id = l
JOIN data t ON t.id = r JOIN my_list ON s.id = my_list.tid
WHERE s.type <> 'END' AND t.id <> my_list.sid
UNION ALL
SELECT my_list.origin, s.letter, t.letter, t.type, s.id, t.id, level + 1
FROM data s JOIN map ON s.id = r
JOIN data t ON t.id = l JOIN my_list ON s.id = my_list.tid
WHERE s.type <> 'END' AND t.id <> my_list.sid
)
结果变慢(在我的真实桌子上,慢5倍)。
我想知道为什么它会变慢并且是否有其他方法可以摆脱OR以加快查询速度?数据库是MS SQL SERVER 2008R2
谢谢
答案 0 :(得分:1)
我可能错了,但你不能推断谓词:
WHERE origin = 'BB'
在CTE里面。即:
;WITH my_list (origin, source, target, target_type, sid, tid, level) AS (
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s
JOIN map
ON s.id = l
JOIN data t
ON t.id = r
WHERE s.letter = 'BB'
UNION ALL
SELECT s.letter, s.letter, t.letter, t.type, s.id, t.id, 0
FROM data s
JOIN map
ON s.id = r
JOIN data t
ON t.id = l
WHERE s.letter = 'BB'
UNION ALL
SELECT my_list.origin, s.letter, t.letter, t.type, s.id, t.id, level + 1
FROM data s
JOIN map
ON (s.id = l OR s.id = r)
JOIN data t
ON (t.id = l OR t.id = r)
JOIN my_list
ON s.id = my_list.tid
WHERE t.id <> s.id
AND s.type <> 'END'
AND t.id <> my_list.sid
)
SELECT * FROM my_list
WHERE origin = 'BB' AND target_type = 'END'
ORDER BY level
这会提高性能吗?