I acknowledge you said you weren't so much interested in an alternative 
solution, but...

How about something like

select a, min(size) as minSize, recCount
from
  (select a, size, count(*) as recCount
  from a inner join ab
  using (a)
  group by a, size)
group by a;

The inner one will group by a and size, then the outer group by with the min() 
will pick the minimum and use that line to populate the bare column of recCount.

With 10,000 here's your original:

sqlite> select a, (select count(*) from ab where a = a.a and size = (select 
min(size) from ab where a = a.a)) from a;
--EQP-- 0,0,0,SCAN TABLE a
--EQP-- 0,0,0,EXECUTE CORRELATED SCALAR SUBQUERY 1
--EQP-- 1,0,0,SEARCH TABLE ab USING INDEX sqlite_autoindex_ab_1 (a=?)
--EQP-- 1,0,0,EXECUTE CORRELATED SCALAR SUBQUERY 2
--EQP-- 2,0,0,SEARCH TABLE ab USING INDEX sqlite_autoindex_ab_1 (a=?)
a|(select count(*) from ab where a = a.a and size = (select min(size) from ab 
where a = a.a))
1|522
2|486
3|500
Memory Used:                         975336 (max 1508448) bytes
Number of Outstanding Allocations:   270 (max 326)
Number of Pcache Overflow Bytes:     850880 (max 986272) bytes
Number of Scratch Overflow Bytes:    0 (max 12472) bytes
Largest Allocation:                  524288 bytes
Largest Pcache Allocation:           4256 bytes
Largest Scratch Allocation:          12472 bytes
Lookaside Slots Used:                35 (max 100)
Successful lookaside attempts:       71296
Lookaside failures due to size:      19
Lookaside failures due to OOM:       119
Pager Heap Usage:                    844920 bytes
Page cache hits:                     2030205
Page cache misses:                   0
Page cache writes:                   0
Schema Heap Usage:                   1472 bytes
Statement Heap/Lookaside Usage:      32400 bytes
Fullscan Steps:                      2
Sort Operations:                     0
Autoindex Inserts:                   0
Virtual Machine Steps:               1800501558
Run Time: real 39.031 user 38.906649 sys 0.015600


And the alternative:
sqlite> select a, min(size) as minSize, recCount from (select a, size, count(*) 
as recCount from a inner join ab using (a) group by a, size) group by a;
--EQP-- 1,0,0,SCAN TABLE a USING COVERING INDEX sqlite_autoindex_a_1
--EQP-- 1,1,1,SEARCH TABLE ab USING INDEX sqlite_autoindex_ab_1 (a=?)
--EQP-- 1,0,0,USE TEMP B-TREE FOR GROUP BY
--EQP-- 0,0,0,SCAN SUBQUERY 1
--EQP-- 0,0,0,USE TEMP B-TREE FOR GROUP BY
a|minSize|recCount
1|-9|522
2|-9|486
3|-9|500
Memory Used:                         984136 (max 1513008) bytes
Number of Outstanding Allocations:   280 (max 332)
Number of Pcache Overflow Bytes:     855136 (max 986272) bytes
Number of Scratch Overflow Bytes:    0 (max 12472) bytes
Largest Allocation:                  524288 bytes
Largest Pcache Allocation:           4256 bytes
Largest Scratch Allocation:          12472 bytes
Lookaside Slots Used:                55 (max 100)
Successful lookaside attempts:       102118
Lookaside failures due to size:      26
Lookaside failures due to OOM:       258
Pager Heap Usage:                    849164 bytes
Page cache hits:                     199
Page cache misses:                   0
Page cache writes:                   0
Schema Heap Usage:                   1736 bytes
Statement Heap/Lookaside Usage:      58280 bytes
Fullscan Steps:                      2
Sort Operations:                     2
Autoindex Inserts:                   0
Virtual Machine Steps:               511684
Run Time: real 0.063 user 0.015600 sys 0.000000


-----Original Message-----
From: sqlite-users [mailto:sqlite-users-boun...@mailinglists.sqlite.org] On 
Behalf Of E.Pasma
Sent: Friday, July 07, 2017 9:47 AM
To: SQLite mailing list
Subject: [sqlite] Slow query, with correlated sub-sub-query

Hello, below is a theoretical query that becomes slow when the number  
of rows increases. What it does is:
- scan input cases in table a
- for each input case:
-- determine the smallest value of attribute size of elements in table  
ab
-- count the number of elements having this smallest size
With 3 rows in table a and 3*1000 in ab this takes already several  
seconds.
I'm not so much interested in an alternative solution, though  
interesting, and merely want to show an inefficient construction. That  
is a sub-sub-query correlated directly to the main query.
Thanks, E. Pasma

.version
SQLite 3.19.3 2017-06-08 14:26:17 ...

create table a (a, primary key (a))
;
create table ab (a, b, size, primary key (a,b))
;
insert into a
with i as (select 1 as i union all select i+1 from i where i<3)
select i from i
;
insert into ab
with i as (select 1 as i union all select i+1 from i where i<1000)
select a, i as b, random()%10 as size from a, i
;
.eqp on
.timer on
select  a,
        (
            select  count(*)
            from    ab
            where   a=a.a
            and     size=(select min(size) from ab where a=a.a)
        )
from    a
;
--EQP-- 0,0,0,SCAN TABLE a
--EQP-- 0,0,0,EXECUTE CORRELATED SCALAR SUBQUERY 1
--EQP-- 1,0,0,SEARCH TABLE ab USING INDEX sqlite_autoindex_ab_1 (a=?)
--EQP-- 1,0,0,EXECUTE CORRELATED SCALAR SUBQUERY 2
--EQP-- 2,0,0,SEARCH TABLE ab USING INDEX sqlite_autoindex_ab_1 (a=?)
1|56
2|53
3|49
Run Time: real 2.678 user 2.597794 sys 0.008801

_______________________________________________
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

Reply via email to