Re: [sqlite] question about covering index
On 7 Feb 2018, at 1:31am, Mark Wagnerwrote: > Wow, I had no idea that the order of the columns in the index effects how > they're used. Must. Study. More. Just like a phone directory. If the order is (surname, firstname) then the first name in the directory is the one with the lowest surname, not the lowest firstname. This is why your covering index doesn't make sense. Simon. ___ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
Re: [sqlite] question about covering index
Note that if the _id column were not UNIQUE, then the SKIP-SCAN optimization might be used with index i if and only if you had (a) done an analyze and (b) the optimizer thought it might be worthwhile to do so. --- The fact that there's a Highway to Hell but only a Stairway to Heaven says a lot about anticipated traffic volume. >-Original Message- >From: sqlite-users [mailto:sqlite-users- >boun...@mailinglists.sqlite.org] On Behalf Of Mark Wagner >Sent: Tuesday, 6 February, 2018 18:32 >To: SQLite mailing list >Subject: Re: [sqlite] question about covering index > >Wow, I had no idea that the order of the columns in the index effects >how >they're used. Must. Study. More. > >On Tue, Feb 6, 2018 at 5:15 PM, Keith Medcalf <kmedc...@dessus.com> >wrote: > >> >> That said, however, the performance increase will be proportional >to the >> number of x values that are selected vs the number of rows in the >table. >> Unless the table is many orders of magnitude larger than the number >of >> similar x values you are searching for, the table scan will likely >be >> faster. Of course, you will also "pay" the extra index maintenance >and >> storage fee's, which may or may not outweigh the increase >conferred. >> >> --- >> The fact that there's a Highway to Hell but only a Stairway to >Heaven says >> a lot about anticipated traffic volume. >> >> >> >-Original Message- >> >From: sqlite-users [mailto:sqlite-users- >> >boun...@mailinglists.sqlite.org] On Behalf Of Keith Medcalf >> >Sent: Tuesday, 6 February, 2018 18:07 >> >To: SQLite mailing list >> >Subject: Re: [sqlite] question about covering index >> > >> > >> >Because your fields are backwards? >> > >> >x should come before _id (x is a row selector, _id is a grouping >> >selector), and the y cannot be used to sort (obviously) but can be >> >used to avoid the table lookup to feed the results into the temp >b- >> >tree sorter. >> > >> >sqlite> CREATE TABLE foo (_id integer primary key, x, y); >> >sqlite> CREATE INDEX i on foo(_id, x, y); >> >sqlite> CREATE INDEX j on foo(x, _id, y); >> >sqlite> CREATE INDEX k on foo(y, x, _id); >> >sqlite> .eqp on >> >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; >> >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) >> >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY >> >sqlite> .eqp full >> >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; >> >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) >> >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY >> >addr opcode p1p2p3p4 p5 comment >> > - - -- >--- >> >-- >> >0 Init 0 50000 Start at >50 >> >1 SorterOpen 1 5 0 k(1,B) 00 >> >2 Noop 2 3 000 >> >3 Integer0 5 000 r[5]=0; >> >clear abort flag >> >4 Integer0 4 000 r[4]=0; >> >indicate accumulator empty >> >5 Null 0 8 800 >> >r[8..8]=NULL >> >6 Gosub 7 39000 >> >7 OpenRead 3 4 0 k(4) 02 root=4 >> >iDb=0; j >> >8 Noop 0 0 000 Begin >> >WHERE-loop0: foo >> >9 CursorHint 3 0 0 EQ(c0,1) 00 >> >10Integer1 10000 r[10]=1 >> >11SeekGE 3 27101 00 >key=r[10] >> >12 IdxGT 3 27101 00 >key=r[10] >> >13 Noop 0 0 000 Begin >> >WHERE-core >> >14 IdxRowid 3 9 000 >> >r[9]=rowid >> >15 Compare8 9 1 k(1,B) 00 r[8] ><-> >> >r[9] >> >16 Jump 172117 00 >> >17 Move 9 8 100 >r[8]=r[9] >> >18 Gosub 6 32000 output >> >one row >> >19 IfPos 5 41000 if >r[5]>0 >> >then r[5]-=0, goto 41; check abort flag &
Re: [sqlite] question about covering index
Wow, I had no idea that the order of the columns in the index effects how they're used. Must. Study. More. On Tue, Feb 6, 2018 at 5:15 PM, Keith Medcalf <kmedc...@dessus.com> wrote: > > That said, however, the performance increase will be proportional to the > number of x values that are selected vs the number of rows in the table. > Unless the table is many orders of magnitude larger than the number of > similar x values you are searching for, the table scan will likely be > faster. Of course, you will also "pay" the extra index maintenance and > storage fee's, which may or may not outweigh the increase conferred. > > --- > The fact that there's a Highway to Hell but only a Stairway to Heaven says > a lot about anticipated traffic volume. > > > >-Original Message- > >From: sqlite-users [mailto:sqlite-users- > >boun...@mailinglists.sqlite.org] On Behalf Of Keith Medcalf > >Sent: Tuesday, 6 February, 2018 18:07 > >To: SQLite mailing list > >Subject: Re: [sqlite] question about covering index > > > > > >Because your fields are backwards? > > > >x should come before _id (x is a row selector, _id is a grouping > >selector), and the y cannot be used to sort (obviously) but can be > >used to avoid the table lookup to feed the results into the temp b- > >tree sorter. > > > >sqlite> CREATE TABLE foo (_id integer primary key, x, y); > >sqlite> CREATE INDEX i on foo(_id, x, y); > >sqlite> CREATE INDEX j on foo(x, _id, y); > >sqlite> CREATE INDEX k on foo(y, x, _id); > >sqlite> .eqp on > >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; > >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) > >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY > >sqlite> .eqp full > >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; > >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) > >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY > >addr opcode p1p2p3p4 p5 comment > > - - -- --- > >-- > >0 Init 0 50000 Start at 50 > >1 SorterOpen 1 5 0 k(1,B) 00 > >2 Noop 2 3 000 > >3 Integer0 5 000 r[5]=0; > >clear abort flag > >4 Integer0 4 000 r[4]=0; > >indicate accumulator empty > >5 Null 0 8 800 > >r[8..8]=NULL > >6 Gosub 7 39000 > >7 OpenRead 3 4 0 k(4) 02 root=4 > >iDb=0; j > >8 Noop 0 0 000 Begin > >WHERE-loop0: foo > >9 CursorHint 3 0 0 EQ(c0,1) 00 > >10Integer1 10000 r[10]=1 > >11SeekGE 3 27101 00 key=r[10] > >12 IdxGT 3 27101 00 key=r[10] > >13 Noop 0 0 000 Begin > >WHERE-core > >14 IdxRowid 3 9 000 > >r[9]=rowid > >15 Compare8 9 1 k(1,B) 00 r[8] <-> > >r[9] > >16 Jump 172117 00 > >17 Move 9 8 100 r[8]=r[9] > >18 Gosub 6 32000 output > >one row > >19 IfPos 5 41000 if r[5]>0 > >then r[5]-=0, goto 41; check abort flag > >20 Gosub 7 39000 reset > >accumulator > >21 IdxRowid 3 1 000 > >r[1]=rowid > >22 Column 3 0 200 > >r[2]=foo.x > >23 Column 3 2 300 > >r[3]=foo.y > >24 Integer1 4 000 r[4]=1; > >indicate data in accumulator > >25 Noop 0 0 000 End > >WHERE-core > >26Next 3 12000 > >27Noop 0 0 000 End WHERE- > >loop0: foo > >28Gosub 6 32000 output > >final row > >29Goto 0 41000 > >30Integer1 5 000 r[5]=1; set > >abort flag &
Re: [sqlite] question about covering index
That said, however, the performance increase will be proportional to the number of x values that are selected vs the number of rows in the table. Unless the table is many orders of magnitude larger than the number of similar x values you are searching for, the table scan will likely be faster. Of course, you will also "pay" the extra index maintenance and storage fee's, which may or may not outweigh the increase conferred. --- The fact that there's a Highway to Hell but only a Stairway to Heaven says a lot about anticipated traffic volume. >-Original Message- >From: sqlite-users [mailto:sqlite-users- >boun...@mailinglists.sqlite.org] On Behalf Of Keith Medcalf >Sent: Tuesday, 6 February, 2018 18:07 >To: SQLite mailing list >Subject: Re: [sqlite] question about covering index > > >Because your fields are backwards? > >x should come before _id (x is a row selector, _id is a grouping >selector), and the y cannot be used to sort (obviously) but can be >used to avoid the table lookup to feed the results into the temp b- >tree sorter. > >sqlite> CREATE TABLE foo (_id integer primary key, x, y); >sqlite> CREATE INDEX i on foo(_id, x, y); >sqlite> CREATE INDEX j on foo(x, _id, y); >sqlite> CREATE INDEX k on foo(y, x, _id); >sqlite> .eqp on >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY >sqlite> .eqp full >sqlite> SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; >--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX j (x=?) >--EQP-- 0,0,0,USE TEMP B-TREE FOR ORDER BY >addr opcode p1p2p3p4 p5 comment > - - -- --- >-- >0 Init 0 50000 Start at 50 >1 SorterOpen 1 5 0 k(1,B) 00 >2 Noop 2 3 000 >3 Integer0 5 000 r[5]=0; >clear abort flag >4 Integer0 4 000 r[4]=0; >indicate accumulator empty >5 Null 0 8 800 >r[8..8]=NULL >6 Gosub 7 39000 >7 OpenRead 3 4 0 k(4) 02 root=4 >iDb=0; j >8 Noop 0 0 000 Begin >WHERE-loop0: foo >9 CursorHint 3 0 0 EQ(c0,1) 00 >10Integer1 10000 r[10]=1 >11SeekGE 3 27101 00 key=r[10] >12 IdxGT 3 27101 00 key=r[10] >13 Noop 0 0 000 Begin >WHERE-core >14 IdxRowid 3 9 000 >r[9]=rowid >15 Compare8 9 1 k(1,B) 00 r[8] <-> >r[9] >16 Jump 172117 00 >17 Move 9 8 100 r[8]=r[9] >18 Gosub 6 32000 output >one row >19 IfPos 5 41000 if r[5]>0 >then r[5]-=0, goto 41; check abort flag >20 Gosub 7 39000 reset >accumulator >21 IdxRowid 3 1 000 >r[1]=rowid >22 Column 3 0 200 >r[2]=foo.x >23 Column 3 2 300 >r[3]=foo.y >24 Integer1 4 000 r[4]=1; >indicate data in accumulator >25 Noop 0 0 000 End >WHERE-core >26Next 3 12000 >27Noop 0 0 000 End WHERE- >loop0: foo >28Gosub 6 32000 output >final row >29Goto 0 41000 >30Integer1 5 000 r[5]=1; set >abort flag >31Return 6 0 000 >32IfPos 4 34000 if r[4]>0 >then r[4]-=0, goto 34; Groupby result generator entry point >33Return 6 0 000 >34Copy 1 12100 >r[12..13]=r[1..2] >35Copy 3 11000 r[11]=r[3] >36MakeRecord 113 15 00 >r[15]=mkrec(r[11..13]) >37SorterInsert 1 15113 00 key=r[15] >38Return 6 0 000 end groupb
Re: [sqlite] question about covering index
6 February, 2018 17:44 >To: SQLite mailing list >Subject: [sqlite] question about covering index > >Given the following schema: > >CREATE TABLE foo (_id integer primary key, x, y); >CREATE INDEX i on foo(_id, x, y); > >And the following query > >sqlite> EXPLAIN QUERY PLAN SELECT * FROM foo WHERE x=1 GROUP BY _id >ORDER >BY y; > >I would have expected it (hoped?) that it would use the covering >index for >the order by. Any clue why it doesn't or what I could do differently >to >get it to use an index for the selection, the grouping, and the >ordering? > >selectid = 0 > order = 0 >from = 0 > detail = SCAN TABLE foo > >selectid = 0 > order = 0 >from = 0 > detail = USE TEMP B-TREE FOR ORDER BY >___ >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
Re: [sqlite] question about covering index
OK, I oversimplified trying to make it easier. The real query has a join so I'm aggregating some of the columns. But this test case seemed to show the issue. I could show something closer to what I'm really doing if that explanation isn't sufficient. On Tue, Feb 6, 2018 at 4:48 PM, Simon Slavinwrote: > On 7 Feb 2018, at 12:43am, Mark Wagner wrote: > > > CREATE TABLE foo (_id integer primary key, x, y); > > CREATE INDEX i on foo(_id, x, y); > > > > And the following query > > > > sqlite> EXPLAIN QUERY PLAN SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER > > BY y; > > Why are you grouping on the primary key ? Primary key values must be, by > definition, unique. Grouping by a unique value means every group has one > entry. > > There's a similar problem with the index you created. Since the primary > key is first, there's no point in having the x and y in the index. > Therefore there's no point in having the index since it just duplicates the > primary key index for the table. > > I suspect that SQLite is acting weird because you fed it with weird things. > > Simon. > ___ > 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
Re: [sqlite] question about covering index
On 7 Feb 2018, at 12:43am, Mark Wagnerwrote: > CREATE TABLE foo (_id integer primary key, x, y); > CREATE INDEX i on foo(_id, x, y); > > And the following query > > sqlite> EXPLAIN QUERY PLAN SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER > BY y; Why are you grouping on the primary key ? Primary key values must be, by definition, unique. Grouping by a unique value means every group has one entry. There's a similar problem with the index you created. Since the primary key is first, there's no point in having the x and y in the index. Therefore there's no point in having the index since it just duplicates the primary key index for the table. I suspect that SQLite is acting weird because you fed it with weird things. Simon. ___ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users
[sqlite] question about covering index
Given the following schema: CREATE TABLE foo (_id integer primary key, x, y); CREATE INDEX i on foo(_id, x, y); And the following query sqlite> EXPLAIN QUERY PLAN SELECT * FROM foo WHERE x=1 GROUP BY _id ORDER BY y; I would have expected it (hoped?) that it would use the covering index for the order by. Any clue why it doesn't or what I could do differently to get it to use an index for the selection, the grouping, and the ordering? selectid = 0 order = 0 from = 0 detail = SCAN TABLE foo selectid = 0 order = 0 from = 0 detail = USE TEMP B-TREE FOR ORDER BY ___ sqlite-users mailing list sqlite-users@mailinglists.sqlite.org http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users