据我所知,HEAP表只会对于审计表和/或插入比选择频繁发生的地方很有用。这样就可以节省磁盘空间和磁盘I / O,因为没有要维护的聚簇索引,而且由于非常少的读取,因此不会产生额外的碎片。
#1 楼
唯一有效的用途是用于导入/导出/ ETL流程中使用的临时表。
使用
SELECT * INTO..
临时,临时和短期备份表临时表在使用之前/之后通常相当平坦且被截断。
请注意,与数据大小相比,聚簇索引通常很小:数据是最低级别索引结构。
堆表也有问题。至少这些:
不能进行碎片整理以减少磁盘空间。这很重要,因为例如,已使用的数据页将散布在整个MDF上,因为数据没有来自聚集索引的“顺序”。非聚集索引现在指向该行,而不是聚集索引条目。这会影响性能:需要通过具有非聚集索引的聚集索引访问数据
另请参见
http:/ /www.sqlbadpractices.com/heap-tables/(错误的做法)
http://msdn.microsoft.com/zh-cn/library/hh213609.aspx(MS的建议)
http://sqlskills.com/BLOGS/PAUL/post/A-SQL-Server-DBA-myth-a-day-(2930)-fixing-heap-fragmentation.aspx(Paul Randal的DBA神话)
评论
它通常将堆用于两个单独的事物。当临时表有效设置时,我使用ETL暂存和工作表临时存储数据。所有这些在下一次加载时都会被截断。
–赞恩
2012年11月9日17:12
好的问题。
–赞恩
2012年11月9日17:12
略微调整-如果在进行更改之前执行SELECT INTO以便创建小表的快速备份,则默认情况下会创建堆。我会说这是有效的用法-但这只是挑剔。我想知道我的工作完成后就想摆脱那个堆。
–布伦特·奥扎(Brent Ozar)
15年4月23日在21:45
@BrentOzar:同意,我一直在做。我的回答是“长期和持久性表格”,但我会更新
– gbn
15年5月6日在6:38
#2 楼
主要注意事项我看到堆的一个重要优点和集群表的一个重要优点,以及可以同时使用的第三个注意事项。
堆可以为您节省一个间接层。索引包含行ID,它们直接指向磁盘位置(不是真的,而是尽可能直接)。因此,针对堆的索引查找应该花费大约是针对聚簇表的非聚簇索引查找的一半。
归因于(几乎)自由索引,聚簇索引本身得以排序。因为聚簇索引是按照数据的物理顺序反映的,所以它在实际数据本身的顶部占用相对较小的空间,当然无论如何您都必须存储这些空间。因为它是物理排序的,所以对该索引进行范围扫描可以查找到起点,然后非常高效地将其压缩到终点。
堆上的索引引用RID(64位)。如前所述,聚簇表上的非聚簇索引引用聚簇键,聚簇键可以更小(32位
INT
),相同(64位BIGINT
)或更大(48位DATETIME2()
加32位INT
或128位GUID)。显然,更广泛的参考文献提出了更大,更昂贵的索引。空间要求
使用这两个表:
CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)
CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)
...每个记录都填充870万条记录,两个记录所需的空间均为150 MB;群集表的索引为120 MB,非群集表的索引为310 MB。这反映出聚簇索引比RID窄,并且聚簇索引主要是“免费赠品”。如果在
ID2
上没有唯一索引,则非集群表的索引空间将降至155 MB(如您所料,为一半),而集群PK的索引空间将仅为150 KB-几乎没有内容。因此,具有32位索引(名义上总共64位)的群集表中的32位字段的非聚集索引占用了120 MB,而具有64位的堆中的32位字段的索引却占用了120 MB RID(总共96位,名义上)占用了155 MB,比天真地预期从64位密钥更改为96位密钥所增加的50%略少,但是当然,开销会减小有效大小的差异。 />
填充两个表并创建它们的索引对于每个表花费的时间相同。在运行涉及扫描或搜索的简单测试时,我发现表之间没有实质性的性能差异,这与gbn有用链接的Microsoft白皮书相符。所述论文的确显示出高度并发访问的显着差异。我不确定为什么会发生这种情况,希望比我有更多经验的大容量OLTP系统能够告诉我们。
添加〜40字节的随机可变长度数据不会明显改变这种等效性。也不用宽UUID替换
INT
(每个表的速度减慢到大约相同的程度)。您的里程可能会有所不同,但是在大多数情况下,是否有索引比哪种索引更为重要。零碎的数据
对非聚集索引进行范围扫描-由于表是堆或索引不是聚簇索引-涉及到扫描索引,然后针对每个命中对表进行查找。这可能非常昂贵,因此仅扫描表有时会更便宜。但是,您可以使用覆盖索引来解决此问题。无论是否对表进行群集,这都适用。
正如@gbn所指出的,没有简单的方法来压缩堆。但是,如果您的表随着时间的推移逐渐增加-这是非常常见的情况-几乎没有浪费,因为删除所释放的空间将被新数据填充。
我见过的一些关于堆与集群表的讨论提出了一个奇怪的草人论点,即没有索引的堆不如集群表,因为它总是需要进行表扫描。确实是这样,但是更有意义的比较是“大型索引良好的群集表”与“大型索引良好的堆”。如果您的表很小,或者您总是要进行表扫描,那么对它进行集群与否无关紧要。
因为集群表中的每个索引都引用了聚类索引,它们实际上是所有覆盖索引。引用索引列和集群列的查询可以执行索引扫描,而无需任何表查找。如果您的聚簇索引是一个合成键,那么通常这没有什么价值,但是如果您还是需要检索它的一个业务键,那么这是一个不错的功能。
TL; DR
我是数据仓库专家,不是OLTP专家。对于事实表,我几乎总是在最可能需要范围扫描的字段(通常是日期字段)上使用聚簇索引。对于维度表,我在PK上进行了聚类,因此已针对事实表进行了合并联接的预排序。
有多个使用聚类索引的原因,但是如果这些原因都不适用,那么开销可能就不值得了。我怀疑人们普遍使用聚簇索引的背后有很多“我们总是这样做”和“这只是最佳实践”。尝试使用数据和负载,看看哪种方法最有效。
#3 楼
我认为至少可以说,“唯一有效的用途是用于导入/导出/ ETL流程中的登台表”。您必须采用给定系统的预期用例,然后根据堆或索引组织表的优点进行选择(我知道,这是一个Oracle术语,但描述得很好)。我们的仓库装载了约1.5个每天要处理十亿行,并且必须支持高度并发的写入,处理以及读取。关系存储支持OLAP数据库,因此读取通常主要是表扫描。生成的报告和下游提要通常也没有足够的选择性,因此任何索引都将是有用的。该系统支持数据的滑动窗口,因此,一旦加载了表,我们很少再写入该表,并且鉴于表分区的实施效果较差,需要Sch-M锁进行分区拆分,切换和合并,而Sch-S锁进行读取等。 ,尽管我们也有一些分区表,但系统必须使用许多表。使用许多表有助于简化数据分段和清除周期,同时还减少了争用。
因此,在某些任意列上索引组织表(聚集表)的开销增加了能够将bcp放入堆,处理OLAP分区,执行一些表扫描查询,然后在3天后删除它意味着这是不值得的。请注意,在我们的情况下,数据是从大型网格集群返回的,因此也没有对数据的排序,因此插入具有聚集索引的表中可能会引入其他问题,例如“热点”和页面拆分等。
另外,我认为关于页面分散的争论有些不屑一顾。聚集索引的页面也可以分散在整个文件中。只是在重新索引(假设超过1000页)之后,这可能比堆更好,但随后您还必须重新索引。
如果需要的话,还可以使用稀疏列和压缩来节省空间。确实,在某些情况下
在具有聚集索引的表上进行选择可能会更快,但是您必须权衡使用它进行加载和维护所需的资源。
[编辑]我可能应该弄清楚,只有我们未分区的事实表是堆。分区表和维表都具有聚簇索引,以支持有效的查找等。
[Edit2]已将25亿修正为15亿。 Tut,这两个数字彼此相邻。我猜在手机上键入回复会发生什么...
评论
您在谈论SQL Server吗?@a_horse_with_no_name是的,我忘了提到sry
堆表非常适合具有数百万行的表,这些表会受到用户的严重打击。缺点是它们会占用大量空间,因为数据在物理上未排序存储。同样,您依靠索引来调整查询。由于性能问题,我在根本不使用聚集索引的地方工作。可能是由于簇索引选择不当所致,但是如果您仅使用堆表,则不必担心。更好的解决方案是使用sql server企业版并水平分区大表。但是如果你没有耳鼻喉
另请参见stackoverflow.com/questions/1341393/…。
use-the-index-luke.com/blog/2014-01/…