综合索引的开销
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。
我有很多 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。