【问题标题】:How are the table data stored when it has a clustered index有聚集索引的表数据如何存储
【发布时间】:2012-08-26 04:13:05
【问题描述】:

我发现了很多类似 开头的帖子。很多时候我遇到过有人说“聚集索引基于聚集索引键对表内的数据进行物理排序”。这不是真的! 然后这些帖子继续描述它是如何通过链接列表或其他方式实际存储的。例如,post 表示

每个索引行都包含一个键值和一个指向任一索引的指针 B-tree 中的中间层页面,或 Leaf 层中的 Data 行 的指数。索引的每个级别中的页面都链接在一个 双向链表。数据链中的页面和其中的行 按聚集索引键的值排序。

这就引出了我的问题,数据页存储表格数据的地方,对吧?那么如果对它们进行排序,并且其中的数据也按照索引列的值进行排序,为什么说聚集索引保持表数据按排序顺序是错误的呢?这是一张来自 Kalen Delaney 书中的图片,它显示了带有 CI 的表中的叶子页都是根据 CI 值排序的:

【问题讨论】:

    标签: sql indexing clustered-index


    【解决方案1】:

    下面的博文清楚地解释了聚集索引是如何存储的。

    Does a Clustered Index really physically store the rows in key order?

    【讨论】:

      【解决方案2】:

      当你创建索引时,还会创建一个索引表(我认为它称为索引分配图(IAM),不太确定名称) 在聚集索引的情况下,索引表包含索引列,以及指向实际记录的指针。

      所以当表有聚集索引时,数据可能不会在表上进行物理排序.. 磁盘中的数据将作为链表维护,聚集索引是指向该数据的指针。

      现在索引表将被物理排序......而不是实际的表......并且索引表被维护为 B-Tree,因此搜索会更快。

      现在当你创建一个非聚集索引时,它会指向聚集索引表

      编辑:(正如 marc_s 指出的那样)聚集索引的叶节点实际上包含数据,而在非聚集索引中包含指针..

      但我还是不相信,它会重新排序磁盘中的数据,它只会重新排序指针

      【讨论】:

      • 所以你的意思是说会有两个相同数据的副本,一个在 B-Tree 中按排序顺序,另一个在实际表中按插入顺序?就空间而言,这不会非常低效吗?
      • @Cupidvogel:索引表将只有列,它们是索引的一部分
      • 其实 - 聚集索引 IS的数据的叶级
      • @marc_s:当我们向表中插入一条记录时,叶子节点会受到影响..还是叶子节点的指针?
      • 如果有足够的空间容纳新行,该行将被插入到叶级页面中。如果不是 - 将发生页面拆分。当然,叶级以上的索引页也会更新(使用新的集群键条目)
      【解决方案3】:

      你是对的。

      聚集索引根据聚集索引键对表内的数据进行物理排序。如果是这种情况,那么插入到没有可用空间的大表中间将需要大量的 IO 来为新记录腾出空间。

      而是从文件中的任何位置分配一个新页面并链接到链接列表中。

      页面的物理顺序与逻辑顺序的不同程度就是逻辑碎片的程度。重建或重组索引可以减少这种情况。

      【讨论】:

      • 叶级页面不一定排序。只有在逻辑分类为零时,它们才会完全排序。
      • 没什么。叶级页面表。它们不是两个不同的东西。它们保存在一个可能会或可能不会排序的链接列表中。页面乱序的程度就是碎片化的程度。链表有可能从页面100 -> 101 -> 102 进行(例如),在这种情况下零碎片,或者它可能从页面100 -> 200 -> 150 进行,在这种情况下,有100% 的碎片。
      • NCI 的叶级别仅包含索引中定义为键列或包含列的列的数据。 CI 的叶级别包含所有列的数据。 (忽略内容存储在行外的宽表)。具有整个表的INCLUDE-d 列的 NCI 与 CI 的结构几乎相同。
      • @Cupidvogel - 您不能仅在这 3 列(除非它们是表中的唯一列)上创建聚集索引,因为 CI 将隐含 @987654324 @所有其他列。
      • 对不起。我失去了接受这次谈话的意愿。我不知道我需要重复多少次同一点。叶级页面没有必要排序。只有当逻辑碎片为零时,它们才会完全排序
      【解决方案4】:

      我原来的陈述是错误的
      因为任何索引都不会影响表中的数据。聚集索引只是另一种类型的索引指向表中的数据。它不会更改顺序或对数据执行任何其他操作。
      您始终可以在创建(聚集或非聚集)索引之前和之后直接从具有行号的表中获取数据。
      原始语句结束

      需要更正(我不经常使用 MSSQL,所以以前没有机会测试过)
      似乎 MSSQL 将聚集索引实现为根本不是真正的索引,但可能更接近触发器/约束对。

      根据我现在的粗略测试:

      1)

      CREATE TABLE testTable ...  
      INSERT ... (few rows)  
      SELECT * FROM testTable  
      

      这会按插入顺序显示所有结果

      2)

      CREATE CLUSTERED INDEX ... ON testTable (...); 
      INSERT ... (few rows)  
      SELECT * FROM testTable  
      

      这显示了按CLUSTERED INDEX中的字段排序的所有结果
      3)

      DROP INDEX (CLUSTERED INDEX Name) ON testTable;
      INSERT ... (few rows)  
      SELECT * FROM testTable  
      

      这显示了步骤 2) [在 DROP INDEX 之前] 以相同顺序 和稍后插入的行 [在步骤 3)] 中的所有结果。

      对我来说,这意味着 MSSQL确实 重新排序实际的数据记录(很可能在插入/删除时付出了巨大的代价)。

      所以,我接受纠正和谴责。老实说,我从没想过会出现这种情况(聚集索引行为,而不是我被证明是错误的)。

      【讨论】:

      • 非聚集索引也是如此,那么它与聚集索引有何不同?
      • 但是我看到太多的帖子和太多的书都说没有错,聚集索引不会影响数据在表中的存储方式!
      • 其实 - 聚集索引 IS的数据的叶级
      • @Germann 没关系,我们在学习的过程中都会犯错,但是在这里,一旦你犯了错误,你就会在眨眼之间受到惩罚!没问题,无论如何感谢您的努力...
      • @Cupidvogel 我不介意被纠正 - 它有助于我学习......有时假设非常具有误导性 - 因为它们可能会导致走向错误的方向。
      【解决方案5】:

      聚集索引按索引的列对表数据进行排序。插入或更新时,每个新行都将位于表格的正确位置。

      非聚集索引不会发生这种情况。

      【讨论】:

        猜你喜欢
        • 2023-03-10
        • 2020-09-15
        • 2017-12-02
        • 1970-01-01
        • 1970-01-01
        • 2023-03-26
        • 1970-01-01
        • 1970-01-01
        • 2014-09-08
        相关资源
        最近更新 更多