【问题标题】:Compound index required to speed up join-ed query?加速连接查询需要复合索引吗?
【发布时间】:2011-01-04 02:27:25
【问题描述】:

一位同事让我解释索引(指数?)如何提高性能;我试图这样做,但我自己也很困惑。
我使用下面的模型进行解释(错误/诊断日志数据库)。它由三个表组成:

  • 业务系统列表,包含其名称的“系统”表
  • 不同类型的跟踪列表,表“TraceTypes”,定义可以记录哪些类型的错误消息
  • 实际跟踪消息,具有来自 SystemTraceTypes 表的外键

我在演示中使用了 MySQL,但是我不记得我使用的表类型。我认为是 InnoDB。

 System                                TraceTypes
-----------------------------         ------------------------------------------
| ID          | Name        |         | ID    | Code   | Description           |
-----------------------------         ------------------------------------------
| 1           | billing     |         | 1     | Info   | Informational mesage  |
| 2           | hr          |         | 2     | Warning| Warning only          |
-----------------------------         | 3     | Error  | Failure               |
           |                          ------------------------------------------
           |                ------------|
 Traces    |                |            
 --------------------------------------------------
 | ID | System_ID | TraceTypes_ID | Message       |
 --------------------------------------------------
 | 1  |  1        |  1            | Job starting  |
 | 2  |  1        |  3            | System.nullr..|
 --------------------------------------------------

首先,我向所有表中添加了一些记录,并证明下面的查询在 0.005 秒内执行:

select count(*) from Traces 
  inner join System on Traces.System_ID = System.ID
  inner join TraceTypes on Traces.TraceTypes_ID = TraceTypes.ID
where 
  System.Name='billing' and TraceTypes.Code = 'Info'

然后我生成了更多数据(还没有索引)

  • “系统”包含大约 100 个条目
  • “TraceTypes”包含大约 50 个条目
  • “跟踪”包含约 1000 万条记录。

现在之前的查询需要 8-10 秒。

我在Traces.System_ID 列和Traces.TraceTypes_ID 列上创建了索引。现在这个查询在毫秒内执行:

select count(*) from Traces where System_id=1 and TraceTypes_ID=1;

这也很快:

select count(*) from Traces 
  inner join System on Traces.System_ID = System.ID
where System.Name='billing' and TraceTypes_ID=1;

但之前连接所有三个表的查询仍然需要 8-10 秒才能完成。

仅当我创建复合索引(索引中包含 System_ID 和 TraceTypes_ID 列)时,速度才下降到毫秒。

我之前学到的基本语句是“您用于连接的所有列都必须被索引”。
然而,在我的场景中,我在System_IDTraceTypes_ID 上都有索引,但是 MySQL 没有使用它们。问题是——为什么?我的赌注是 - 项目计数比率 100:10,000,000:50 会使单列索引太大而无法使用。但这是真的吗?

【问题讨论】:

    标签: mysql performance join indexing


    【解决方案1】:

    首先,分析慢速 SQL 语句的正确且最简单的方法是执行 EXPLAIN。了解优化器如何选择它的计划,并思考为什么以及如何改进它。我建议只使用 2 个单独的索引来研究 EXPLAIN 结果,以了解 mysql 如何执行您的语句。

    我对 MySQL 不是很熟悉,但似乎 MySQL 4 的限制是在查询中每个表只使用一个索引。自 MySQL 5 (index merge) 以来,这似乎有所改进,但我不确定它是否适用于您的情况。再说一次,EXPLAIN 应该告诉你真相。

    即使允许每个表使用 2 个索引(MySQL 5),使用 2 个单独的索引通常比复合索引慢。与使用复合索引的单遍相比,使用 2 个单独的索引需要索引合并步骤。

    Multi Column indexes vs Index Merge 可能会有所帮助,它使用 MySQL 5.4.2。

    【讨论】:

    • tahnk 你,我从来不知道这样的“每个表一个索引”规则,但这似乎是合乎逻辑的,也可以解释我的问题(虽然我在 mysql5.4.something 中)。
    【解决方案2】:

    决定优化器是否使用它们的不是索引的大小,而是选择性。

    【讨论】:

      【解决方案3】:

      我的猜测是它会使用索引,然后它可能会使用传统的查找来移动到另一个索引,然后过滤掉。请检查执行计划。所以简而言之,您可能会在嵌套循环中遍历两个索引。据我了解。我们应该尝试在过滤或连接中的列上创建一个复合索引,然后我们应该对选择中的列使用 Include 子句。我从未在 MySql 工作过,所以我的理解是基于 SQL Server 2005。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-07-27
        • 2013-08-28
        • 2021-04-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多