web-dev-qa-db-ja.com

100 GBテーブルにクラスター化インデックスを作成する方法

約30億行のディスク容量約104 GBを占めるヒープテーブルがあります。このテーブルの[WeekEndingDate]列にクラスター化インデックスを作成しようとしています。データファイルには約200 GBの空き容量があり、tempdbには約280 GBの空き容量があります。

私は2つの異なる方法を試しました。最初に、次のコマンドを使用してテーブルに直接インデックスを作成しました。

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]
8
user578849

ディスク容量が短期的に必要な場合、1つのオプションは次のとおりです。

  1. Tempdbを一時的に縮小し、そのドライブの安全と思われるスペースを解放します。
  2. テーブルがtempdbドライブにあるDBのセカンダリデータファイルを作成します。
  3. クラスタ化インデックスをテーブルに追加します。
  4. セカンダリファイルからすべてのデータを移行して、セカンダリファイルを縮小します。
  5. セカンダリファイルを削除します。
  6. Tempdbファイルが以前のサイズまで拡大できることを確認してください。
  7. テーブルのDBでインデックスを再構築します(セカンダリファイルを削除すると断片化が発生します)。

注:他の人が示唆しているように、問題のテーブルから非クラスター化インデックスを一時的に削除するような場合にのみ、これを行います。とにかく、非クラスター化インデックスをすべて再構築する必要があるため、クラスター化インデックスの追加をより速く行うことができます(クラスター化インデックスが配置されている場合、インデックスキーはテーブル自体の行を見つけるために使用されます)。 。

それは実際には別のポイントです。クラスター化インデックスのキーの幅はどれくらいですか?非クラスター化インデックスがあり、クラスター化インデックスのキーがヒープへのポインターよりも大幅に広い場合、非クラスター化インデックスは、クラスター化インデックスの作成後により多くの領域を消費します。

クラスターキーが複数の列、または1つの大きな列(たとえば、平均長が25以上のvarchar列)で構成される場合は、代わりに代理キー(通常は単調増加する値)を検討することができます。 、最高のINSERTパフォーマンス。

3
RDFozz

あなたのスペースを埋めているのはあなたのメガソートです(あなたは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はフラグメント化されますが、後で再構築できます。

1
sepupic

簡単なヒント-クラスタ化インデックスを作成する前に、このヒープ上のすべての非クラスタ化インデックス(存在する場合)を削除することを検討してください。それらの非CIをそれらのインクルード列の詳細とともにスクリプト化し、クラスター化インデックスが正常に作成された後で、それらの定義を使用して後でそれらを再度作成できます。

0
Channdeep Singh