Jens Miltner wrote:
I have a schema similar to this:
CREATE TABLE foo (id integer primary key, name text);
CREATE TABLE bar (id integer primary key, foo_id integer, something
text);
CREATE INDEX bar_idx on bar(foo_id, something);
When I run a query like
SELECT
foo.id AS foo_id,
bar.id AS bar_id
FROM
bar
LEFT JOIN
foo ON foo.id=bar.foo_id
ORDER BY
bar.something
;
sqlite will only use the primary key index of foo
(as the output of 'explain query plan' shows:
0|0|TABLE bar
1|1|TABLE foo USING PRIMARY KEY
)
If I try to disable the foo primary key index by prefixing foo.id with
a '+' sign, no index will be used.
I'd have expected the bar_idx index to be used for the ORDER BY
clause? Or is this some unreasonable assumption?
Is there a way to enforce this?
Thanks,
</jum>
Jens,
Your query is not using any index to do the order by clause, it is
sorting the intermediate results.
There is no need to join the foo table in your query since the foo_id is
available in the bar table. The following is equivalent:
SELECT
foo_id,
bar.id AS bar_id
FROM
bar
ORDER BY
bar.something
;
It still does a sort as shown by the explain output
sqlite> .explain on
sqlite> explain SELECT
...> foo_id,
...> bar.id AS bar_id
...> FROM
...> bar
...> ORDER BY
...> bar.something
...> ;
addr opcode p1 p2 p3
---- -------------- ---------- ----------
---------------------------------
0 OpenVirtual 1 3 keyinfo(1,BINARY)
1 Goto 0 28
2 Integer 0 0
3 OpenRead 0 3
4 SetNumColumns 0 3
5 Rewind 0 15
6 Column 0 1
7 Rowid 0 0
8 MakeRecord 2 0
9 Column 0 2
10 Sequence 1 0
11 Pull 2 0
12 MakeRecord 3 0
13 IdxInsert 1 0
14 Next 0 6
15 Close 0 0
16 OpenPseudo 2 0
17 SetNumColumns 2 2
18 Sort 1 26
19 Integer 1 0
20 Column 1 2
21 Insert 2 0
22 Column 2 0
23 Column 2 1
24 Callback 2 0
25 Next 1 19
26 Close 2 0
27 Halt 0 0
28 Transaction 0 0
29 VerifyCookie 0 3
30 Goto 0 2
31 Noop 0 0
sqlite> .explain off
sqlite> explain query plan SELECT
...> foo_id,
...> bar.id AS bar_id
...> FROM
...> bar
...> ORDER BY
...> bar.something
...> ;
0|0|TABLE bar
sqlite>
To use the index to do the oder by the index must start with the columns
used to order the output. If you create an index on the bar.something
column then it will be used to scan the bar table in order rather than
from start to finish by primary key id.
sqlite> create index bar_someting on bar(something);
sqlite> .explain on
sqlite> explain SELECT
...> foo_id,
...> bar.id AS bar_id
...> FROM
...> bar
...> ORDER BY
...> bar.something
...> ;
addr opcode p1 p2 p3
---- -------------- ---------- ----------
---------------------------------
0 Noop 0 0
1 Goto 0 19
2 Integer 0 0
3 OpenRead 0 3
4 SetNumColumns 0 3
5 Integer 0 0
6 OpenRead 2 5 keyinfo(1,BINARY)
7 Rewind 2 16
8 RowKey 2 0
9 IdxIsNull 0 15
10 IdxRowid 2 0
11 MoveGe 0 0
12 Column 0 1
13 Rowid 0 0
14 Callback 2 0
15 Next 2 8
16 Close 0 0
17 Close 2 0
18 Halt 0 0
19 Transaction 0 0
20 VerifyCookie 0 4
21 Goto 0 2
22 Noop 0 0
sqlite> .explain off
sqlite>
sqlite> explain query plan SELECT
...> foo_id,
...> bar.id AS bar_id
...> FROM
...> bar
...> ORDER BY
...> bar.something
...> ;
0|0|TABLE bar WITH INDEX bar_someting
sqlite>
HTH
Dennis Cote