我正在simple-talk阅读关于索引的文章,其中写道
如果堆上有一个非聚集索引(作为主键),并且将数据插入到表中,则必须进行两次写入。一种写入用于插入行,一种写入用于更新非聚集索引。另一方面,如果一个表有一个聚簇索引作为主键,插入只需要一次写入,而不是两次写入。这是因为聚簇索引及其数据是同一个索引。因此,将行插入到以聚集索引作为主键的表中比将相同数据插入到以非聚集索引作为其主键的堆中要快。无论主键是否单调递增,都是如此。
是不是错了?聚簇索引很自然地求助于 B+ 树,其中只有键存储在中间节点中(不像 B 树,其中存储了整个记录。这就是为什么 B+ 树可以在单个页面中容纳更多的键,导致它的宽度很大但高度较短),因此所有记录都存储在叶子页面中(页面本身通过链表进行逻辑排序,而每个页面中的数据进行物理排序)。因此,如果必须更新记录,比如值 1 必须更新为 7,更新是否需要应用于聚集索引顶部节点中的两个键(在某些情况下,这可能会导致重新整个结构的结构)和叶页记录中的相应值?
更新:好的,我做了一些研究,发现除了初始树结构(其中某些值必须出现两次,例如节点中的键值)之外,当插入新值时,它们刚好适合叶子页面,而树被重组以适应它。但是,当插入 5 个值时,第 3 个值可能会导致第一个插入的值(当前只占用叶级空间)级联起来,从而导致它被写入两次(一次在叶级,另一个在叶级)指数水平)。当然,这样的重写(虽然它们不会在插入时发生,但它们可以在以后发生)与每次使用 NCI 插入堆时发生的两次写入相比要少得多,但说没有重写仍然是错误的吗?
我认为这里的问题是术语上的差异。
通常所说的“写入次数”是对象访问次数,而不是物理操作所触及的页数。
通常将其用作讨论中的指标的原因是因为它是一个更“稳定”且更有意义的数字。当我们进入这里时,
INSERT
即使是一行的语句所涉及的页数也取决于许多因素,因此在您自己的环境和情况之外它不是一个非常有用的数量。我要从文章引用中挑选的一件事是(强调我的):
这可能令人困惑。向基表中插入一行将涉及对基表的插入,以及对每个非聚集索引的插入(忽略特殊索引功能),而不是更新。
是的,假设更新的列在索引键中。然而,这仍然是单个对象访问,因此是“单次写入”。