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


8

約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]

「新しいテーブル、バッチで行を移動する」アプローチを実行するとき、移動するときに元のテーブルの行を削除していますか?データを削除するときにヒープに未使用のスペースを解放させるために、追加の体操が必要になる場合があります。
AMtwo 2017

この場合、非クラスター化インデックスが受け入れられない理由については興味深いかもしれません。[はい、私はクラスタ化されたものと非クラスタ化されたものの違い/利点を認識しています...非クラスタ化インデックスを除外した理由について興味があるだけです]; また、テーブルにはすでに非クラスター化インデックスが配置されていますか?その場合、どのくらいのスペースを使用しますか?[現在の非クラスター化インデックスを削除すると、クラスター化インデックスを作成するのに十分な領域が解放されるかどうか疑問に思いますか?]
markp-fuso

でインデックスを作成してみましたDATA_COMPRESSION=NONEか?それが機能する場合は、後で圧縮できます。
Dan Guzman

nice question.i google it。そしてこれを読んで、彼らが言ったのはdba.stackexchange.com/questions/11956/…またはstackoverflow.com/questions/2309889/… これが唯一の正しい答えです。
KumarHarsh 2017

1
確かに、失敗した実際のエラーメッセージを含めることができますか?
RDFozz 2017

回答:


3

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

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

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

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

クラスターキーが複数の列、または1つの大きな列(たとえば、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 2017

0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.