【问题标题】:No direct access to data row in clustered table - why?无法直接访问聚集表中的数据行 - 为什么?
【发布时间】:2011-05-02 05:47:01
【问题描述】:

[11] 告诉:

"在非聚集索引中,叶级不包含所有数据。除了键值外,叶级(树的最低级)中的每个索引行都包含一个书签告诉 SQL Server 在哪里可以找到与索引中的键对应的数据行。
书签可以采用两种形式之一。 如果表有聚集索引,则书签是对应数据行的聚集索引键
.如果表是堆(换句话说,它没有聚集索引),则书签是行标识符 (RID),它是 File#:Page#:Slot# 形式的实际行定位器。"

这是聚集索引键的副本还是非聚集索引有指向它的指针?

是否应该遍历所有聚集索引结构,即具有中间数据的 b-tree,以通过聚集表上的非聚集索引书签获取行数据?

聚集索引导致直接引用变得不可能的原因是什么?


更新:
让我重新表述这个问题。这是如何完成的,我可以自己阅读,但我想了解为什么会这样做。

继续通过 RID 从具有(添加)聚集索引的非聚集索引中引用行数据会不会效率更高?

假设一个表只有非聚集索引(但没有聚集索引)。
非聚集索引叶子包含真实数据的 RID。无需查找/遍历即可直接访问行数据。

添加聚集索引意味着消除 IAM(索引分配映射)页面并用聚集索引键替换所有非聚集索引的所有 RID + 需要额外查找而不是直接访问。
这有什么意义?

更新 2:
我的问题是否被微软本人否决了?再次感谢,这是一种荣誉。
不解释就投反对票是没有意义的。

更新3:
@PerformanceDB",我无法理解您回答中的短语:

""这也意味着 B-Tree 的索引高度减少了一级(这就是为什么如果你检查它们它们很小的原因)。"

你能解释一下吗?

是的,我想要插图。

我开始阅读:Debunking myths about clustered indexes - part 4 (CIXs, TPC-C & Oracle clusters),它与许多其他来源一样,明确指出 SQL Server 与 Oracle 相比缺乏对聚簇表的直接访问功能。

Update4(Update5 - 已被删除):
一些回答者提到了这样一个事实,即 NCI 叶中的书签 CI 密钥用于在页面拆分的情况下实现地址独立性。

在使用 CI NCI(非聚集索引)的非聚集表中的索引重组或碎片整理期间,NCI 中的行重定位和相应的 RID NCI 中的更改罢工>被修改?

在我看来,这似乎是寻址方案的缺陷——该行应该随着它的地址移动,不是吗?
此外,堆是否完全不受页面拆分的影响?由于行中可变大小数据类型的大小增加


相关问题:

引用:
[11]
Microsoft® SQL Server™ 2005 内部:存储引擎
由 Kalen Delaney -(坚实的质量学习)
..................................
出版商:微软出版社
发布日期:2006 年 10 月 11 日
打印 ISBN-10:0-7356-2105-5
打印 ISBN-13:978-0-7356-2105-3
页数:464

[11a] p.250 第 7 章中的索引组织。索引内部和管理

这是有用的在线复制粘贴
http://sqlserverindexeorgnization.blogspot.com/

虽然没有任何来源的学分

【问题讨论】:

  • +!谢谢。提问者通过单击信封按钮以及添加到他收藏夹中的问题的帖子和 cmets 来查看他自己问题的答案。我现在将在我的主要帖子中添加对您的回答的澄清问题

标签: sql-server database performance database-design indexing


【解决方案1】:

问题在于 doco 是 gobbledegook,并增加了它声称它澄清的混乱。如果您忘记所有这些并重新开始,那实际上是非常简单的。由于您正在查询数据存储结构并关注性能,让我们看一下这个角度(不是逻辑)。没有称为“表”的数据存储结构。

包含行的数据页。没有聚集索引。由于插入/删除,行不会移动。这些行可以全部读取(表扫描)或单独读取(通过非聚集索引)。它变得非常分散。

聚集索引

B 树。索引与数据行聚集。叶级数据行。这意味着 次访问减少了一次 I/O。这也意味着 B 树的索引高度减少了一级(这就是为什么如果你检查它们它们很小的原因)。堆(整个数据存储结构)被淘汰。没有指针。行以聚集索引键顺序维护(由于插入/删除/扩展,行在页面上移动)。页面在范围内被修剪。

非聚集索引

B 树。行数所需的全高。

  1. 在有聚集索引的地方,叶子级别是聚集索引键(这样它就可以到达 CI 中的确切位置,也就是行)。

  2. 在没有聚集索引的地方,叶子级别是一个指针:File:Page:Offset(这样它就可以去堆,并获取行)。堆中的 RowIds 不会改变(如果他们改变了,每次您插入/删除 一个 行时,您都必须更新所有关联 NCI 中的所有 NCI 条目,对于所有 other 行)。

这就是为什么当您创建 CI 时,所有 NCI 都会自动重建(它们必须从 [2] 切换到 1)。显然,始终在 NCI 之前创建 CI。

没有File:Page:Slot,行长是可变的,是Page内的Offset。

没有书签或其他 goobledegook。

关于“无法直接访问聚簇表中的数据行 - 为什么”

废话。您可以通过 CI(少一个 I/O)或 NCI⇢CI Key 直接访问每个数据行。

这是非常快的,由 Britton Lee 发明;由 Sybase 重新实施并获得专利;通过不诚实和达斯维德的微薄获得。

如果您需要进一步说明,我可以提供插图。


评论回复


“这也意味着 B-Tree 的索引高度减少了一级(这就是为什么如果你检查它们它们很小)。”

假设您有一个包含 10 亿行的表。垂直绘制的任何给定索引(例如,唯一的,在 PK 上)的 B 树的“高度”是 8;或者您可以说索引是 8 级深,在顶部(单个条目)和底部(叶级)之间。叶层当然是最宽的,也是最多的;它将有 10 亿个条目。假设每个索引页包含 256 个条目,则叶减一级别包含 390K 条目。

CI B-tree(仅索引部分)将包含 7 个级别,390K 条目,占用 10MB;因为叶级是数据行(其中有 10 亿个条目,很好地分布在 100GB 中),因此被排除或不重复。

是的,我想要插图。

好的。我有一套完成的 Sybase 文档;为了避免混淆,我为您截取了一个,并排除了 Sybase 拥有的位,而 MS 没有。对不起。不要跟随链接,只停留在一页上。此外,在 Sybase 和 MS 中,堆中的碎片非常大,因此堆中非常低的碎片水平有所不同,因此我将其保持不变。

Data Storage Basics

(这是我更详细的 Sybase 图表的精简版本,我已经为 MS 上下文进行了屠宰。如果您想要完整的 Sybase 集,该文档底部有一个链接。)

“我开始阅读:揭穿关于聚集索引的神话 - 第 4 部分(CIX、TPC-C 和 Oracle 集群),它与许多其他来源一样,明确提到 SQL Server 与Oracle,缺乏对聚簇表的直接访问功能。”

小心你阅读的内容,网络上充斥着肤浅的信息;断章取义地讨论了一半的真理;错误信息(来自供应商以及善意的无知者)。如您所见,我只是回答问题;我不会浪费时间回答参考文献中提出的问题。

想想这个。实施良好的带有 CI 的表不需要碎片整理;并且当实施不好时,需要不经常的碎片整理;没有 CI 的表需要频繁且几乎离线的碎片整理。那是你的维护窗口运行到星期一早上。只是一个为什么孤立地讨论项目实际上是错误信息的例子。这就是为什么我的文档都相互关联并相互关联的原因。

“一些回答者提到了这样一个事实,即 NCI 叶中的 CI 密钥是为了在页面拆分的情况下实现地址独立性。”

是的,我只是不会那样说,这和您发布的第一个参考一样令人困惑。页面拆分与它无关。为了清楚起见,我故意在上面的帖子中这样做。由于行移动(CI 保持页面和 Extents 修剪),NCI 必须具有 CI 键,才能找到行。它不能使用会一直变化的 RowId。除非您有广泛的 CI 密钥,否则这没什么大不了的。一个 4 字节的 RowId(加上处理开销)与一个 8 字节的 CI 密钥(减去所说的开销)......谁在乎(好吧,也许是你)。解决更高级别的问题,而低级别的问题将小到不值得解决。当您的数据库碎片化且未标准化时,在低级别挤出 1% 的性能提升是有点愚蠢的。

由一组集成组件组成的系统,没有一个可以单独更改或评估。一堆未集成的组件被分解,而不是系统。在你的质疑水平上,你还没有能力形成结论,或者对这个或那个有怨恨,如果你这样做了,它们是不成熟的结论和怨恨,这会阻碍你的进步。最重要的是,通过问答获得的知识与通过阅读加经验获得的知识之间存在很大差异。

“在使用 CI 对非聚集表进行 undex 重组或碎片整理期间,NCI 中的行是否已重定位并且 NCI 中的相应 RID 会发生变化?”

你的意思是 "non-clustered INDEX with CI" 吗? NCI 不值得进行碎片整理,只需删除/创建它们即可。

或者您的意思是 “对 CI [整个表] 进行碎片整理” ?我已经发布过,当您重新创建 CI(或对其进行碎片整理)时,会自动重建 NCI。这与 RowIds 无关,而是关于更改:当您删除 CI 时,NCI 必须从 CI 键重写为 RowIds;创建 CI 时,NCI 必须改回 CI 密钥。已启用的 DBA 在删除 CI 之前先删除 NCI。

“在我看来,这似乎是寻址方案的缺陷 - 该行应该随着它的地址移动,不是吗?” 在不了解更高级别的情况下,您的级别太低了。如果行移动,它的地址就会改变;如果地址改变,则行移动。要么你有一个 CI(行移动)x 要么你有一个堆(行不移动)。

“另外,堆是否完全不受页面拆分的影响?”

没有。当可变长度行扩展并且页面上没有空间时,仍然会发生页面拆分。但是在事情的方案中,由于从不移动行,由于它是基于 RowId(NCI 依赖),堆上的大量碎片,这是一个小项目。

【讨论】:

【解决方案2】:

我不会发布这个(我的)问题,我在发帖之前看到过that answer by AlexSmith there,我在发帖后几分钟就看到了,并且已经在这里得到了回答:

很遗憾,这里无法接受它作为答案

更新:
accepted here answer by PerformanceDBA 告诉:“问题是 doco 是 gobbledegook,并增加了它声称它澄清的混乱”

嗯,所有的 msdn 文档都会讲述和展示,例如,cf。来自Clustered Index Structures"Heap Structures" 的图片,聚集表没有IAM 页面。同时,遵循Inside the Storage Engine: Using DBCC PAGE and DBCC IND to find out if page splits ever roll back 的代码的输出显示相反。

不想继续在这里发送垃圾邮件,我将提问和参与转移到 /www.sqlservercentral.com/Forums

我的相关问题:

【讨论】:

  • 人类的天性是在宇宙中找到与他们的思维方式一致的事物,而在同一个宇宙中寻找与他们的思维方式不同的事物,就像免费提供的一样。它不会使一个或另一个“正确”,不,这需要一个合格的小组进行更多的评估和考虑;它只是重新强化了这种心态。另一方面,开放、探究的思想以不同的方式发展。
【解决方案3】:

继续通过 RID 从具有(添加)聚集索引的非聚集索引中引用行数据会不会效率更高?

聚集索引的全部意义在于记录是通过逻辑定位器访问的(通常不会改变),而不是物理的。

如果索引指向物理 RID 并且行更改了其物理位置(例如从页面拆分),则所有索引也需要更新。

这正是发明聚集索引来处理的那种问题。

【讨论】:

    【解决方案4】:

    这样做不是更有效率吗? 继续按 RID 引用行数据 从非聚集索引有 (添加)集群一个?

    在许多情况下,它会更有效,是的。我相信聚集索引最初是这样实现的(在 6.0 版中?)。据推测,由于 marc_s 提到的原因,它们被更改了,如果您的聚集索引有很多页面拆分,这是有道理的。

    【讨论】:

      【解决方案5】:

      让我重新表述这个问题。如何 这完成了我可以自己阅读,但我 想了解为什么这样做 方式。

      这样做不是更有效率吗? 继续按 RID 引用行数据 从非聚集索引有 (添加)集群一个?

      不!如果表有插入,并且发生页面拆分,那么您可能必须更新许多使用 RID 指向这些数据行的新位置的引用已移动到 SQL Server 中的新页面。这正是为什么 SQL Server 团队选择使用集群键 作为“数据指针”,可以这么说。发生页面拆分时,集群键的值不会改变,因此不需要更新索引。

      【讨论】:

        【解决方案6】:

        如果表具有聚集索引,则每个非聚集索引行都包含聚集索引键的副本。

        如果一个表没有聚集索引,即该表是一个堆,则每个非聚集索引行都包含一个指针,该指针由文件标识符 (ID)、页码和页面上的行号构建而成。整个指针称为行 ID (RID)。

        当您使用聚集索引识别(选择)一行时,您将拥有该行的所有列。 当您在非聚集索引中识别出一行时,您需要执行另一个查找步骤以获取未包含在非聚集索引中的列。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-04-28
          • 1970-01-01
          • 1970-01-01
          • 2011-12-14
          • 1970-01-01
          • 2022-12-03
          • 1970-01-01
          相关资源
          最近更新 更多