Sql-Server

如何在 100 GB 表上創建聚集索引

  • August 18, 2017

我有一個堆表,它需要大約 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]

如果您對磁碟空間有短期需求,一種選擇是:

  1. 暫時縮小 tempdb,在該驅動器上釋放盡可能多的空間,以確保安全。
  2. 在 tempdb 驅動器上為表所在的數據庫創建輔助數據文件。
  3. 將聚集索引添加到表中。
  4. 通過從中遷移所有數據來縮小輔助文件。
  5. 刪除輔助文件。
  6. 確保允許 tempdb 文件增長到以前的大小。
  7. 在表的數據庫中重建索引(刪除輔助文件會導致一些碎片)。

注意:正如其他人所建議的那樣,我只會在暫時從相關表中刪除非聚集索引等事情之後才這樣做。這尤其允許添加聚集索引更快,因為無論如何都必須重建非聚集索引(使用聚集索引,索引鍵用於定位表本身中的行) .

這實際上是另一點 - 聚集索引上的鍵有多寬?如果您確實有非聚集索引,並且聚集索引上的鍵明顯比指向堆的指針寬,那麼在創建聚集索引後非聚集索引將消耗更多空間。

如果集群鍵包含多列,甚至是一個大列(例如,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 將被碎片化,但您可以在之後重建它。

引用自:https://dba.stackexchange.com/questions/183635