指数让我失望 - 我该如何优化这个SQLite查询?

时间:2013-09-17 03:18:05

标签: sqlite

我需要一些帮助来优化以下查询:

SELECT
kd2c.id as _id,
kd2c.literal as kanji
FROM
kd2_character as kd2c
JOIN krad_components as kcom ON kcom.kanji_fk = kd2c.id
WHERE kcom.radical_fk IN (1, 2, 3, etc...)
GROUP BY kd2c.id HAVING count(distinct kcom.radical_fk) = <number of integers in WHERE clause>
ORDER BY kd2c.freq IS NULL ASC, kd2c.freq, kd2c.id

查询本身(无论WHERE子句中的fk数量)都需要0.04秒才能运行,这相对于我所有其他查询需要大约0.0003秒。我针对上述声明运行EXPLAIN QUERY PLAN并收到以下内容:

# | selectid | order | from | detail 
1   0   0   0   SCAN TABLE kd2_character AS kd2c USING INTEGER PRIMARY KEY (~1000000 rows)
2   0   1   1   SEARCH TABLE krad_components AS kcom USING COVERING INDEX idx_krad_components (kanji_fk=? AND radical_fk=?) (~9 rows)
3   0   0   0   EXECUTE LIST SUBQUERY 1
4   0   0   0   USE TEMP B-TREE FOR ORDER BY

我很确定脚本因为初始SCAN TABLE而需要很长时间。如果是这样的话,我怎么能摆脱它呢?我认为在kd2_characer.id上创建索引会有所帮助,但它对执行时间没有任何明显的影响。

如何改进此查询?有没有更好的方法来构建我的GROUP BY,因为它可能是SCAN的来源?

1 个答案:

答案 0 :(得分:0)

当SQLite连接两个表时,它使用嵌套循环连接,即它遍历一个表的所有记录,并查找另一个表中的对应记录。 如果第一个表的许多记录在必须连接之前被某些WHERE条件过滤掉,并且第二个表在连接列上有索引,则会更快。

对于此特定查询,SQLite估计使用kd2_character作为循环中的外表更快(因为您有一个索引可用于kanji_fk和{{{ 1}}列)。 这可能是也可能不是。

尝试运行ANALYZE一次以获得更准确的估算。

您可以使用CROSS JOIN强制SQLite使用特定的连接顺序;检查这是否有所不同:

radical_fk

(如果数据库的内容最终发生变化,以便其他连接顺序更快,则此优化很危险。)