如何在 100 GB 表上創建聚集索引
我有一個堆表,它需要大約 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 = ON
和都試過了OFF
。使用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]
如果您對磁碟空間有短期需求,一種選擇是:
- 暫時縮小 tempdb,在該驅動器上釋放盡可能多的空間,以確保安全。
- 在 tempdb 驅動器上為表所在的數據庫創建輔助數據文件。
- 將聚集索引添加到表中。
- 通過從中遷移所有數據來縮小輔助文件。
- 刪除輔助文件。
- 確保允許 tempdb 文件增長到以前的大小。
- 在表的數據庫中重建索引(刪除輔助文件會導致一些碎片)。
注意:正如其他人所建議的那樣,我只會在暫時從相關表中刪除非聚集索引等事情之後才這樣做。這尤其允許添加聚集索引更快,因為無論如何都必須重建非聚集索引(使用聚集索引,索引鍵用於定位表本身中的行) .
這實際上是另一點 - 聚集索引上的鍵有多寬?如果您確實有非聚集索引,並且聚集索引上的鍵明顯比指向堆的指針寬,那麼在創建聚集索引後非聚集索引將消耗更多空間。
如果集群鍵包含多列,甚至是一個大列(例如,
varchar
平均長度為 25 或更多的列),您可能需要考慮使用代理鍵(通常是單調遞增的值,以獲得最佳INSERT
性能。
填滿你的空間的是你的超級排序(你試圖對你所有的 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 將被碎片化,但您可以在之後重建它。