web-dev-qa-db-ja.com

限られたDBスペースで非常に大きなテーブルを分割する方法は?

とても大きなテーブルがあります。パーティション化したいのですが、できません。

データベースサイズ:1 TB、空き容量200 GB

テーブル:

  • サイズ:165​​列(行長4216 KB、LOBなし)、5億行、600 GBのデータ。
  • 可能なパーティション:パーティションごとの日
  • 1日あたりの行数/パーティション:200万

パーティション分割するには、クラスター化インデックスを作成する必要があります。しかし、パーティションを作成するには、テーブルと同じサイズの空き領域が必要であり、余分な600GBはありません。

このテーブルを分割する方法はありますか?

編集1:

データを別のテーブルにコピーしてみました。

しかし、1日分のデータを別のテーブルにDELETE(またはINSERT)しようとすると、エラーが発生し、トランザクションログがいっぱいになり、トランザクションがロールバックされます。私のトランザクションログは約20 GBで、これ以上大きくすることはできません。

3
Stoleg

同じスキーマで、パーティション化されたオブジェクトとして新しいテーブルを作成する必要があります。オプションで、テーブルを圧縮してさらにスペースを節約できます。ページごとに平均1行しか配置していないので、どの程度のスペース節約が見られるかわかりません。新しいテーブルに数千行を入れてから圧縮して、スペースの節約がCPUオーバーヘッドに値するかどうかを確認することをお勧めします。

ドライブスペースをすべて消費することなく、またトランザクションログを肥大化させることなく、これだけのデータを移動する方法については、実行ごとに少量のデータを移動するループで実行する必要があります。処理できるウィンドウの大きさを確認するためにデータ分析を行う必要がありますが、データ量に基づいて、一度に1分ずつ行を移動する必要があると想定します。

DECLARE @processFrom as datetime
SELECT @processFrom = min(YourDateColumn)
FROM YourTable

DECLARE TABLE @Rows (...)

WHILE EXISTS (SELECT * FROM YourTable)
BEGIN
     DELETE TOP (10000) FROM YourTable
     OUTPUT DELETED.* INTO @Rows
     WHERE YourDateColumn = @processFrom


     INSERT INTO NewTable
     (...)
     SELECT ...
     FROM @Rows

     DELETE FROM @Rows

     IF @@ROWCOUNT = 0
              SET @processFrom = dateadd(dd, 1, @processFrom)
END

すべてが完了し、すべてのデータが新しいテーブルにあることを確認したら、古いテーブルを削除し、新しいテーブルの名前を変更して、古いテーブルの名前を付けます。この方法では何も壊れません。新しいテーブルに適用できるように、古いテーブル(存在する場合)の権限をスクリプトで削除する必要があります。

このテーブルへの外部キーを持つテーブルがある場合、これが機能する前にそれらを削除する必要があります。

4
mrdenny