2014-02-16 50 views
1

我正在使用递归语句来选择代表树结构条目的表中给定父项的所有子项。这是在Sqlite(它现在支持递归)。
这使我可以非常快速地选择树中的数千条记录,而不会因为从调用应用程序准备数千条选择语句而遭受巨大的性能损失。重复使用Sqlite中以下查询中的SQL查询的结果

WITH RECURSIVE q(Id) AS 
(
    SELECT Id FROM Entity 
    WHERE Parent=(?) 
    UNION ALL 
    SELECT m.Id FROM Entity AS m 
    JOIN Entity ON m.Id=q.Parent 
) 
SELECT Id FROM q; 

现在,假设我有任何数量的其他表中的这些实体的相关数据,我想随后加载。由于它们的任意数量(以模块化方式),因此不可能直接在这个数据中包含数据提取。他们必须遵循它。但是,如果对于每个相关的表,然后执行一条SELECT语句,那么直接在Sqlite中直接从树中选择所有数据的所有性能增益几乎是无用的,因为我仍然会在数千个随后的请求中停顿,并发出一个选择语句。

所以两个问题:

  1. 更好的解决办法是制定一个类似递归的语句为每个相关的表,这将递归地从这棵树上再次聚集实体,这次选择它们的相关数据加入它。 这听起来确实更有效率,但制定这样一个声明真的很棘手,我在这里有点失落。

  2. 现在真正的奥秘在于,会不会有一个更有效的解决方案,它将以某种方式将最后一个查询的结果缓存到某处(实体树中具有id的行)并将它们连接到在下面的语句中不需要递归迭代它呢?

这是第一个选项的尝试,假设我想从相关表中选择一个字段Data组件:是第二个UNION ALL合法吗?

WITH RECURSIVE q(Data) AS 
(
    SELECT Id FROM Entity 
    WHERE Parent=(?) 
    UNION ALL 
    SELECT m.Id FROM Entity AS m 
    JOIN Entity ON m.Id=q.Parent 
    UNION ALL 
    SELECT Data FROM Component AS c 
    JOIN Component ON c.Id=q.Id 
) 
SELECT Data FROM q; 

回答

1

documentation说:

2.命名的AS关键字的左侧必须从化合物的最右边的SELECT语句的WHERE子句中出现一次表选择,无处不在。

所以你的第二个查询是不合法的。

但是,CTE的行为像一个普通的表/视图,所以你可以把它加入相关的表:

WITH RECURSIVE q(Id) AS 
(...) 
SELECT q.Id, c.Data 
FROM q JOIN Component AS c ON q.Id = c.Id 

如果你想重用q对多个查询计算出的值,没有什么你可以用CTE来做,但你可以将它们存储在临时表中:

CREATE TEMPORARY TABLE q_123 AS 
WITH RECURSIVE q(Id) AS 
(...) 
SELECT Id FROM q; 

SELECT * FROM q_123 JOIN Component ...; 
SELECT * FROM q_123 JOIN Whatever ...; 

DROP TABLE q_123; 
+0

不错!你认为创建临时表的这种用例(10 000条记录)会比第一个选项更有趣吗?我会尝试这些解决方案并回复你 – MONK