Some observations.  It seems the WHERE pushdown optimization you cited only
applies to subqueries with existing WHERE clause.  In your example without
WHERE, the SELECT specifies the whole table as the left hand side of the
UNION.  Scanning the whole table is likely more efficient than using an
index to retrieve every row.  Do you have a better example of the problem?


[Another suggestion in the form of a question:  Is the more efficient UNION
ALL completely ruled out because of duplicates?]

Peter





On Thu, Mar 1, 2018 at 2:37 AM, Adrián Medraño Calvo <amca...@prs.de> 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;
> -- 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