在我需要处理的事情中,在给定的时间,我需要找到具有0或1个子节点的树的所有节点(使用物化路径+相邻节点制作)。 列类似于:
id int
parent_node int
treepath VARCHAR(255)
deepness int
当我尝试提出解决方案时,我只能想到使用太多子查询或表连接的非常复杂的查询。
对于有0个孩子的节点,我一直在考虑搜索未被parent_id引用并且在子树内的所有节点。
SELECT *
FROM user_tree
WHERE
node_id NOT IN (
SELECT parent_id
FROM user_tree
WHERE parent_id IS NOT NULL
)
AND
treepath LIKE
(
SELECT CONCAT(treepath, '/%')
FROM user_tree
WHERE node_id = 4
)
使用EXPLAIN,这似乎对数据库有点痛苦,因为它需要多长时间才能获得节点列表。
是否有一种非常痛苦的方式(在性能上)来创建一个查找我想要的内容?
编辑:
根据要求,这里有一些表格的样本格式:
id parent_id treepath deepness
1 NULL 1 0
2 NULL 2 0
3 1 1/3 1
4 1 1/4 1
5 4 1/4/5 2
7 3 1/3/7 2
8 3 1/3/8 2
9 7 1/3/7/11 3
答案 0 :(得分:2)
没有样本数据,这只是一个猜测:
SELECT t1.*, t2.numchildren
FROM user_tree t1
LEFT JOIN ( SELECT parent_id, COUNT(*) AS numchildren
FROM user_tree
GROUP BY parent_id ) t2
ON t1.id = t2.parent_id
WHERE t2.numchildren IS NULL
OR t2.numchildren = 1;
答案 1 :(得分:1)
查询
SELECT parent_id, COUNT(id) AS n FROM user_tree GROUP BY parent_id HAVING n = 1
找到有一个孩子的父母。您可能想要添加INDEX(parent_id)。
查询
SELECT id FROM user_tree WHERE id NOT IN (SELECT DISTINCT parent_id FROM user_tree)
找到树叶。相同的索引会有所帮助。
答案 2 :(得分:0)
您的查询逻辑是正确的。我会将条件移到from
子句,因为这通常会更好地优化:
SELECT ut.*
FROM user_tree ut join
(select CONCAT(treepath, '/%') as treepath4
FROM user_tree
WHERE node_id = 4
) node4
on ut.treepath LIKE node4.treepath4 left outer join
user_tree child
on child.parent_id = ut.node_id
WHERE ut.treepath LIKE node4.treepath4 and
child.node_id is null;
对于0或1个孩子:
SELECT ut.*
FROM user_tree ut join
(select CONCAT(treepath, '/%') as treepath4
FROM user_tree
WHERE node_id = 4
) node4
on ut.treepath LIKE node4.treepath4 left outer join
user_tree child
on child.parent_id = ut.node_id
GROUP BY ut.node_id
HAVING count(child.node_id) in (0, 1);
答案 3 :(得分:0)
或者,您可以向表中添加新字段children_count
。这将大规模优化此特定查询。但是你会在添加/删除节点上浪费一些时间。