On Wednesday, 2 January, 2019 16:58, Jonathan Moules
<[email protected]> wrote:
>Gah, sorry. Another typo. I really should be more awake when I post
>to this list. The non-simplified code does have the item_id on the
>subquery (otherwise it simply wouldn't execute at all of course). So:
>SELECT *
> FROM item_info
> JOIN (
> select
> count(1) as num,
> item_id
> from users
> group by item_id)
> USING (item_id)
> where item_id = ?;
Now perhaps we are getting somewhere. So now what exactly is your complaint?
You have asked for the following join to occur:
JOIN this table, which you can see by the following command:
select * from item_info
with the table that you can see by the following command:
select count(1) as num, item_id from users group by item_id
using the common column item_id in both tables
and then to return only the row where the item_id is the specific one provided.
So, the ONLY way to solve this is to generate the table on the RHS of the join
first, and then join it to the item_info table, and then return only the row
you have asked for. This produces the following plan:
CREATE TABLE users (
item_id TEXT REFERENCES item_info (item_id)
NOT NULL
COLLATE NOCASE,
some_data TEXT
);
CREATE INDEX users__item_id__idx ON users (
item_id
);
CREATE TABLE item_info (
item_id TEXT PRIMARY KEY ON CONFLICT IGNORE
NOT NULL
COLLATE NOCASE,
more_data TEXT
);
.eqp full
SELECT *
FROM item_info
JOIN (
select
count(1) as num,
item_id
from users
group by item_id)
USING (item_id)
where item_id = ?;
QUERY PLAN
|--MATERIALIZE 1
| `--SCAN TABLE users USING COVERING INDEX users__item_id__idx (~1048576 rows)
|--SEARCH TABLE item_info USING INDEX sqlite_autoindex_item_info_1 (item_id=?)
(~1 row)
`--SCAN SUBQUERY 1 (~96 rows)
addr opcode p1 p2 p3 p4 p5 comment
---- ------------- ---- ---- ---- ------------- -- -------------
0 Init 0 77 0 00 Start at 77
1 Integer 45 1 0 00 r[1]=45
2 Once 0 45 0 00 materialize
"subquery_1"
3 OpenEphemeral 1 2 0 00 nColumn=2
4 Noop 3 1 0 00
5 Integer 0 5 0 00 r[5]=0; clear abort
flag
6 Null 0 8 8 00 r[8..8]=NULL
7 Gosub 7 42 0 00
8 OpenRead 4 3 0 k(2,NOCASE,) 00 root=3 iDb=0;
users__item_id__idx
9 ColumnsUsed 4 0 0 1 00
10 Explain 10 0 0 SCAN TABLE users USING COVERING INDEX
users__item_id__idx (~1048576 rows) 00
11 Noop 0 0 0 00 Begin WHERE-loop0:
users
12 Rewind 4 28 10 0 00
13 Noop 0 0 0 00 Begin WHERE-core
14 Column 4 0 9 00 r[9]=users.item_id
15 Compare 8 9 1 k(1,NOCASE) 00 r[8] <-> r[9]
16 Jump 17 21 17 00
17 Move 9 8 1 00 r[8]=r[9]
18 Gosub 6 33 0 00 output one row
19 IfPos 5 45 0 00 if r[5]>0 then
r[5]-=0, goto 45; check abort flag
20 Gosub 7 42 0 00 reset accumulator
21 Integer 1 10 0 00 r[10]=1
22 AggStep 0 10 2 count(1) 01 accum=r[2]
step(r[10])
23 If 4 25 0 00
24 Column 4 0 3 00 r[3]=users.item_id
25 Integer 1 4 0 00 r[4]=1; indicate
data in accumulator
26 Noop 0 0 0 00 End WHERE-core
27 Next 4 13 0 01
28 Noop 0 0 0 00 End WHERE-loop0: users
29 Gosub 6 33 0 00 output final row
30 Goto 0 45 0 00
31 Integer 1 5 0 00 r[5]=1; set abort flag
32 Return 6 0 0 00
33 IfPos 4 35 0 00 if r[4]>0 then
r[4]-=0, goto 35; Groupby result generator entry point
34 Return 6 0 0 00
35 AggFinal 2 1 0 count(1) 00 accum=r[2] N=1
36 SCopy 2 11 0 00 r[11]=r[2]
37 SCopy 3 12 0 00 r[12]=r[3]
38 MakeRecord 11 2 10 00 r[10]=mkrec(r[11..12])
39 NewRowid 1 13 0 00 r[13]=rowid
40 Insert 1 10 13 08 intkey=r[13]
data=r[10]
41 Return 6 0 0 00 end groupby result
generator
42 Null 0 2 3 00 r[2..3]=NULL
43 Integer 0 4 0 00 r[4]=0; indicate
accumulator empty
44 Return 7 0 0 00
45 Return 1 0 0 00 end subquery_1
46 OpenRead 0 4 0 2 02 root=4 iDb=0;
item_info
47 ColumnsUsed 0 0 0 3 00
48 OpenRead 5 5 0 k(1,NOCASE) 02 root=5 iDb=0;
sqlite_autoindex_item_info_1
49 ColumnsUsed 5 0 0 1 00
50 Explain 50 0 0 SEARCH TABLE item_info USING INDEX
sqlite_autoindex_item_info_1 (item_id=?) (~1 row) 00
51 Noop 0 0 0 00 Begin WHERE-loop0:
item_info
52 CursorHint 5 0 0 EQ(c0,expr) 00
53 Variable 1 14 0 00 r[14]=parameter(1,)
54 IsNull 14 75 0 00 if r[14]==NULL goto 75
55 Affinity 14 1 0 B 00 affinity(r[14])
56 SeekGE 5 75 14 1 00 key=r[14]
57 IdxGT 5 75 14 1 00 key=r[14]
58 DeferredSeek 5 0 0 00 Move 0 to 5.rowid if
needed
59 Explain 59 0 0 SCAN SUBQUERY 1 (~96 rows) 00
60 Noop 0 0 0 00 Begin WHERE-loop1:
subquery_1
61 Column 5 0 15 00
r[15]=item_info.item_id
62 CursorHint 1 0 0 EQ(r[15],c1) 00
63 Rewind 1 75 0 00
64 Column 5 0 16 00
r[16]=item_info.item_id
65 Column 1 1 17 00
r[17]=subquery_1.item_id
66 Ne 17 73 16 (NOCASE) 51 if r[16]!=r[17]
goto 73
67 Noop 0 0 0 00 Begin WHERE-core
68 Column 5 0 18 00
r[18]=item_info.item_id
69 Column 0 1 19 00
r[19]=item_info.more_data
70 Column 1 0 20 00 r[20]=subquery_1.num
71 ResultRow 18 3 0 00 output=r[18..20]
72 Noop 0 0 0 00 End WHERE-core
73 Next 1 64 0 01
74 Noop 0 0 0 00 End WHERE-loop1:
subquery_1
75 Noop 0 0 0 00 End WHERE-loop0:
item_info
76 Halt 0 0 0 00
77 Transaction 0 0 3 0 01 usesStmtJournal=0
78 Goto 0 1 0 00
Which does exactly what you asked in the most efficient manner possible.
What is it that you think it ought to be doing instead?
---
The fact that there's a Highway to Hell but only a Stairway to Heaven says a
lot about anticipated traffic volume.
_______________________________________________
sqlite-users mailing list
[email protected]
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users