【问题标题】:Sqlite View does not use index for left join queriesSqlite View 不使用索引进行左连接查询
【发布时间】:2021-03-25 05:51:42
【问题描述】:

在 Sqlite 中,我将视图定义为两个表的联合。当我使用该视图运行查询时,如果查询足够简单,则使用索引。对于某些复杂的查询,它不会并最终运行全表扫描。有没有办法让我可以高效地使用视图?

表/视图定义:

CREATE TABLE 'Table1'     (Id varchar (18) PRIMARY KEY UNIQUE ON CONFLICT ROLLBACK,    Name varchar (255)    )
CREATE TABLE 'Table2'     (Id varchar (18) PRIMARY KEY UNIQUE ON CONFLICT ROLLBACK,    Name varchar (255)    )
CREATE TABLE 'Table3'     (Id varchar (18) PRIMARY KEY UNIQUE ON CONFLICT ROLLBACK,    Name varchar (255)    )
CREATE VIEW [UnionView] AS SELECT 'T1' tid, T1.rowid, T1.* FROM [Table1] T1 UNION ALL SELECT 'T2' tid, T2.rowid, T2.* FROM [Table2] T2

简单查询(使用索引):

SELECT Id FROM [UnionView] WHERE Id = 'asdf'

解释查询计划:

  1. 复合查询
  2. 最左边的子查询
  3. 搜索表 Table1 AS T1 USING INDEX sqlite_autoindex_Table1_1 (Id=?)
  4. 联合所有
  5. 搜索表 Table2 AS T2 USING INDEX sqlite_autoindex_Table2_1 (Id=?)

LEFT JOIN 查询(​​不使用索引):

SELECT T3.Id FROM [Table3] T3 LEFT JOIN [UnionView] T ON T3.Id=T.Id  WHERE T3.Id = 'asdf'

解释查询计划

  1. 物化 2
  2. 复合查询
  3. 最左边的子查询
  4. 扫描表 Table1 AS T1
  5. 联合所有
  6. 扫描表 Table2 AS T2
  7. 使用覆盖索引 sqlite_autoindex_Table3_1 (Id=?) 搜索 TABLE Table3 作为 T3
  8. 扫描子查询 2 作为 T

【问题讨论】:

    标签: sqlite indexing view union


    【解决方案1】:

    您的复杂查询对Table1Table2 进行全表扫描,因为您没有对UnionView 进行任何过滤。
    它确实使用了sqlite_autoindex_Table3_1
    此外,WHERE 子句应用于连接之后。

    如果您在连接之前过滤UnionView,则将使用索引:

    EXPLAIN QUERY PLAN 
    SELECT T3.Id 
    FROM [Table3] T3 
    LEFT JOIN (SELECT Id FROM [UnionView] WHERE Id = 'asdf') T 
    ON T3.Id=T.Id  
    WHERE T3.Id = 'asdf'
    

    结果:

    • 实体化 3
    • 复合查询
    • 最左边的子查询
    • 使用索引 sqlite_autoindex_Table1_1 搜索 TABLE Table1 作为 T1 (Id=?)
    • 联合所有
    • 使用索引 sqlite_autoindex_Table2_1 搜索 TABLE Table2 AS T2 (Id=?)
    • 使用覆盖索引 sqlite_autoindex_Table3_1 (Id=?) 搜索 TABLE Table3 作为 T3
    • 扫描子查询 3

    【讨论】:

    • 如果 LEFT JOIN 的右侧是表而不是视图,那么我们不需要 RHS 表的附加条件,对吗?因此,例如,此查询不需要对 Table1 进行显式过滤以高效运行:SELECT T3.Id FROM Table3 T3 LEFT JOIN Table1 T1 ON T3.Id=T1.Id WHERE T3.Id = 'asdf' 我相信我的困惑是,由于我们可以在编写选择时将视图视为表,所以我不希望做一些不同的事情有效地查询视图。
    • @FernandoRodriguez 不,这是不正确的。只有sqlite_autoindex_Table3_1 将用于该查询,因为再次只过滤了 T3。
    • @FernandoRodriguez 观看演示:dbfiddle.uk/…
    • 好吧,也许这更像是一个 sqlite 优化抱怨,但 sqlite 不应该弄清楚 Id 过滤器也应该应用于 UnionView,而不是强迫我复制过滤器?您确实提到了 where 子句是在连接之后执行的,因此可以帮助解释这种行为。
    • @FernandoRodriguez 不,在任何 SQL 查询中执行的语句顺序都有先应用 ON 子句的连接,然后再应用 WHERE 子句中的条件。
    猜你喜欢
    • 1970-01-01
    • 2019-08-27
    • 2016-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多