Re: [sqlite] SQLite does not use opportunity to optimise COUNT() queries using partial indexes

2016-12-01 Thread Paul
Thanks!

That explains a lot. For some reason I thought that 'SELECT COUNT() FROM 
' is optimised. 

 
> Gonna take a stab and answering this.
> http://www.sqlite.org/opcode.html
> 
> The explain output for select count() from foo; uses the "Count" opcode. The 
> description for that is
> "Store the number of entries (an integer value) in the table or index opened 
> by cursor P1 in register P2"
> So that is indeed going to scan through the whole table, as the OpenRead was 
> pointed to the table B-tree and not the index B-tree.
> 
> In the second case "select count() from foo where ref_count = 0" the OpenRead 
> opens up the index (p4 isn't an integer) so that is indeed going through the 
> index.
> 
> Remember also that you can get a more succinct explain by using "explain 
> query plan".
> 
> Here's the output of me running this in a CLI I compiled with the pretty 
> explain comments. Using .eqp full it outputs the "explain query plan" 
> results, then the "explain" results, then the query results.
> 
> (Hmm, random note: It looks like ".eqp full" makes it disregard ".header on" 
> when it gets down to outputting the results. Downgrading to only ".eqp on" 
> respects the ".header on" though.)
> 
> SQLite version 3.15.1 2016-11-04 12:08:49
> Enter ".help" for usage hints.
> Connected to a transient in-memory database.
> Use ".open FILENAME" to reopen on a persistent database.
> 
> sqlite> create table foo (id integer primary key, ref_count integer not null);
> 
> sqlite> create index foo_ref_count_idx on foo (ref_count) where ref_count = 0;
> 
> sqlite> .eqp full
> 
> sqlite> select count() from foo;
> --EQP-- 0,0,0,SCAN TABLE foo
> addr  opcode p1p2p3p4 p5  comment
>   -        -  --  -
> 0 Init   0 7 000  Start at 7
> 1 OpenRead   1 2 0 1  00  root=2 iDb=0
> 2 Count  1 1 000  r[1]=count()
> 3 Close  1 0 000
> 4 Copy   1 2 000  r[2]=r[1]
> 5 ResultRow  2 1 000  output=r[2]
> 6 Halt   0 0 000
> 7 Transaction0 0 2 0  01  usesStmtJournal=0
> 8 Goto   0 1 000
> 0
> 
> sqlite> select count() from foo where ref_count = 0;
> --EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX foo_ref_count_idx 
> (ref_count=?)
> addr  opcode p1p2p3p4 p5  comment
>   -        -  --  -
> 0 Init   0 13000  Start at 13
> 1 Null   0 1 100  r[1..1]=NULL
> 2 OpenRead   1 3 0 k(2,,) 02  root=3 iDb=0; 
> foo_ref_count_idx
> 3 Integer0 2 000  r[2]=0
> 4 SeekGE 1 8 2 1  00  key=r[2]
> 5   IdxGT  1 8 2 1  00  key=r[2]
> 6   AggStep0   0 0 1 count(0)   00  accum=r[1] 
> step(r[0])
> 7 Next   1 5 100
> 8 Close  1 0 000
> 9 AggFinal   1 0 0 count(0)   00  accum=r[1] N=0
> 10Copy   1 3 000  r[3]=r[1]
> 11ResultRow  3 1 000  output=r[3]
> 12Halt   0 0 000
> 13Transaction0 0 2 0  01  usesStmtJournal=0
> 14Goto   0 1 000
> 0
> 
> sqlite> select count() from foo where ref_count != 0;
> --EQP-- 0,0,0,SCAN TABLE foo
> addr  opcode p1p2p3p4 p5  comment
>   -        -  --  -
> 0 Init   0 13000  Start at 13
> 1 Null   0 1 100  r[1..1]=NULL
> 2 OpenRead   0 2 0 2  00  root=2 iDb=0; foo
> 3 Rewind 0 8 000
> 4   Column 0 1 200  r[2]=foo.ref_count
> 5   Eq 3 7 2 (BINARY)   54  if r[2]==r[3] 
> goto 7
> 6   AggStep0   0 0 1 count(0)   00  accum=r[1] 
> step(r[0])
> 7 Next   0 4 001
> 8 Close  0 0 000
> 9 AggFinal   1 0 0 count(0)   00  accum=r[1] N=0
> 10Copy   1 4 000  r[4]=r[1]
> 11ResultRow  4 1 000  output=r[4]
> 12Halt   0 0 000
> 13Transaction0 0 2 0  

Re: [sqlite] SQLite does not use opportunity to optimise COUNT() queries using partial indexes

2016-12-01 Thread David Raymond
Gonna take a stab and answering this.
http://www.sqlite.org/opcode.html

The explain output for select count() from foo; uses the "Count" opcode. The 
description for that is
"Store the number of entries (an integer value) in the table or index opened by 
cursor P1 in register P2"
So that is indeed going to scan through the whole table, as the OpenRead was 
pointed to the table B-tree and not the index B-tree.

In the second case "select count() from foo where ref_count = 0" the OpenRead 
opens up the index (p4 isn't an integer) so that is indeed going through the 
index.

Remember also that you can get a more succinct explain by using "explain query 
plan".

Here's the output of me running this in a CLI I compiled with the pretty 
explain comments. Using .eqp full it outputs the "explain query plan" results, 
then the "explain" results, then the query results.

(Hmm, random note: It looks like ".eqp full" makes it disregard ".header on" 
when it gets down to outputting the results. Downgrading to only ".eqp on" 
respects the ".header on" though.)

SQLite version 3.15.1 2016-11-04 12:08:49
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.

sqlite> create table foo (id integer primary key, ref_count integer not null);

sqlite> create index foo_ref_count_idx on foo (ref_count) where ref_count = 0;

sqlite> .eqp full

sqlite> select count() from foo;
--EQP-- 0,0,0,SCAN TABLE foo
addr  opcode p1p2p3p4 p5  comment
  -        -  --  -
0 Init   0 7 000  Start at 7
1 OpenRead   1 2 0 1  00  root=2 iDb=0
2 Count  1 1 000  r[1]=count()
3 Close  1 0 000
4 Copy   1 2 000  r[2]=r[1]
5 ResultRow  2 1 000  output=r[2]
6 Halt   0 0 000
7 Transaction0 0 2 0  01  usesStmtJournal=0
8 Goto   0 1 000
0

sqlite> select count() from foo where ref_count = 0;
--EQP-- 0,0,0,SEARCH TABLE foo USING COVERING INDEX foo_ref_count_idx 
(ref_count=?)
addr  opcode p1p2p3p4 p5  comment
  -        -  --  -
0 Init   0 13000  Start at 13
1 Null   0 1 100  r[1..1]=NULL
2 OpenRead   1 3 0 k(2,,) 02  root=3 iDb=0; 
foo_ref_count_idx
3 Integer0 2 000  r[2]=0
4 SeekGE 1 8 2 1  00  key=r[2]
5   IdxGT  1 8 2 1  00  key=r[2]
6   AggStep0   0 0 1 count(0)   00  accum=r[1] 
step(r[0])
7 Next   1 5 100
8 Close  1 0 000
9 AggFinal   1 0 0 count(0)   00  accum=r[1] N=0
10Copy   1 3 000  r[3]=r[1]
11ResultRow  3 1 000  output=r[3]
12Halt   0 0 000
13Transaction0 0 2 0  01  usesStmtJournal=0
14Goto   0 1 000
0

sqlite> select count() from foo where ref_count != 0;
--EQP-- 0,0,0,SCAN TABLE foo
addr  opcode p1p2p3p4 p5  comment
  -        -  --  -
0 Init   0 13000  Start at 13
1 Null   0 1 100  r[1..1]=NULL
2 OpenRead   0 2 0 2  00  root=2 iDb=0; foo
3 Rewind 0 8 000
4   Column 0 1 200  r[2]=foo.ref_count
5   Eq 3 7 2 (BINARY)   54  if r[2]==r[3] goto 7
6   AggStep0   0 0 1 count(0)   00  accum=r[1] 
step(r[0])
7 Next   0 4 001
8 Close  0 0 000
9 AggFinal   1 0 0 count(0)   00  accum=r[1] N=0
10Copy   1 4 000  r[4]=r[1]
11ResultRow  4 1 000  output=r[4]
12Halt   0 0 000
13Transaction0 0 2 0  01  usesStmtJournal=0
14Integer0 3 000  r[3]=0
15Goto   0 1 000
0


-Original Message-
From: sqlite-users [mailto:sqlite-users-boun...@mailinglists.sqlite.org] On 
Behalf Of Paul
Sent: Thursday, December 01,