【问题标题】:Does MySQL update the index on all inserts? Can I make it update after every x inserts?MySQL 是否更新所有插入的索引?我可以在每 x 插入后更新它吗?
【发布时间】:2014-06-19 13:32:29
【问题描述】:

我有几个关于 MySQL 索引的相关问题:

  1. MySQL 是否在每次插入内容时更新索引?
  2. 当 MySQL 因插入而更新索引时,是否会重建整个索引?
  3. 有没有办法让 MySQL 在每次插入 x 后更新索引?

我的应用程序中有很多插入,我担心 MySQL 在每次插入后都会重建索引。数据不必是实时的,因此我可以在特定数量的插入后更新索引(如果可能的话)。

【问题讨论】:

  • 你不能用Trigger来做这个吗?
  • 不清楚您的要求。您的更新有问题吗?有索引吗?究竟是什么问题,为什么你认为“在特定数量的插入后更新索引”会有所帮助?或者你很好奇 MySql 是如何在内部做到这一点的?来源可用;你调查过吗?

标签: mysql sql indexing


【解决方案1】:

当 MySQL 因插入而更新索引时,它会重建索引吗? 整个索引?

不,MySQL 不会在每次插入时“重建”索引。

MySQL 的默认页面大小为 16K。它以 1MB 的增量分配这些页面(称为扩展区)。

第一次创建表时(重建索引),页面被填满 15/16,为一些随机插入留出空间。如果您的索引条目每个为 500 字节(主键大小 + 聚集索引的行数据),则在必须拆分页面之前为插入 2 个新行留下空间。

当 MySQL 需要在整页上插入一行时,必须拆分页面。 MySQL 将添加一个新页面,并将一半的页面数据移动到新页面。

在一个页面内,记录实际上可能不是按物理顺序排列的。它们将按照插入的顺序排列。它们通过链表的形式按顺序链接。因此,即使是随机插入也不会导致数据在物理上重新排序。除了需要拆分页面之外,数据不会四处移动。

随机插入后,您的页面将从 1/2 满到满。

所有这些工作都会影响您的插入性能,因为每次插入都必须更新索引。此外,具有许多半满页的索引会对读取性能产生负面影响。

现在,如果您按索引顺序插入行,那么 MySQL 只会不断地添加到页面的末尾,将它们填满 15/16,并在页面的时间添加一个范围。由于没有页面拆分,因此性能损失要小得多,因此不涉及数据移动,更不用说几乎整页的读取性能优势了。

因此,虽然更新插入索引时需要进行一些维护,但 MySQL 不会在每次插入时“重建”索引。另外,请参阅 Bill Karwin 的 note about change buffering,这可能会影响到您。

【讨论】:

    【解决方案2】:

    MySQL 可能已经在尽你所能做到了。

    对于 InnoDB(它应该是 MySQL 的默认存储引擎),插入、更新和删除会立即更改主键或唯一键索引。但他们从不重建整个索引,他们将新值添加到这些索引中(或从中取出值)。

    对于非唯一索引,InnoDB 执行change buffering。也就是说,它将更改排队,稍后将在后台合并到索引中。它甚至会整合更改,以便更有效地完成对索引的物理更新。

    您无需执行任何操作即可启用此功能,因为默认情况下已启用。 MySQL 5.1 仅更改 INSERT 的缓冲。 MySQL 5.5 及更高版本还会更改 UPDATEDELETE 的缓冲。

    如果需要,您可以禁用此功能(例如,如果您使用 SSD,避免随机 I/O 并不那么重要,您可能希望确保队列中的更改不会累积) .通常,您应该保持启用该功能。

    【讨论】:

      【解决方案3】:

      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,这一点很重要,因为它需要二级索引来查找重复键(主键除外)。

      【讨论】:

        猜你喜欢
        • 2012-01-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-28
        • 1970-01-01
        • 2016-01-13
        • 1970-01-01
        • 2022-01-14
        相关资源
        最近更新 更多