【问题标题】:Is there any significant benefit in adding multi-column indices in MySQL over having single column indices?与单列索引相比,在 MySQL 中添加多列索引有什么显着的好处吗?
【发布时间】:2022-01-18 11:08:17
【问题描述】:

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

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);

还是因为所有列都被索引了,所以几乎没有什么区别?

【问题讨论】:

  • 一个 user_id 有多少张票?
  • 可以是一个,也可以是数千个。
  • 一个表副本只能使用一个索引。您可以按每个单独的列创建索引 - 但只能使用其中一个。 如果我们执行以下操作,优化此查询是否会带来显着的性能优势也许很有可能。还通过(user_id, ticket_status, ticket_id) 测试索引。
  • 这个问题的问题在于,我们无法提前告诉您使用多列索引是否会获得显着的性能提升!这取决于您的数据(索引中附加列的选择性以及还有多少记录需要按第 3 列排序)。显着这个词也是模糊的,我们认为显着的,你可能不认为显着。对你来说最好的方法是测试它:在你的开发环境中获取相似的大小和特征数据,并用单列索引和多列索引测试性能,你就会知道答案
  • 请阅读 Marcus Windand 的 use-the-index-luke.com 。

标签: mysql sql performance indexing query-optimization


【解决方案1】:

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

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

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

同时,在这个论坛中有几十个甚至数百个示例,我对性能问题(高 CPU、慢查询等)的解决方案主要是用多列索引替换单列索引。当WHERE、ORDER BY、和LIMIT都可以由INDEX处理时,性能提升有时是惊人的。

多对多映射表(“联结”)是一种非常常见的模式模式,新手无法正确索引。更多信息: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);没用的。

  • 如果您的任何索引是我推荐的索引的前缀,请删除它;这将是多余的,并且会妨碍您。 (使用EXPLAIN SELECT 来查看。)

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

  • 同样适用于(user_id)

  • 如果优化器使用INDEX(ticket_id),它将从 id 的末尾开始并向后工作。如果没有 15 个相关的行,它将在扫描整个表之前不会停止。

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

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

  • 一个合适的索引对SELECT 的好处可能比对INSERTs 的负担要大得多;所以不用担心这种权衡。

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

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

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

【讨论】:

  • 非常感谢您的详细回答。在此查询的实践中,事实证明添加复合索引对该特定查询产生了显着影响。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 1970-01-01
相关资源
最近更新 更多