加速加入查询所需的复合索引?

时间:2010-01-12 09:09:04

标签: mysql performance join indexing

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

  • 业务系统列表,包含其名称的“System”表
  • 不同类型的跟踪列表,表“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个条目
  • “Traces”包含约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使得单列索引太大而无法使用。但这是真的吗?

3 个答案:

答案 0 :(得分:2)

首先,分析慢速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。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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