sql >> データベース >  >> RDS >> Sqlserver

非常に大きなテーブルでのデータ型の絞り込み

    まず、これをやってくれてありがとう。多くの人があまり価値を感じないほど明らかな勝利ですが、それだけの価値はあります:)。世界をほんの少しだけ正気にします。

    IsActive について ブール値であること。私の推測では、あなたはそれを BIT にすることを考えています。 分野。それが良い方法かもしれませんが、TINYINT を使用した方がよい場合もあります。 意味を 2 つ以上の状態に拡張する可能性があるためです。その場合、実際には StatusID のほうが多くなります .通常、Active として単純に開始する場合です。 / 非アクティブ 、しかし後で削除される可能性があります および/またはその他。サイジングの観点から、TINYINT は常に 1 バイトです。一方、BIT 1 バイト 最大 8 BIT フィールド .つまり、1 つの BIT フィールドは 1 バイト、2 BIT fields も 1 バイトで、最大 8 BIT まで続きます。 フィールドは 1 バイトで格納されます。したがって、BIT を選択してもスペースの節約にはなりません TINYINT以上 テーブルに BIT が 1 つしかない場合 分野。考慮すべき点です。

    見てきたように、ALTER TABLE を実行するのは、大きなテーブルでは少し大変です。素晴らしいものではありませんが、1 つのオプションは NOT NULL を追加することです。 field--Number_1new -- DEFAULT 付き 値 (これは、少なくとも SQL 2012 以降ではデフォルトにより瞬時になります) が自然には持たない値 (例:255) であり、その後、次のように、ループ内でゆっくりと値を移行します:

    UPDATE TOP (5000) tab
    SET tab.Number_1new = tab.Number_1
    FROM [table] tab
    WHERE tab.Number_1new = 255;
    

    それが終わったら、次のことを行います:

    sp_rename 'table.Number_1', 'Number_1old', 'COLUMN';
    sp_rename 'table.Number_1new', 'Number_1', 'COLUMN';
    

    もちろん、それを TRANSACTION でラップし、それを TRY / CATCH でラップするのが最善です。関連するコードが更新され、すべてがテストされ、データが良好に見えたら、Number_1old をドロップできます。

    ただし、私が見つけた最善の方法は、新しいテーブルを作成し、データをゆっくりと移行してから、テーブルとコードを同時に交換することです。 SQL Server Central の記事 Restructure 100 Million Row (または詳細) 秒単位のテーブル。 SRSLY! (無料登録が必要です)。その記事に到達する際に問題が発生した場合に備えて、基本的な手順は次のとおりです:

    <オール>
  1. 理想的な構造の新しいテーブル [tableNew] を作成します。 Enterprise Edition を使用している場合は、ROW または PAGE 圧縮を有効にすることを検討してください。ただし、悪影響を及ぼす場合もあるため、事前に調査を行ってください。 MSDN には、それを理解するのに役立つドキュメントと、潜在的な節約を見積もるのに役立ついくつかのツールがあります。しかし、圧縮を有効にしたとしても、そのアクションがあなたがここで行っているプロジェクトを置き換えるものだとは思いません.
  2. トリガーを追加 AFTER UPDATE, DELETE [テーブル] で変更を同期します (ただし、新しい行について心配する必要はありません)
  3. 不足している行をバッチで移動する SQL エージェント ジョブを作成します。 INSERT INTO [tableNew] (Columns) SELECT TOP (n) Columns FROM [table] WHERE ?? ORDER BY ??
  4. WHERE 句と ORDER BY 句は状況によって異なります。これらは、クラスター化インデックスを最大限に活用するように調整する必要があります。新しいテーブルのクラスター化インデックスが古い/現在のテーブルと構造的に同じである場合、各ループの開始時に [tableNew] から MAX([id]) を取得し、それを使用して WHERE table.[id] > @MaxIdInTableNew ORDER BY table.[id] .
  5. 完全なカットオーバーが必要になる 1 週間ほど前に、新しいテーブルを作成し、現在のテーブルでトリガーし、SQL エージェント ジョブを実行します。その時間枠はあなたの状況に応じて変わるかもしれませんが、十分な時間を確保してください.リリースが開始されるはずなのに、完全なセットを 100k 恥ずかしがり屋にするよりも、行の移行を完了し、一度に数滴しか入らない方が、ジョブにとってはるかに優れています。
  6. 他の関連テーブルを移行する計画の場合 (INT に変換する 2 つの FK の PK 参照) s) 次に、これらのフィールドをここに INT にします。 これらの他のテーブルが INT フィールドを PK として持つように移行されるまで、FK を追加しないでください。 FK フィールドを変更するためだけに、このテーブルを再構築する必要はありません。
  7. カットオーバー中 (もちろん、TRY / CATCH で):<オール>
  8. トランを開始
  9. 両方のテーブルで最終的な行カウントを行い、すべてが移動されたことを確認します (リリース前に行のサニティ チェックを行い、トリガーが期待どおりに更新と削除を行ったことを確認することをお勧めします)
  10. 現在のテーブルの名前を「old」に変更
  11. 「新しい」テーブルの名前を「新しい」を含まないように変更します
  12. SQL エージェント ジョブをドロップする (または少なくとも無効にする)
  13. 制約などの依存オブジェクトの名前変更
  14. コミット


    1. 前の(不明な)日付のSQL値

    2. 設定を保存するためのXMLまたはデータベーステーブル

    3. SQLServer2008とSQLServer2005の互換性

    4. 選択方法*ただし、列名は各ビューで一意である必要があります