On Thu, Jul 6, 2017 at 12:54 PM, Clemens Ladisch <clem...@ladisch.de> wrote:

> Dominique Devienne wrote:
> > with
> > kcounts(t, c) as (
> >   select code_type, count(*)
> >    from keys
> >   group by code_type
> > ),
> > ...
> > select ...,
> >        (select c from kcounts where t = 'SET') as "#sets",
> >        (select c from kcounts where t = 'CST') as "#constants",
> >        (select c from kcounts where t = 'CMT') as "#comments",
> >        (select c from kcounts where t = 'LOG') as "#logs",
> >        ...;
> >
> > the SQL as written does several passes over kcounts
>
> However, the subquery is flattened: each pass counts only rows with
> a specific code_type value.
>
> An index on code_type would help _very much_.


Actually not that much apparently.
No Simon, I didn't have an index on code_type.
In fact keys is itself a view, and cote_type a case expression.

That's fine, I created a expression index using

create index idx_keys_code on keys_tab(
       case
       when (code & 1) = 1 then 'SET'
       when (code & 2) = 2 then 'CST'
       when (code & 4) = 4 then 'CMT'
       when (code & 8) = 8 then 'LOG'
       else null
       end
)

The plan correctly changes to "SCAN TABLE keys USING INDEX idx_keys_code",
4x.

And the runtime only drops to ~5.4s closer to 6.5s than 2.15s,
but at the cost of 22MB extra in the DB file for the index. Not sure that a
good tradeof.

> Is there a way to reformulate this query differently to somehow achieve a
> > single pass on the keys table? Or force the query planner to
> "instantiate"
> > the kcounts "CTE view" to achieve that single scan, via some kind of
> hint?
>
> It would be possible to prevent the subquery flattening
> (http://www.sqlite.org/optoverview.html#flattening), but AFAIK there is
> no hint that would force SQLite to recognize that all the instances of
> kcounts are then identical and can be reused.
>
> You could put kcounts into a temporary table.
>

I could it in a table, but then who updates kcounts when keys (or keys_tab)
changes?
I guess one can play with triggers then, to emulate materialized views,
opening a new can of worm.

These are "persistent report views", as already discussed when the thousand
separator was added to printf.
"Users" just "view" these views in any SQLite clients, typically a GUI one.
And they should remain "dynamic"
into case the table contents are modified with DMLs.

Maybe the "hint" to create an ephemeral table for a "CTE view" could be to
prefix the CTE view name with temp. ?

I know that Richard/SQLite are not much into planner hints, but a few
exists already.

What do you think Richard? --DD

> with
> temp.kcounts(t, c) as (
>   select code_type, count(*)
>    from keys
>   group by code_type
> ),
> ...
> select ...,
>        (select c from kcounts where t = 'SET') as "#sets",
>        (select c from kcounts where t = 'CST') as "#constants",
>        (select c from kcounts where t = 'CMT') as "#comments",
>        (select c from kcounts where t = 'LOG') as "#logs",
>        ...;
_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to