综合索引的开销

Overhead of Composite Indexes

我有很多 table 有外键索引和包含这些外键的聚簇索引。例如,我有一个 table 如下所示:

TABLE: Item
------------------------
id       PRIMARY KEY
owner    FOREIGN KEY
status

... many more columns

MySQL 为主键和外键生成索引,但有时,我想提高查询性能,所以我会创建聚簇索引或覆盖索引。这会导致索引的列重叠。

INDEXES ON: Item
------------------------
idx_owner (owner)
idx_owner_status (owner, status)

如果我删除 idx_owner,以后通常使用 idx_owner 的查询将只使用 idx_owner_status,因为它有 owner 作为索引中的第一列。

idx_owner 值得留在身边吗?即使 MySQL 仅使用索引的一部分,使用 idx_owner_status 是否还有额外的 I/O 开销?

编辑:我真的只对 InnoDB 关于索引的行为方式感兴趣。

简答 删除较短的索引。

长答案 需要考虑的事项:

放弃它:

  • 每个 INDEX 都是一个驻留在磁盘上的独立 BTree,因此需要 space。
  • 当您 INSERT 新行或 UPDATE 修改索引列时,每个 INDEX 都会更新(迟早)。对于 'change buffer'.
  • 这需要一些 CPU 和 I/O 以及 buffer_pool space
  • 对于较短索引的任何 功能 使用(与性能相反)都可以由较长索引执行。

别丢了:

  • 较长的索引比较短的索引更大。所以它不太可缓存。因此(在极端情况下)使用较大的代替较短的可能导致更多I/O。一个加剧这种情况的案例:INDEX(int, varchar255).

最后一项真的覆盖其他项的情况非常罕见。

奖金

"covering" 索引包含所有 SELECT 中提到的列。例如:

SELECT status FROM tbl WHERE owner = 123;

这将 INDEX(owner, status) 的 BTree,因此明显快于

SELECT status, foo FROM tbl WHERE owner = 123;

如果您确实需要该查询更快,请将 both 的索引替换为 INDEX(owner, status, foo).

二级密钥中的 PK

还有一个花絮...在 InnoDB 中,PRIMARY KEY 的列隐式附加到每个辅助键。所以,这三个例子真是

INDEX(owner, id)
INDEX(owner, status, id)
INDEX(owner, status, foo, id)

更多讨论 在我的博客 composite indexes and index cookbook