On 03/01/2018 05:37 PM, Adrián Medraño Calvo wrote:
Dear SQLite,

The following SQL script shows a query selecting data from a recursive CTE and 
filtering it.  I expected the optimizer to apply the filter to the recursive 
CTE directly, and indeed the documentation of pushDownWhereTerms 
(src/select.c:3833) indicates this possibility when various conditions are 
satisfied.  As far as I can see, the conditions are satisfied, but the query is 
nonetheless not optimized.  This indicates a misunderstanding on my part, or an 
oversight in SQLite.

-- A table containing some numbers.
CREATE TABLE t (v INT PRIMARY KEY);
INSERT INTO t
VALUES (0), (1), (2), (3), (4), (5);

-- Recursive query relating a number a sequence of numbers from "t" equal or
-- greater than it.
EXPLAIN QUERY PLAN
WITH RECURSIVE
eqgrseq(initial, next) AS (SELECT v, v
                            FROM   t
                            UNION
                            SELECT eqgrseq.initial, t.v
                            FROM   eqgrseq
                            JOIN   t
                            ON     (t.v = eqgrseq.next + 1))
SELECT eqgrseq.initial, eqgrseq.next
FROM   eqgrseq
WHERE  eqgrseq.initial = :initial;


It's quite a special case really. You can push the WHERE term down only because it refers to a column that is always copied without modification from the initial result set into any recursive results. You could not push down a term like:

  WHERE eqgrseq.next = :next:

Dan.






-- selectid,order,from,detail
-- 2,0,0,"SCAN TABLE t"
-- 3,0,0,"SCAN TABLE eqgrseq"
-- 3,1,1,"SEARCH TABLE t USING COVERING INDEX sqlite_autoindex_t_1 (v=?)"
-- 1,0,0,"COMPOUND SUBQUERIES 0 AND 0 USING TEMP B-TREE (UNION)"
-- 0,0,0,"SCAN SUBQUERY 1”

-- The same query with the WHERE condition manually placed in the recursive 
CTE's
-- initial clause.
EXPLAIN QUERY PLAN
WITH RECURSIVE
eqgrseq(initial, next) AS (SELECT v, v
                            FROM   t
                            WHERE v = :initial
                            UNION
                            SELECT eqgrseq.initial, t.v
                            FROM   eqgrseq
                            JOIN   t
                            ON     (t.v = eqgrseq.next + 1))
SELECT eqgrseq.initial, eqgrseq.next
FROM   eqgrseq
WHERE  eqgrseq.initial = :initial;
-- selectid,order,from,detail
-- 2,0,0,"SEARCH TABLE t USING COVERING INDEX sqlite_autoindex_t_1 (v=?)"
-- 3,0,0,"SCAN TABLE eqgrseq"
-- 3,1,1,"SEARCH TABLE t USING COVERING INDEX sqlite_autoindex_t_1 (v=?)"
-- 1,0,0,"COMPOUND SUBQUERIES 0 AND 0 USING TEMP B-TREE (UNION)"
-- 0,0,0,"SCAN SUBQUERY 1”

Note the query plan difference: the first scans the “t” table, therefore 
recurses for every value, while the second only recurses for the filtered ones.

In our application, the recursive CTE is hidden behind a view in order to 
abstract over the details; manually inserting the WHERE clause would not be 
possible while maintaining the view, as far as I can see.

Thank you,
Adrián.
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to