【问题标题】:SQLite join optimisationSQLite 连接优化
【发布时间】:2011-05-10 04:03:32
【问题描述】:

如果您有如下查询:

select a.Name, a.Description from a
inner join b on a.id1 = b.id1
inner join c on b.id2 = c.id2
group by a.Name, a.Description

如果您认为每个表中有超过 100,000 行,那么在 SQLite 中为该查询建立索引的最佳列是什么?

我问的原因是,当我应用相同的优化时,我没有从另一个 RDBMS (SQL Server) 获得预期的组查询性能。

我是否认为 SQLite 查询中单个表上引用的所有列都需要包含在单个复合索引中以获得最佳性能?

【问题讨论】:

  • 我内心的精神病患者正在抽搐,因为您有一个没有任何聚合函数的 group by 子句。您想通过小组实现什么目标?
  • @MyOtherMe:请参阅下面的答案,我认为他想要在 b 和 c 表中引用的所有描述和名称中有所不同。

标签: sql sqlite indexing query-optimization


【解决方案1】:

注意:我对 SQLite 及其执行计划可能存在的复杂性一无所知。

您肯定需要a.id1b.id1b.id2c.id2 上的索引。我认为综合指数(b.id1, b.id2) 可以产生小的性能提升。 (a.id1, a.Name, a.Description) 也是如此。

【讨论】:

    【解决方案2】:

    来自SQLite query optimization overview

    在对行进行索引查找时,通常的过程是对索引进行二进制搜索以找到索引条目,然后从索引中提取 rowid 并使用该 rowid 进行二进制搜索原来的表。因此,典型的索引查找涉及两个二进制搜索。但是,如果要从表中获取的所有列都已在索引本身中可用,则 SQLite 将使用索引中包含的值,并且永远不会查找原始表行。这为每一行节省了一次二分搜索,并且可以使许多查询的运行速度提高一倍。

    对于任何其他 RDBMS,我建议在 b.id1 和 c.id2 上放置一个聚集索引。对于 SQLite,最好将 b 和 c 中的任何列也包含在这些索引中。

    【讨论】:

    • 覆盖索引几乎存在于每个 RDBMS 中,并且对查找具有相同的效果。问题是大型索引会损害插入/更新性能,因此您必须在更新性能和选择性能之间进行权衡。
    • 感谢您的回复,请原谅我的无知,但是您是说在 SQLite 中可以创建包含多个表中的列的索引,类似于 SQLServer 中的索引视图?
    • 嗯,不,我是说当你在 B 上创建索引时,不要只在 B.id 上创建索引,还要在索引中包含 B 中需要的所有数据列。这将为您节省对这些数据列的二分搜索。在另一个 DBMS 中,通过在索引中包含来自多个表的列可能会更快,但 SQLite 并没有那么先进。
    【解决方案3】:

    问题在于您期望 SQLite 具有与完整 RDBMS 相同的性能特征。它不会。 SQLLite 没有在内存中缓存那么多的奢侈,每次运行应用程序时都必须重建缓存,可能仅限于设置的核心数量等。使用嵌入式 RDBMS 的权衡超过一个完整的。

    就优化而言,尝试索引查找列并进行测试。然后尝试创建一个覆盖索引。请务必同时测试selects 和更新数据库的代码路径,您正在加速其中一个,而牺牲另一个。找到最适合您需求的两者之间平衡的索引,然后使用它。

    【讨论】:

    • 感谢您的回答,我之前曾尝试在 a.Id1、a.name、a.description 上添加复合索引,并在 b.id1、b.id2 和另一个上添加复合索引c.id2 上的索引。然而,这些都无助于小组的表现。这就是引发这个问题的原因,因为在这种情况下使用 SQLite 似乎不可能按性能找出足够的组。我想这只是拥有嵌入式数据库的限制之一。
    【解决方案4】:

    由于您没有将其他表用于返回列,因此可能会更快:

    SELECT DISTINCT a.Name, a.Description
    FROM a, b, c
    WHERE a.id1 = b.id1
    AND b.id2 = c.id2
    

    查看返回的列,因为条件似乎只是它们必须从 a 链接到 bc,您可以查找所有唯一的 a.Namea.Description 对。

    SELECT DISTINCT a.Name, a.Description
    FROM a
    WHERE a.id1 IN (
     SELECT b.id1
     FROM b
     WHERE b.id2 IN (
      SELECT c.id2
      FROM c
      )
     )
    

    或者,取决于每对 a.Namea.Description 是否已经是唯一的,首先找出唯一 ID 然后获取其他列应该会有一些好处。

    SELECT a.Name, a.Description
    FROM a 
    WHERE a.id1 IN (
     SELECT DISTINCT a.id1
     FROM a
     WHERE a.id1 IN (
      SELECT b.id1
      FROM b
      WHERE b.id2 IN (
       SELECT c.id2
       FROM c
       )
      )
     )
    

    【讨论】:

      【解决方案5】:

      我认为 a.id1 和 b.id2 上的索引会给你带来尽可能多的好处。但是 SQLite 提供了 EXPLAIN,它可能会帮助您确定当前执行计划中是否存在可避免的效率问题。

      【讨论】:

        猜你喜欢
        • 2020-04-10
        • 1970-01-01
        • 2010-11-06
        • 1970-01-01
        • 2018-02-26
        • 2011-05-22
        • 2011-12-31
        • 1970-01-01
        相关资源
        最近更新 更多