On Sun, Jun 1, 2014 at 7:25 AM, Bert Huijben <rhuij...@apache.org> wrote:

>         Hi,
>
> I just tested Sqlite 3.8.5 on Subversion's schema and found that one of our
> queries started using a temporary B-Tree while executing, which it didn't
> use in any older Sqlite version. I wouldn't expect a usage of a temporary
> table as the data is already properly ordered when it uses the primary key
> index.
>

Thanks for the beta test!

The unnecessary B-Tree was being used to sort the "SELECT ?2" query - the
one without a FROM clause.  Since that query only returns one row, the
sorting is pointless.  But it is also harmless in the sense that it still
gives the correct answer and the extra work of creating a B-Tree for a
single row does not cost many CPU cycles.  The fact that it is harmless and
does not noticeably impact performance is why this did not show up in our
internal tests.

Nevertheless, it is good to find and fix this sort of thing, so the problem
has now been resolved, and new tests have been added to prevent a
recurrence.  Thanks for the report!

New snapshots are available on the main download page:
http://www.sqlite.org/download.html



>
> The query in its readable form is:
> [[
> INSERT INTO delete_list(local_relpath)
> SELECT ?2
> UNION ALL
> SELECT local_relpath FROM nodes AS n
> WHERE wc_id = ?1
>   AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
>   AND op_depth >= ?3
>   AND op_depth = (SELECT MAX(s.op_depth) FROM nodes AS s
>                   WHERE s.wc_id = ?1
>                     AND s.local_relpath = n.local_relpath)
>   AND presence NOT IN (MAP_BASE_DELETED, MAP_NOT_PRESENT, MAP_EXCLUDED,
> MAP_SERVER_EXCLUDED)
>   AND file_external IS NULL
> ORDER by local_relpath
> ]]
>
> The actual query passed to sqlite is:
>  [[
> INSERT INTO delete_list(local_relpath) SELECT ?2 UNION ALL SELECT
> local_relpath FROM nodes AS n WHERE wc_id = ?1   AND (((local_relpath) >
> (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) <
> CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))   AND op_depth >= ?3
> AND op_depth = (SELECT MAX(s.op_depth) FROM nodes AS s
> WHERE s.wc_id = ?1                     AND s.local_relpath =
> n.local_relpath)   AND presence NOT IN ('base-deleted', 'not-present',
> 'excluded', 'server-excluded')   AND file_external IS NULL ORDER by
> local_relpath
> ]]
>
> The query plan in 3.8.5-201405271818 is:
> [[
> USE TEMP B-TREE FOR ORDER BY
> SEARCH TABLE nodes AS n USING INDEX sqlite_autoindex_NODES_1 (wc_id=? AND
> local_relpath>? AND local_relpath<?)
> EXECUTE CORRELATED SCALAR SUBQUERY 3
> SEARCH TABLE nodes AS s USING COVERING INDEX sqlite_autoindex_NODES_1
> (wc_id=? AND local_relpath=?)
> EXECUTE LIST SUBQUERY 4
> COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)
> ]]
>
> In 3.7.17 and 3.8.4 it was:
> [[
> 2|0|0|SEARCH TABLE nodes AS n USING INDEX sqlite_autoindex_NODES_1 (wc_id=?
> AND
> local_relpath>? AND local_relpath<?)
> 2|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 3
> 3|0|0|SEARCH TABLE nodes AS s USING COVERING INDEX sqlite_autoindex_NODES_1
> (wc_
> id=? AND local_relpath=?)
> 2|0|0|EXECUTE LIST SUBQUERY 4
> 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)
> ]]
>
> Relevant schema:
> [[
> CREATE TEMPORARY TABLE delete_list (
>    local_relpath TEXT PRIMARY KEY NOT NULL UNIQUE
> )
>
> CREATE TABLE NODES (
> wc_id  INTEGER NOT NULL REFERENCES WCROOT (id),
> local_relpath  TEXT NOT NULL,
> op_depth INTEGER NOT NULL,
> parent_relpath  TEXT,
> repos_id  INTEGER REFERENCES REPOSITORY (id),
> repos_path  TEXT,
> revision  INTEGER,
> presence  TEXT NOT NULL,
> moved_here  INTEGER,
> moved_to  TEXT,
> kind  TEXT NOT NULL,
> properties  BLOB,
> depth  TEXT,
> checksum  TEXT REFERENCES PRISTINE (checksum),
> symlink_target  TEXT,
> changed_revision  INTEGER,
> changed_date      INTEGER,
> changed_author    TEXT,
> translated_size  INTEGER,
> last_mod_time  INTEGER,
> dav_cache  BLOB,
> file_external  INTEGER,
> inherited_props  BLOB,
> PRIMARY KEY (wc_id, local_relpath, op_depth)   );
> CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath,
> local_relpath, op_depth);
> CREATE UNIQUE INDEX I_NODES_MOVED ON NODES (wc_id, moved_to, op_depth);
> INSERT INTO "sqlite_stat1" VALUES('NODES','sqlite_autoindex_NODES_1','8000
> 8000 2 1');
> INSERT INTO "sqlite_stat1" VALUES('NODES','I_NODES_PARENT','8000 8000 10 2
> 1');
> INSERT INTO "sqlite_stat1" VALUES('NODES','I_NODES_MOVED','8000 8000 1 1');
> ]]
>
>         Bert
>
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@sqlite.org
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
>



-- 
D. Richard Hipp
d...@sqlite.org
_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to