如何创建在第一行中正确使用索引的sqlite递归视图

时间:2018-08-10 18:03:18

标签: sqlite view query-optimization

我们正在使用sqlite 3.16.0版。

我想创建一些视图以简化我在架构上执行的一些常见的递归操作。但是,与直接运行SQL相比,这些视图要慢得多。

具体来说,该视图向我显示给定节点的祖先:

CREATE VIEW ancestors AS
        WITH RECURSIVE ancestors
             (
                   leafid
                 , parentid
                 , name
                 , depth
             )
             AS
             (SELECT id
                   , parentid
                   , name
                   , 1
                FROM objects
               UNION ALL
              SELECT a.leafid
                   , f.parentid
                   , f.name
                   , a.depth + 1
                FROM objects f
                JOIN ancestors         a
                  ON f.id = a.parentid
        ) ;

与此查询一起使用时:

SELECT *
  FROM ancestors
 WHERE leafid = 157609;

产生以下结果:

sele  order          from  deta
----  -------------  ----  ----
2     0              0     SCAN TABLE objects
3     0              1     SCAN TABLE ancestors AS a
3     1              0     SEARCH TABLE objects AS f USING INTEGER PRIMARY KEY (rowid=?)
1     0              0     COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)
0     0              0     SCAN SUBQUERY 1

Run Time: real 0.374 user 0.372461 sys 0.001483

但是直接运行查询(对同一行的初始查询具有WHERE约束),会产生:

        WITH RECURSIVE ancestors
             (
                   leafid, parentid, name, depth
             )
             AS
             (SELECT id, parentid , name,  1
                FROM objects
               WHERE id = 157609
             UNION ALL
             SELECT a.leafid, f.parentid , f.name, a.depth + 1
               FROM objects f
               JOIN ancestors         a
                 ON f.id = a.parentid
             )
       SELECT *
         FROM ancestors;

Run Time: real 0.021 user 0.000249 sys 0.000111

sele  order          from  deta
----  -------------  ----  ----
2     0              0     SEARCH TABLE objects USING INTEGER PRIMARY KEY (rowid=?)
3     0              1     SCAN TABLE ancestors AS a
3     1              0     SEARCH TABLE objects AS f USING INTEGER PRIMARY KEY (rowid=?)
1     0              0     COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)
0     0              0     SCAN SUBQUERY 1

第二个结果大约快15倍,因为我们在对象上使用PK索引来获取初始行,而视图似乎扫描了整个表,仅在找到所有行的祖先后才在叶节点上进行过滤

有什么方法可以编写视图,以便可以对将用于优化初始查询的消费选择施加约束?

1 个答案:

答案 0 :(得分:0)

您要在第一个子查询中移动WHERE leafid = 157609。这是push-down optimization,SQLite会尽可能尝试这样做。

但是,只有在数据库能够证明结果相同的情况下才有可能。对于这个特定的查询,您知道该转换是有效的,但是目前,尚无算法可以为递归CTE提供这种证明。