我在SQLite上执行了一个查询,计划部分是
0|1|5|SCAN TABLE edges AS e1 (~250000 rows)
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2
2|0|0|SEARCH TABLE dihedral USING AUTOMATIC
COVERING INDEX (TYPE=? AND EDGE=?) (~7 rows)
0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 3
3|0|0|SEARCH TABLE bounds USING AUTOMATIC
COVERING INDEX (FACE=? AND EDGE=?) (~7 rows)
WHERE中的查询是
exists (select dihedral.edge from dihedral where ihedral.type=2 and dihedral.edge=e1.edge) and
exists (select bounds.edge from bounds where bounds.face=f1.face and bounds.edge=e1.edge) and
我理解这不是一个高效的查询,我只想提高性能。
这是我的猜测:
没有子查询扁平化,对吧?
两个存在的子查询引入了相关的子查询,因为它们实际上是作为索引的嵌套循环执行的,对吗?
读取查询,因为表二面角和边界是独立的,两者都与外边缘表相关,因此没有索引的计算复杂度为O(n^2)
。但是,由于有覆盖指数,性能应该好多了吧?我发现在wiki上,索引的性能更好O(log(N))
,所以整体性能应该是O(n*log(N))
,这是对的吗?
有谁能帮我理解发生了什么?谢谢。
答案 0 :(得分:0)
SQLite确实支持subquery flattening,但这对于像这里这样的EXISTS子查询是不可能的。
AUTOMATIC显示数据库仅为此查询创建临时索引。 这强烈表明您应该永久创建这些索引:
CREATE INDEX dihedral_type_edge ON dihedral(type, edge);
CREATE INDEX bounds_face_edge ON bounds(face, edge);
外部查询遍历所有edge
行,并且对于每一行,在索引中搜索。
这将导致O(edge * (log(dihedral) + log(bounds)))
。
临时索引创建需要对这些表进行排序,因此整个运行时最终为O(dihedral*log(dihedral) + bounds*log(bounds) + edge*(log(dihedral)+log(bounds)))
。