如何在100 GB表上创建聚簇索引


8

我有一个堆表,该表占用约104 GB的磁盘空间,近30亿行。我正在尝试在[ WeekEndingDate]列上的此表上创建聚簇索引。我在数据文件中有大约200 GB的可用空间,在tempdb中有大约280 GB的可用空间。

我尝试了两种不同的方法。首先是使用以下命令直接在表上创建索引:

CREATE CLUSTERED INDEX CX_WT_FOLD_HISTORY
ON WT_FOLD_HISTORY (WeekEndingDate ASC)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = ON, 
IGNORE_DUP_KEY = OFF
, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, 
DATA_COMPRESSION = PAGE)

我尝试了SORT_IN_TEMPDB = ONOFF。使用时,ON它会填满tempdb,并OFF填满数据驱动器。

另一种方法是使用所需索引创建一个新的空白表,然后将堆中的记录插入到新表中。填满数据驱动器后,此操作也失败。

关于该怎么做的其他建议。我读过的大多数内容都表明,在创建索引时,需要大约1.2倍的表大小才能用作工作空间。我有更多的方法,但仍然失败。任何建议,将不胜感激。

这是我原来的堆表结构:

CREATE TABLE [dbo].[WT_FOLD_HISTORY](
[WeekEndingDate] [varchar](50) NULL,
[Division] [varchar](50) NULL,
[Store] [varchar](50) NULL,
[SKUNumber] [varchar](50) NULL,
[UPC] [varchar](50) NULL,
[SalesUnits] [varchar](50) NULL,
[SalesCost] [varchar](50) NULL,
[SalesRetail] [varchar](50) NULL,
[InventoryUnits] [varchar](50) NULL,
[InventoryCost] [varchar](50) NULL,
[InventoryRetail] [varchar](50) NULL,
[OnOrderUnits] [varchar](50) NULL,
[OnOrderCost] [varchar](50) NULL,
[OnOrderRetail] [varchar](50) NULL,
[ReceiptUnits] [varchar](50) NULL,
[ReceiptCost] [varchar](50) NULL,
[ReceiptRetail] [varchar](50) NULL,
[PermanentMarkdowns] [varchar](50) NULL,
[ReturnsToVendor] [varchar](50) NULL,
[POSMarkdowns] [varchar](50) NULL,
[TimeFK] [smallint] NULL,
[LocationFK] [int] NULL,
[ItemFK] [int] NULL
) ON [AcademySports_DataFG1]

在执行“新表,批量移动行”方法时,是否要在移动原始表时删除原始表中的行?您可能需要做一些额外的练习,以使堆在删除数据时释放未使用的空间。
AMtwo '17年

为何在这种情况下不接受非聚集索引可能会引起关注;[是的,我知道集群与非集群的区别/好处...只是好奇为什么您排除了非集群索引];另外,该表是否已经有任何非聚集索引,如果有,它们将使用多少空间?[想知道是否删除任何当前的非聚集索引可能释放足够的空间来创建聚集索引?]
markp-fuso

您是否尝试使用创建索引DATA_COMPRESSION=NONE?如果可行,您可以随后进行压缩。
丹·古兹曼

很好的问题。我在google上阅读了这句话,他们说的是dba.stackexchange.com/questions/11956/…stackoverflow.com/questions/2309889/… 这是唯一正确的答案。
KumarHarsh

1
可以肯定的是,您能否包括它失败的实际错误消息?
RDFozz

Answers:


3

如果您短期需要磁盘空间,则一种选择是:

  1. 临时收缩tempdb,以释放安全的磁盘空间。
  2. 为表所在的数据库在tempdb驱动器上创建一个辅助数据文件。
  3. 将聚簇索引添加到表中。
  4. 通过从中迁移所有数据来缩小辅助文件。
  5. 删除辅助文件。
  6. 确保允许tempdb文件增长到以前的大小。
  7. 在表的数据库中重建索引(删除辅助文件将导致一些碎片)。

注意:正如其他人所建议的那样,我只会在诸如从相关表中临时删除非聚集索引之类的操作之后执行此操作。尤其是,这将使添加聚簇索引的速度更快,因为无论如何都必须重新构建非聚簇索引(有了聚簇索引,索引键用于在表本身中定位行) 。

这实际上是另一点-聚集索引上的键有多宽?如果您确实有非聚集索引,并且聚集索引上的键比进入堆的指针宽得多,那么在创建聚集索引之后,非聚集索引将占用更多空间。

如果群集键由几列或什至是一个大列(例如,varchar平均长度为25或更长的一列)组成,则您可能需要考虑使用代理键(通常是单调递增的值),以获得最佳INSERT性能。


1

占满整个空间的是您的大型排序(您尝试对整个104Gb进行整体排序),因此我认为可以在较小的部分进行排序就可以解决。我建议您创建新的群集表,并将数据以小块的形式插入,如下所示:

declare @rowcount int = 1;
while @rowcount > 0
begin
  delete top (5000) 
  from your_heap with(tablock) 
      output deleted.field1, ..., deleted.fieldN 
      into new_clustered_table;
  set @rowcount = @@rowcount;
end; 

这样,您一次只能排序5000行,唯一的问题是无法进行分页,因为您没有进行排序的插入。因此,完成后,new_clustered_table将被分段,但是您可以在之后重建它。


是的,您是对的,我更新了答案,但这只是一个主意。
sepupic

0

快速提示-在尝试创建聚簇索引之前,请考虑将所有非聚簇索引(如果有)都删除。您可以对那些非配置项及其包含列详细信息进行脚本编写,然后在成功创建聚簇索引之后使用这些定义再次创建它们。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.