大索引(MYSQL)会降低插入性能

大索引(MYSQL)会降低插入性能,mysql,Mysql,最近,我发现其中一台服务器的磁盘i/O流量很高。在一些诊断之后,由于在某些表上写入索引而导致的高I/O。我做了几次评估测试,发现mysql在向索引较大的表中插入记录时需要大量写操作 索引列的数据类型为varchar(15)和varchar(17),两者都是非唯一索引 如果我将20000条记录加载到包含10000条记录的表中,磁盘上只有80次写入,而当表增长到2000万条时,磁盘上有1700次写入(索引列上有大约100万个不同的值) 即使插入的记录数也是相同的 引擎是MyISAM 增加索引的大小也

最近,我发现其中一台服务器的磁盘i/O流量很高。在一些诊断之后,由于在某些表上写入索引而导致的高I/O。我做了几次评估测试,发现mysql在向索引较大的表中插入记录时需要大量写操作

索引列的数据类型为varchar(15)和varchar(17),两者都是非唯一索引 如果我将20000条记录加载到包含10000条记录的表中,磁盘上只有80次写入,而当表增长到2000万条时,磁盘上有1700次写入(索引列上有大约100万个不同的值) 即使插入的记录数也是相同的

引擎是MyISAM

增加索引的大小也会增加每次插入时磁盘上的写操作数


这是BTREE索引行为吗?我如何解决这个问题?

使用InnoDB而不是MyISAM

InnoDB通过缓冲对二级索引的写入、合并二级索引(如果可能)以及延迟昂贵的I/O来提供帮助。您可以在MySQL手册的下面阅读更多关于此功能的信息


请回复您的评论:

在B-树中插入新值可能会很昂贵。如果叶级别没有空间,则插入可能会导致拆分树的非叶节点的级联效应,可能一直到树的顶部。这可能会导致大量I/O,因为树的不同节点可能在磁盘上彼此相隔很远地存储

其他缓解策略是通过将较少使用的数据移动到另一个表中,使表变小。或者通过使用使一个逻辑表由多个单独的物理表组成。每个这样的子表必须有相同的索引,但每个单独的索引都会更小


这里有一个动画示例:

请看“将键33插入到B-树(w/Split)”示例,其中显示了将值插入到填充它的B-树节点的步骤,以及B-树的响应方式


现在想象一下,示例插图只显示了B树的较深的底部部分(如果索引B树有数百万个条目,则会出现这种情况),填充父节点本身可能会导致溢出,并强制拆分操作继续向树的较高级别进行。如果树顶部的所有祖先节点都已填充,则此操作可以一直持续到树的最顶端。

使用InnoDB而不是MyISAM

InnoDB通过缓冲对二级索引的写入、合并二级索引(如果可能)以及延迟昂贵的I/O来提供帮助。您可以在MySQL手册的下面阅读更多关于此功能的信息


请回复您的评论:

在B-树中插入新值可能会很昂贵。如果叶级别没有空间,则插入可能会导致拆分树的非叶节点的级联效应,可能一直到树的顶部。这可能会导致大量I/O,因为树的不同节点可能在磁盘上彼此相隔很远地存储

其他缓解策略是通过将较少使用的数据移动到另一个表中,使表变小。或者通过使用使一个逻辑表由多个单独的物理表组成。每个这样的子表必须有相同的索引,但每个单独的索引都会更小


这里有一个动画示例:

请看“将键33插入到B-树(w/Split)”示例,其中显示了将值插入到填充它的B-树节点的步骤,以及B-树的响应方式


现在想象一下,示例插图只显示了B树的较深的底部部分(如果索引B树有数百万个条目,则会出现这种情况),填充父节点本身可能会导致溢出,并强制拆分操作继续向树的较高级别进行。如果树顶部的所有祖先节点都已填充,则此操作可以一直持续到树的最顶端。

感谢您的回复,由于表处于生产环境中,不希望更改其引擎,是否有其他可能的方法来减少索引写入的I/O。另外,昂贵的I/O是B树的本质还是造成这种情况的任何原因。非常感谢您的明确解释,这意味着当叶节点溢出时,由于拆分节点的操作而产生的I/O,而当树增长时,成本会很高?由于我不太了解B-树的算法,这种行为会附加到所有rdbms中,比如ORACLE(尽管缓冲区上有i/O),非常感谢,但为什么主索引不会导致这样的问题?主索引容易出现这种问题。这就是为什么使用auto_increment主键是好的,因为它总是在索引的末尾添加新值,从而降低插入成本。感谢您的回复,有没有其他可能的方法来减少索引写入时的I/O,因为表处于生产环境中,不喜欢更改其引擎。另外,昂贵的I/O是B树的本质还是造成这种情况的任何原因。非常感谢您的明确解释,这意味着当叶节点溢出时,由于拆分节点的操作而产生的I/O,而当树增长时,成本会很高?由于我不太了解B-树的算法,这种行为会附加到所有rdbms中,比如ORACLE(尽管缓冲区上有i/O),非常感谢,但为什么主索引不会导致这样的问题?主索引容易出现这种问题。这就是为什么使用auto_increment主键是好的,因为它总是将新值放在索引的末尾,从而降低插入的成本。