如何理解SQLite`EXPLAIN QUERY PLAN`结果?

时间:2013-07-15 20:32:57

标签: sql sqlite explain sql-execution-plan

我已经读过连接比子查询更好。

但是

EXPLAIN QUERY PLAN
SELECT Queue.Id, NULL
    FROM Queue
    INNER JOIN LastQueue
    ON Queue.Id=LastQueue.Id

给出

Array
(
    [0] => Array
        (
            [selectid] => 0
            [order] => 0
            [from] => 0
            [detail] => SCAN TABLE Queue (~1000000 rows)
        )

    [1] => Array
        (
            [selectid] => 0
            [order] => 1
            [from] => 1
            [detail] => SEARCH TABLE LastQueue USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
        )

)

,而

EXPLAIN QUERY PLAN
SELECT Queue.Id, NULL
    FROM Queue
    WHERE (SELECT 1 FROM LastQueue WHERE Queue.Id=LastQueue.Id) IS NOT NULL

给出

Array
(
    [0] => Array
        (
            [selectid] => 0
            [order] => 0
            [from] => 0
            [detail] => SCAN TABLE Queue (~500000 rows)
        )

    [1] => Array
        (
            [selectid] => 0
            [order] => 0
            [from] => 0
            [detail] => EXECUTE CORRELATED SCALAR SUBQUERY 1
        )

    [2] => Array
        (
            [selectid] => 1
            [order] => 0
            [from] => 0
            [detail] => SEARCH TABLE LastQueue USING INTEGER PRIMARY KEY (rowid=?) (~1 rows)
        )

)

我认为我必须将行数相乘才能了解成本。我是对的?

然后,

  • 使用join:1000000 * 1
  • 使用子查询:500000 * 1 * 1

那么,子查询是否比加入更快?

是否有一个很好的教程来学习如何理解EXPLAIN / EXPLAIN QUERY PLAN结果?

为什么SCAN TABLE Queue是~1000000和~500000,那个表有76行?

2 个答案:

答案 0 :(得分:6)

EXECUTE CORRELATED SCALAR SUBQUERY 1就在那里,因为您使用的是不同的查询语法。

两种情况下的实际执行情况相同:SQLite遍历Queue表的所有记录,并尝试在LastQueue表中查找相应的记录。

估计记录计数不同对您来说无关紧要,因为您知道实际记录数是相同的。

连接可能比其他数据库中的子查询更好,但在仅使用嵌套循环连接的SQLite中,唯一的区别是连接允许SQLite在连接中选择外部和内部表。

在任何情况下,您都应该以最简单和可维护的方式编写查询,并且只有在您已经测量到您得到明显且必要的改进时才对其进行优化。


请注意,而不是:

WHERE (SELECT ...) IS NOT NULL

写作会更加惯用:

WHERE EXISTS (SELECT ...)

答案 1 :(得分:1)

解释是为您的表提供不准确的计数。尝试使用analyze来收集表格的统计数据,然后再次尝试解释。

我认为你会发现两个查询都会以几乎完全相同的速度返回。由于额外的步骤,子查询可能更慢。这里需要注意的重要一点是“SCAN TABLE”,这意味着它会查看磁盘上的所有行。

http://www.sqlite.org/lang_analyze.html

你的桌子上还有没有索引吗?因为它应该使用它们,但它似乎不是。确保在create table语句中使用主键。

http://www.sqlite.org/lang_createtable.html