重叠的多列索引

Overlapping multi-column indices

像这样考虑一个 table(人为的例子;我试图让它变得模糊 relatable):

CREATE TABLE `roles` (
  `host` varchar(50) NOT NULL,
  `port` smallint(6) NOT NULL,
  `user_id` varchar(50) NOT NULL,
  `role` varchar(50) NOT NULL
) ENGINE=InnoDB

典型数据:

INSERT INTO TABLE `roles`
(host, port, user_id, role)
VALUES
('localhost', 8080, 'root', 'admin'),
('localhost', 8080, 'guest', 'readonly');

我知道数据是唯一且非空的:
(host, port, user_id)
我打算使用那个多列索引作为我的主键。

但我 喜欢我的 SELECT 的覆盖索引优化,select 所有列。为此,我正在考虑在以下位置添加更广泛的多列索引:
(host, port, user_id, role)

所以问题来了……如果我创建两个索引,(a,b,c)(a,b,c,d):MySQL/InnoDB 是否足够聪明,可以在后台将其实现为单个索引?
或者它会创建和维护两个索引,浪费 space 和时间——并且没有注意到 (a,b,c,d)(a,b,c) 的超集?

我想避免这个问题,只做主键(a,b,c,d),这样只有一个索引。但这似乎是一个次优的主键(它考虑了比保证唯一性所需的更多的列)。

如果您创建两个索引,那么 (a,b,c) 和 (a,b,c,d) 查询优化器无法选择更好的.. 在这种情况下,您应该明确指定要使用的索引加入 using 子句加入 ..

但如果你真的需要,你应该考虑创建不重叠的列索引,例如:

 (a,b,c)   

(d,c,b,a)  

其他不以相同序列开始的组合

在这种情况下,索引是根据查询列的匹配等级来选择的

无论如何你可以在这里找到有用的信息https://dev.mysql.com/doc/refman/5.7/en/mysql-indexes.html

(a,b,c) 可能比 (a,b,c,d) 优先使用(优化器),因为索引较小。

同时拥有这两个索引会浪费磁盘 space,并且当缓存两个索引的一部分时会导致缓存中的空间浪费。这会导致查询变慢。

与其同时拥有两者,不如保留较长的一个。它会处理这两种情况。

如果 d 是一个 "big" 列,那么它的索引将为 "big"。在这种情况下,(a,b,c) 可能是首选。

另一方面,(a,b,c) 和 (b,c,a) 处理 不同的 查询,因此您 可能 两者都需要。

Cookbook on building indexes