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

nai*_*sts 6 mysql indexing performance join

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

  • 业务系统列表,包含其名称的表"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..|
 --------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

首先,我在所有表中添加了一些记录,并证明下面的查询在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'
Run Code Online (Sandbox Code Playgroud)

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

  • "系统"包含大约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;
Run Code Online (Sandbox Code Playgroud)

这也很快:

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

但加入所有三个表的上一个查询仍需要8-10秒才能完成.

只有当我创建了一个复合索引(索引中包含System_ID和TraceTypes_ID列)时,速度才会降低到毫秒.

我之前教过的基本陈述是"用于加入的所有列都必须编入索引".
然而,在我的情况我有两个索引System_IDTraceTypes_ID,但是MySQL并没有使用它们.问题是 - 为什么?我的投注是 - 项目计数比率100:10,000,000:50使得单列索引太大而无法使用.但这是真的吗?

bry*_*sai 2

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

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

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

多列索引与索引合并可能会有所帮助,它使用 MySQL 5.4.2。