我是 SQL 和数据库管理的初学者,我试图理解聚集索引和非聚集索引之间的区别。我或多或少地理解了不同的任务是什么,但是在谈到“指针”问题时我有一些问题。我不是来自 CS,所以我有一些问题来想象指针在“叶级”会发生什么,以及它们以何种方式将索引连接到数据。那么,聚集索引不存储指向数据的指针是什么意思,而非聚集索引呢?
如果这些问题听起来很愚蠢,请提前抱歉,但此时我很困惑!
我是 SQL 和数据库管理的初学者,我试图理解聚集索引和非聚集索引之间的区别。我或多或少地理解了不同的任务是什么,但是在谈到“指针”问题时我有一些问题。我不是来自 CS,所以我有一些问题来想象指针在“叶级”会发生什么,以及它们以何种方式将索引连接到数据。那么,聚集索引不存储指向数据的指针是什么意思,而非聚集索引呢?
如果这些问题听起来很愚蠢,请提前抱歉,但此时我很困惑!
不,这不是一个坏问题。
在 MS SQL Server(和其他类似的工作方式)中,聚集索引不存储指向数据的指针,因为它不需要,聚集索引实际上包含表数据本身。
聚集索引是表,只是以特定方式排序。
如果您创建并填充一个没有聚集索引(称为“堆”)的全新表,然后添加一个非聚集索引,那么您将创建一个新的(有序)对象,该对象仍然必须指向实际中的行表。
但是如果你使用那个堆并添加一个聚集索引,你实际上是在重新排序表本身。
堆只是一堆上面有行的页面,实际上并没有任何关于表单 SQL Server 跟踪“该表由此页面列表表示”的位置的信息。要找到任何东西,它必须扫描整个批次(除非您使用
TOP 1
orTOP <n>
或OFFSET
/FETCH
在这种情况下它可能会扫描直到找到足够的行)。索引是一种树结构,它使查找内容比扫描所有内容要快得多。我不会详细介绍索引/树结构(尽管请参阅打击以获得有用的参考),但使用索引意味着您只需阅读几页而不是数千页即可找到特定的东西。树在顶层有一个根节点,在底层有一个叶子节点,中间有一个分支节点。
SQL Server 中堆上的非聚集索引在其叶节点中引用了数据在 DB 中的位置:该页面中的文件、页面和行号。因此,一旦您到达树的底部,您仍然需要阅读页面,如果有很多匹配项,则可能每个找到的行都有一个。
SQL Server 中的聚集索引(该术语在 postgres 和其他地方的含义略有不同)包含叶节点中的实际行数据:不需要额外的查找。这就是聚集索引对范围查询特别有用的原因:您可以在同一页面上找到与过滤器匹配的几行(可能是几百行)的数据,因此无需进行进一步查找。
具有聚集索引的表上的非聚集索引与堆上的索引非常相似。不同之处在于,叶子节点不包含指向数据在堆中位置的指针,而是包含行的聚集键,因此可以通过聚集索引找到额外的数据(除非您需要的所有内容都包含在索引值中,值和聚类键,在
INCLUDED
这种情况下不需要进一步查找)。似乎聚集表上的非聚集索引可能比非聚集索引效率低,但聚集索引中的搜索只会是一页或几页,还有其他因素可以使堆查找比读取索引指向的一页效率低,而且堆在其他方面也可能效率低下。
有关更多详细信息和一些图表,请参阅https://learn.microsoft.com/en-us/sql/relational-databases/sql-server-index-design-guide#Clustered上的官方文档。或者,如果您有一点时间学习游戏,请尝试 Brent Ozar 的How To Think Like SQL Server。