我有一些关于MySQL索引的相关问题:
我的应用程序中有很多插入内容,我担心MySQL会在每次插入后重建索引。数据不必是实时的,因此我可以在特定数量的插入后更新索引(如果可能的话)。
答案 0 :(得分:4)
MySQL可能已经尽可能地完成了你所描述的内容。
对于InnoDB(应该是MySQL的默认存储引擎),插入,更新和删除会立即更改主键或唯一键索引。但他们从不重建整个索引,他们在这些索引中添加新值(或从中取出值)。
对于非唯一索引,InnoDB执行change buffering。也就是说,它将更改排队,稍后将在后台合并到索引中。它甚至可以整合更改,以便更有效地完成对索引的物理更新。
您无需执行任何操作即可启用此功能,因为默认情况下已启用此功能。 MySQL 5.1确实仅为INSERT
更改缓冲。 MySQL 5.5及更高版本还改变了UPDATE
和DELETE
的缓冲。
如果需要,您可以禁用此功能(例如,如果您使用SSD,避免随机I / O不是那么重要,您可能希望确保排队的更改不会累积) 。通常,您应该启用该功能。
答案 1 :(得分:2)
MySQL没有"重建"每次插入后的索引。 MySQL在现有索引中插入一行或多行。
MySQL有许多不同寻常的选择,而且我不了解所有这些选项。如果有一个选项说:"哦,让表上的索引与表中的数据不同步,我会感到惊讶。"听起来不合理。
如果你有很多插入,最好的策略是在一个语句中进行插入。而不是:
insert into t(...)
select . . .
from t2
where id = id1;
执行:
insert into t(...)
select . . .
from t2
where id in (id1, id2, . . .)
对此的扩展是插入临时表。然后只需将临时表一次性加载到大表中:
insert into t(...)
select ...
from temptable;
最后,删除索引,执行大插入(在一个或多个步骤中),然后重新创建索引有时会更快。
一个警告:如果删除唯一索引,则还会删除唯一约束。如果您使用on duplicate key update
,这很重要,因为它需要辅助索引来查找重复键(主键除外)。
答案 2 :(得分:1)
当MySQL由于插入而更新索引时,它是否会重建 整个指数?
不,MySQL没有"重建"每个插入的索引。
MySQL的默认页面大小为16K。它以1MB为增量分配这些页面(称为范围)。
首次创建表时(重建索引),页面填满15/16,为一些随机插入留出空间。如果您的索引条目各为500字节(主键大小+聚簇索引的行数据),则在分割页面之前为2个新行留出空间。
当MySQL需要在整页上插入一行时,必须拆分该页面。 MySQL将添加一个新页面,并将一半页面数据移动到新页面。
在页面中,记录实际上可能不是物理顺序。他们将按照他们插入的顺序排列。它们通过链表的形式按顺序链接。因此,即使是随机插入也不会导致数据被物理重新排序。除了拆分页面之外,数据不会移动。
在随意插入后,您的页面将从1/2全部到完整。
所有这些工作确实会影响您的插入性能,因为必须使用每个插入更新索引。此外,具有多个半满页面的索引将对读取性能产生负面影响。
现在,如果您按索引顺序插入行,那么MySQL只会不断添加到页面的末尾,将它们填满15/16,并在页面时添加范围。由于没有页面拆分,因此性能损失要小得多,因此不涉及数据移动,更不用说几乎整页的读取性能优势。
因此,虽然更新插入索引涉及一些维护,但MySQL并没有重建"重建"每个插入的索引。另外,请参阅Bill Karwin的note about change buffering,这可能会对您产生影响。