在 MySQL 中添加多列索引比使用单列索引有什么显着的好处吗?

Is there any significant benefit in adding multi-column indices in MySQL over having single column indices?

作为高负载系统中数据库优化的新手,我有以下问题 - 假设我们有以下查询(查询带有示例数据):

SELECT * 
FROM ticket 
WHERE ticket_status='draft' 
AND user_id='789437879' 
ORDER BY ticket_id DESC  LIMIT 0, 15

我们已经有以下索引:

CREATE INDEX ticket_status on ticket(ticket_status);
CREATE INDEX user_id on ticket(user_id);
CREATE INDEX ticket_id on ticket(ticket_id);

如果我们执行以下操作,优化此查询是否会有显着的性能优势:

CREATE INDEX make_that_query_more_efficient on ticket(user_id,ticket_status);

或者它几乎没有任何区别,因为所有列都已编入索引?

这取决于查询。但绝对是在你的例子中。

在许多查询中,它会产生巨大的差异。

这里有一个关于这样的讨论:http://mysql.rjweb.org/doc.php/index1。它讨论了针对简单查询的各种索引策略。结论是复合索引显然是查询的最佳选择。

同时,在这个论坛中有几十个,也许数百个示例,我解决性能问题(高 CPU、慢查询等)的方法主要是将单列索引替换为多列索引。当 WHEREORDER BY LIMIT 都可以由 INDEX.[=37 处理时,性能提升有时是惊人的=]

多对多映射 table ('junction') 是一种非常常见的模式模式,新手无法正确索引。更多信息:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table

对于您的查询,这将是一个不同的世界:

INDEX(user_id, ticket_status,  -- these two can be in either order
      ticket_id)               -- this needs to be last

执行将快速钻取索引的 BTree 到具有 ticket_status='draft' AND user_id='789437879' 的行。它将从这些项目的末尾开始并向后扫描 (DESC),拾取 15 个(或更少)项目。然后它将查找其他列 (*) 并传送它们。

几乎任何其他索引都需要扫描超过 15 个项目。

至于你的指数。

  • 如果ticket_id已经是PRIMARY KEY,那么不要添加INDEX(ticket_id);会没用的。

  • 如果你的任何索引是我推荐的索引的前缀,DROP它;这将是多余的,而且会碍事。 (使用 EXPLAIN SELECT 来查看。)

  • 如果优化器选择了您的 (ticket_status),它会查看所有具有所需状态的条目,根据 user_id 进行过滤,对结果进行排序,然后剥离 15 行.

  • 同样适用于(user_id)

  • 如果优化器使用 INDEX(ticket_id),它将从 id 的末尾开始并向后工作。如果没有 15 个相关行,它将直到扫描整个 table.

    才会停止
  • 请注意,我的复合索引甚至避免了排序。

  • 其余的索引可能有用也可能没用;这取决于其他查询是否可以使用它们。

  • 一个 suitable 索引可能对 SELECT 比对 INSERTs 的负担更有利;所以不用担心这个权衡。

  • user_id 开头可能对其他查询有用;从 status 开始似乎不太可能。由于“基数”,单列 INDEX(ticket_status) 不太可能被任何查询使用。

  • 我的 3 列索引可能比您类似的 2 列索引好得多。我的负责 ORDER BYLIMIT;你的需要收集很多行并对它们进行排序。

  • 如果 * 中有大的 TEXT 列,性能差异可能会更大。