sqlite - 如何在sqlite中使用where和group by提高查询性能

标签 sqlite indexing group-by where

现在在一个名为log的表中大约有200万条记录。查询性能变得 Not Acceptable ,但我不想在当前阶段将表拆分到不同的分区。 因此,我尝试添加一些索引以提高查询性能。

CREATE TABLE log
           (
                id Integer primary key autoincrement,
                app_id text,
                __key__id INTEGER,

                secret text,
                trace_code text,
                url text,

                action text,

                facebook_id text,
                ip text,

                tw_time timestamp,
                time timestamp,

                tag text,
                to_url text,

                from_url text,
                referer text,

                weight integer,
                Unique(app_id, __key__id)
            );
CREATE INDEX key1 on log (action, url, tag);

但是,sqlite 似乎只是忽略了我的索引,而是扫描了整个表。 我错过了什么吗?

sqlite> explain query plan select count(*) from log where action like 'content_%
';
0|0|0|SCAN TABLE log (~1182357 rows)


sqlite> explain query plan select count(*) from log where action like 'content_%
' group by url, tag;
0|0|0|SCAN TABLE log (~1182357 rows)
0|0|0|USE TEMP B-TREE FOR GROUP BY

编辑1

@MaxSem 谢谢,当我将查询更改为:

sqlite> explain query plan select count(*) from log indexed by key1 where action
 in ('content_click','content_mouseover', 'content_display');
0|0|0|SEARCH TABLE log USING COVERING INDEX key1 (action=?) (~886770 rows)
0|0|0|EXECUTE LIST SUBQUERY 1

但是,我无法解释Sqlite无法处理原始查询的原因。

编辑2

我应该改变我的问题。 有没有办法在 sqlite 中加速这种查询?

最佳答案

我相信 SQLite 不能将索引列用于带有 LIKE 谓词的查询,即使 starts with LIKE 查询也是如此。但是您可以使用不等式模拟这种 LIKE 谓词:

sqlite> create table t (action text, url text, tag text);
sqlite> insert into t values ('click', 'foo', 'bar');
sqlite> insert into t values ('clack', 'foo', 'bar');
sqlite> insert into t values ('clock', 'foo', 'bar');
sqlite> insert into t values ('cluck', 'foo', 'bar');
sqlite> insert into t values ('cleck', 'foo', 'bar');
sqlite> insert into t values ('clyck', 'foo', 'bar');
sqlite> create index t_index on t (action, url, tag);

使用开头的 LIKE,您可以进行全面扫描:

sqlite> explain query plan select count(*) from t where action like 'cl%';
0|0|0|SCAN TABLE t (~500000 rows)

但是对于不等式,使用索引:

sqlite> explain query plan select count(*) from t where action >= 'cl' and action < 'cm';
0|0|0|SEARCH TABLE t USING COVERING INDEX t_index (action>? AND action<?) (~62500 rows)

此技术的警告是您在选择下限(此处为“cm”)时必须小心,以便词典顺序为您提供您所期望的结果,并且此技术无法轻松建模所有 LIKE 谓词。

当您使用带有标记的 IN 谓词来精确匹配时,当然会使用索引,因为您又回到了使用等式:

sqlite> explain query plan select count(*) from t where action in ('click', 'clack');
0|0|0|SEARCH TABLE t USING COVERING INDEX t_index (action=?) (~20 rows)
0|0|0|EXECUTE LIST SUBQUERY 1

如果您仍想使用 LIKE,您可以将您的表与您希望从子查询中获得的操作值的预选列表连接起来:

sqlite> explain query plan select count(*) from t join (select distinct action from t where action like 'cl%') a where t.action = a.action;
1|0|0|SCAN TABLE t USING COVERING INDEX t_index (~500000 rows)
0|0|1|SCAN SUBQUERY 1 AS a (~500000 rows)
0|1|0|SEARCH TABLE t USING COVERING INDEX t_index (action=?) (~10 rows)

如果您愿意,这基本上为您提供了一个动态 IN 谓词,而不是明确列出所有可能的值。

当然,在这里,我从你的大表中提取与 LIKE 查询匹配的操作列表,所以这本身就是一个完整的扫描,否定了所有的好处,但是如果你规范化你的模式有一个单独的(很多更小的)操作表,带有一个小整数代理键,您将用作日志表中的操作列,那么您将避免在日志表中多次存储重复字符串(由小整数替换),并且您会能够轻松加入他们进行查询。

关于sqlite - 如何在sqlite中使用where和group by提高查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11152371/

相关文章:

python - 如何在 python 中删除 sqlite3 数据库?

sql - 在sqlite3中使用row_number时出现语法错误

c++ - 在sqlite数据库中存储类

c - 获取第一个字符串字符来获取索引?

elasticsearch - Elasticsearch 1.x添加时间戳的字段副本

mysql - 从具有每个不同 candidate_id 的最近日期的行中返回数据

SQLite连接多个表按较少的COUNT排序

java - 知道为什么我的 getColumnIndex() 通过 android 返回 -1 吗?

sql - Postgresql 查询不识别列

postgresql - Postgres 反向 LIKE 查找索引和性能