我有一个SQLite数据库,其中包含带有红色和黑色节点的树(尽管不是红黑树)。树存储为嵌套集(https://en.wikipedia.org/wiki/Nested_set_model)
Name TreeId Left Right IsBlack
A 1 1 8 1
B 1 2 7 0
C 1 3 6 1
D 1 4 5 1
A 2 1 10 1
B 2 2 5 0
C 2 6 9 1
D 2 3 4 1
D 2 7 8 1
TreeId = 2的B和C节点都指向D节点。所以D被写了两次。
这些树可能只包含黑色或红色节点
我想为指定节点选择不包含红色节点的所有路径。 e。从结果中排除红色节点及其所有子树
示例:
记录下来:
Name TreeId Left Right IsBlack
A 1 1 8 1
结果将是:
Name TreeId Left Right IsBlack
A 1 1 8 1
记录下来:
Name TreeId Left Right IsBlack
C 1 3 6 1
结果将是:
Name TreeId Left Right IsBlack
C 1 3 6 1
D 1 4 5 1
最后,记录下来:
Name TreeId Left Right IsBlack
A 2 1 10 1
结果将是:
Name TreeId Left Right IsBlack
A 2 1 10 1
C 2 6 9 1
D 2 7 8 1
为简单起见,我们假设存在另一个查询,该查询按其名称选择搜索节点的TreeId,Left和Right参数。
所以我想出了以下查询(针对节点A):
SELECT Nodes.* FROM Nodes
LEFT JOIN Nodes as n ON Nodes.[TreeId] = n.TreeId AND n.IsBlack = 0 AND Nodes.Left >= n.Left AND Nodes.Right <= n.Right
AND n.Left >= 1 AND n.Right <= 10
WHERE Nodes.TreeId = 2 AND Nodes.Left >= 1 AND Nodes.[Right] <= 10 AND n.Name IS NULL
该查询似乎可以正常运行,但是由于即使有索引也可以进行左联接,因此查询速度非常慢。
所以我在想,是否有一种方法可以根据SQLite来优化查询,避免左连接(例如,使用内部连接,联合等)
P.S。我无法更改数据的存储方式,但是可以修改数据库架构(添加新字段)。
P.P.S。我了解,我可以查询所有结果,然后在代码端对其进行过滤。另一种选择是在db中存储两种类型的树:一种具有红色和黑色节点,另一种仅具有黑色节点。但是,这两种解决方案都是不得已的方法。
预先感谢
答案 0 :(得分:1)
好吧,我不知道它是否会更快-不能只显示几行数据,但这是使用递归CTE至少获得与示例相同的结果:< / p>
WITH RECURSIVE n AS
(SELECT * FROM nodes WHERE name= ?1 AND treeid = ?2 AND isblack = 1
UNION ALL
SELECT n2.name, n2.treeid, n2.left, n2.right, n2.isblack
FROM n
JOIN nodes AS n2
ON n2.treeid = n.treeid
AND (n2.left = n.left + 1 OR n2.right = n.right - 1)
WHERE n2.isblack = 1)
SELECT * FROM n ORDER BY name
您可能希望在nodes(isblack, treeid, name)
上建立索引(并且不要忘记偶尔运行一次PRAGMA optimize。)绑定/替换?1
和?2
以及针对特定查询运行的明显值。