堆是一个没有索引的表还是没有聚集索引?

7 index sql-server clustered-index heap nonclustered-index

BOL 似乎将堆定义为没有聚集索引的表。

但是许多在线帖子似乎将堆等同于没有任何索引的表。

有什么我不知道的微妙之处吗?

谢谢

Sol*_*zky 13

你需要非常小心你在互联网上阅读的内容;-)(当然,这也适用于这个答案或几乎任何地方,但仍然如此)。正如那里有很多好的信息一样,也有很多错误信息(遗憾的是,这不仅限于技术信息)。人们复制和粘贴/重新发布/共享两者。所以,问这个问题很好:-)。

尽管 BOL 确实有一些错误,但在这种情况下(和大多数情况下)它是正确的:堆特别是一个没有聚集索引的表。它与非聚集索引无关。当然,这可能是误解了这些“在线帖子”中所说的内容的一个简单案例,因为“没有任何索引的表”堆,但仅仅是因为没有索引就意味着没有聚集索引。但是,如果这些帖子声称只有非聚集索引的表不是堆,那么它们肯定是不正确的。

如果您查看,sys.indexes您会看到index_idof1是聚集索引,0是堆。一张表将有一个或另一个。不可能两者兼得。非聚集索引从index_id2开始并从那里上升。所有表的 index_id 都为0or1和可选的一个或多个index_id>= 2

您甚至可以使用以下查询对此进行测试:

SELECT COUNT(*)
FROM   sys.indexes si
WHERE  si.index_id IN (0, 1)
GROUP BY si.[object_id]
HAVING   COUNT(*) > 1;
Run Code Online (Sandbox Code Playgroud)

它永远不应该返回一行。

这是第二个测试,它更明显,不允许有人推测该条件可能存在但不存在,我认为通过上述测试是可能的:

-- DROP TABLE #tmp;
CREATE TABLE #tmp (Col1 INT, Col2 INT);
SELECT * FROM tempdb.sys.indexes si WHERE si.[object_id] = OBJECT_ID(N'tempdb.dbo.#tmp')
-- 1 row; index_id = 0 and type_desc = HEAP

CREATE NONCLUSTERED INDEX [IX_#tmp] ON #tmp (Col2 ASC);
SELECT * FROM tempdb.sys.indexes si WHERE si.[object_id] = OBJECT_ID(N'tempdb.dbo.#tmp')
-- 2 rows; index_id = 0 / HEAP and index_id = 2 / NONCLUSTERED

CREATE CLUSTERED INDEX [CIX_#tmp] ON #tmp (Col1 ASC);
SELECT * FROM tempdb.sys.indexes si WHERE si.[object_id] = OBJECT_ID(N'tempdb.dbo.#tmp')
-- still 2 rows (not 3!!); index_id = 1 / CLUSTERED and index_id = 2 / NONCLUSTERED
Run Code Online (Sandbox Code Playgroud)

第二个测试的重点是,关于 SQL Server 什么是真实的,什么是不真实的,权威始终是 SQL Server 本身。因此,测试本质上是向 SQL Server 提出问题,而不是人类,这一点很重要。即使专家有时也会出错,但 SQL Server 总是正确的(当然,关于 SQL Server 的问题)。


此外,虽然这不是任何明确的“证据”,但以下 MSDN 页面的标题相当有说服力:

堆(没有聚集索引的表)