为什么在索引表中只有读取速度更快,而写入速度却更快?

Sus*_*wat 4 sql database indexing performance database-indexes

用于在数据库表中建立索引的数据结构是 B-Tree(默认,B-Tree、R-Tree、Hash)。既然 B-Tree 中的查找、删除和插入都可以在对数时间内完成,那么为什么只有索引表的读取速度更快,而写入速度却更慢呢?

gmi*_*ley 5

索引仅用于加速SELECT语句。对于INSERTUPDATE、 和DELETE您的语句将比正常情况慢,因为索引需要作为语句的一部分进行更新。

我也许应该澄清UPDATE/DELETE这一点。确实,由于索引的更改增加了开销,语句会变慢,但是and语句WHERE的初始查找部分 ( )可能会由于索引而加快。基本上任何使用子句并且引用索引字段的地方,该语句的记录选择部分都应该看到一些增加。UPDATEDELETEWHERE

此外,如果UPDATE语句不更改属于索引的任何列,那么您不应该看到任何额外的缓慢,因为索引没有更新。


Bac*_*its 5

因为索引需要额外的磁盘空间。索引增加了需要记录和写入数据库的数据量。索引会降低写入性能。当更新索引覆盖的列时,该索引也必须更新。同样,任何删除或插入都需要更新相关索引。

索引的磁盘空间和写入损失正是您在创建索引时需要小心的原因。

也就是说,对非索引列的更新可以通过索引提高其性能。

这:

UPDATE Table SET NonIndexedColumn = 'Value' WHERE IndexedKey = 'KeyValue'
Run Code Online (Sandbox Code Playgroud)

会比这个更快:

UPDATE Table SET IndexedColumn = 'Value' WHERE IndexedKey = 'KeyValue'
Run Code Online (Sandbox Code Playgroud)

但在任何合理大小的表中,上述两个可能都比这更快:

UPDATE Table SET NonIndexedColumn = 'Value' WHERE NonIndexedKey = 'KeyValue'
Run Code Online (Sandbox Code Playgroud)

即使表和索引需要更新,删除(尤其是单个删除)同样可以更快。这只是因为查询引擎可以更快地找到目标行。也就是说,读取索引、查找行、删除行并更新索引可以更快,而不是扫描整个表以查找正确的行并删除相关行。然而,即使在这种情况下,也会有更多的数据需要写入;只是扫描整个表的 IO 成本与索引相比可能相当高。

最后,从理论上讲,将插入分散到多个磁盘页面的集群键可以允许系统支持更多并发插入,因为插入通常需要页锁才能发挥作用,但这是一种不太常见的情况,并且可能会导致更差的读取性能,因为对聚集索引进行碎片化。