8

I have many tables where I have indexes on foreign keys, and clustered indexes which include those foreign keys. For example, I have a table like the following:

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

... many more columns

MySQL generates indexes for primary and foreign keys, but sometimes, I want to improve query performance so I'll create clustered or covering indexes. This leads to have indexes with overlapping columns.

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

If I dropped idx_owner, future queries that would normally use idx_owner would just use idx_owner_status since it has owner as the first column in the index.

Is it worth keeping idx_owner around? Is there an additional I/O overhead to use idx_owner_status even though MySQL only uses part of the index?

Edit: I am really only interested in the way InnoDB behaves regarding indexes.

4

1 回答 1

7

简短答案 删除较短的索引。

Long Anwser 需要考虑的事项:

算了吧:

  • 每个INDEX都是一个单独的 BTree,驻留在磁盘上,所以它占用空间。
  • 当您创建新行或修改索引列时,每个INDEX都会更新(迟早) 。这需要一些 CPU 和 I/O 以及 buffer_pool 空间用于“更改缓冲区”。INSERTUPDATE
  • 较短索引的任何功能使用(与性能相反)都可以由较长的索引执行。

不要丢弃它:

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

最后一个项目真正覆盖其他项目是非常罕见的。

奖金

“覆盖”索引是一个包含在 a 中提到的所有列的索引SELECT。例如:

SELECT status FROM tbl WHERE owner = 123;

这将触及BTree for INDEX(owner, status),因此明显快于

SELECT status, foo FROM tbl WHERE owner = 123;

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

主键中的PK

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

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

在我的博客中关于复合索引索引食谱的更多讨论

于 2015-09-06T00:50:00.887 回答