我需要一些帮助来优化以下查询:
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
的来源?
答案 0 :(得分:0)
当SQLite连接两个表时,它使用嵌套循环连接,即它遍历一个表的所有记录,并查找另一个表中的对应记录。
如果第一个表的许多记录在必须连接之前被某些WHERE
条件过滤掉,并且第二个表在连接列上有索引,则会更快。
对于此特定查询,SQLite估计使用kd2_character
作为循环中的外表更快(因为您有一个索引可用于kanji_fk
和{{{ 1}}列)。
这可能是也可能不是。
尝试运行ANALYZE一次以获得更准确的估算。
您可以使用CROSS JOIN强制SQLite使用特定的连接顺序;检查这是否有所不同:
radical_fk
(如果数据库的内容最终发生变化,以便其他连接顺序更快,则此优化很危险。)