我有 Oracle 背景,在 Oracle 中为每个表使用“索引组织表”(IOT) 听起来不合理,我从未真正见过这一点。在 SQL Server 中,我处理的每个数据库在每个表上都有一个聚集索引,这与 IOT(概念上)相同。
这是为什么?是否有任何理由到处使用聚集索引?在我看来,它们只适用于少数情况。
谢谢
我有 Oracle 背景,在 Oracle 中为每个表使用“索引组织表”(IOT) 听起来不合理,我从未真正见过这一点。在 SQL Server 中,我处理的每个数据库在每个表上都有一个聚集索引,这与 IOT(概念上)相同。
这是为什么?是否有任何理由到处使用聚集索引?在我看来,它们只适用于少数情况。
谢谢
聚集索引与索引组织表并不完全相同。对于 IOT,每个字段都必须参与 IOT 密钥。SQL Server 上的聚集索引不必是唯一的,也不必是主键。
聚集索引在 SQL Server 上被广泛使用,因为几乎总是存在一些自然排序,这使得常用查询更加高效。Oracle 中的 IOT 承载了更多的包袱,因此它们并没有那么有用,尽管它们可能比它们通常被认为的更有用。
从历史上看,SQL Server 6.5 或 7.0 IIRC 之前的真正旧版本不支持行级锁定,只能锁定在表或页面级别。通常会使用聚集索引来确保写入分散在表的物理存储周围,以最大程度地减少页面锁的争用。但是,SQL Server 6 几年前就停止了支持,因此存在此问题的应用程序将仅限于罕见的遗留系统。
如果没有聚集索引,您的表将被组织为一个堆。这意味着插入的每一行都添加到表末尾的数据页中。此外,随着行的更新,如果更新的数据比以前大,它们将移动到表末尾的数据页。
什么时候最好没有聚集索引
如果您的表需要尽可能快的插入,但会牺牲更新和读取速度,那么没有聚集索引可能适合您。一个例子是,如果您有一个用作队列的表,例如,许多插入稍后会被读取并移动到另一个表。
聚集索引
聚集索引根据聚集索引中的列组织表中的数据。如果你聚集在错误的东西上,例如唯一标识符,这可能会减慢速度(见下文)。
只要您的聚集索引位于最常用于搜索的值上,并且它是唯一的并且不断增加,您就可以从聚集索引中获得一些惊人的性能优势。例如,如果您有一个名为 USERS 的表,您通常在其中根据 USER_ID 查找用户数据,那么在 USER_ID 上进行集群将加快所有这些查找的性能。这只是减少了为获取数据而需要读取的数据页的数量。
如果您的聚集索引中有太多键,这也会减慢速度。
聚集索引的一般规则:
不要聚集在任何 varchar 列上。
在 INT IDENTITY 列上进行聚类通常是最好的。
根据您通常搜索的内容进行聚类。
基于 UniqueIdentifiers 的聚类
在索引中使用唯一标识符时,它们的效率极低,因为没有自然的排序顺序。基于索引的 b 树结构,在使用 uniqueidentifiers 时,您最终会得到极其碎片化的索引。在重建或重组后,它们仍然极为分散。因此,您最终会得到一个较慢的索引,由于碎片,最终在内存和磁盘上非常巨大。同样在 uniqueidentifier 的插入中,您更有可能在索引上出现页面拆分,从而减慢您的插入速度。通常,唯一标识符对索引来说是个坏消息。
概括
我的建议是每个表都应该有一个聚集索引,除非有很好的理由不这样做(即表作为一个队列运行)。
我不知道为什么大多数时候你更喜欢堆而不是聚集索引。使用聚类,您可以免费获得一个您选择的索引。大多数情况下,这是主键(您可能无论如何都想强制执行!)。
堆主要用于特殊情况。
我们在关系数据库中使用主键,通常关系是通过这些主键建立的。大多数人习惯将第一个字段命名为 TableID 并将其设为主键。当您在查询中加入两个或更多表时,如果使用聚集索引,您将获得最快的结果。