web-dev-qa-db-ja.com

データウェアハウスロードの制約とインデックスを無効にするスクリプト

データウェアハウスにデータを読み込みます。

現在、私は、便利さとスピードのために、データをロードする前に外部キー制約とインデックスを削除するために使用するスクリプトを持っています。ロードを実行できる大きなウィンドウがあるので、ロード中にユーザーがデータにアクセスすることを心配する必要はありませんが、データベース内の他のテーブルの無関係なデータに影響を与えたくありません。

このスクリプトを思いつくために hereelsewhere の調査を行いましたが、見落としている可能性があり、パフォーマンスが最適でないか、重要な何かが欠けている可能性がある場合(わからない...計算された列または何か?)、または間違った順序で物事を実行している場合など。

これを堅牢で高性能にするためのアドバイスはありませんか。

制約とインデックスを無効にする

編集:コメンターが冗長であることを理解するのに役立つWHILEループを削除しました。

Declare @schema varchar(128) = 'dbo';
Declare @sql nvarchar(max) = N'';

-- 1. Indices
-- Select a list of indexes in the schema and generate statements to disable them.
Select @sql = @sql + 'ALTER INDEX ' + QuoteName(idx.name) + ' ON ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' DISABLE;' + CHAR(13)
  From sys.indexes As idx
  Join sys.objects As obj On idx.object_id = obj.object_id
  Where ((obj.type = 'U' And idx.type in (2,6)) -- Non-clustered index/columnstore on a table
    Or obj.type = 'V') -- All indexes on indexed views
    And obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name, idx.name;

Execute sp_executesql @sql;


-- 2. Foreign-key constraints
-- Build a list of foreign keys constraints in the schema and generate statements to disable the constraint checking.
Select @sql = @sql + 'ALTER TABLE ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' NOCHECK CONSTRAINT ' + QuoteName(fk.name) + ';' + CHAR(13)
  From sys.foreign_keys As fk
  Join sys.objects As obj On fk.parent_object_id = obj.object_id  
  Where obj.schema_id = (Select schema_id From sys.schemas Where name = @schema);

Execute sp_executesql @sql;

制約を有効にし、インデックスを再構築し、統計を更新します

Declare @schema nvarchar(128) = 'dbo';
Declare @sql nvarchar(max) = N'';

-- 1. Indices
-- Build a list of tables in the schema and generate statements to enable the indices on them.
Select @sql = @sql + 'ALTER INDEX ' + QuoteName(idx.name) + ' ON ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' REBUILD' + iif(idx.type = 6, ' WITH (MAXDOP = 1);', ' WITH (FILLFACTOR = 100);') + CHAR(13)
  From sys.indexes idx
  Join sys.objects obj ON obj.object_id = idx.object_id
  Where ((obj.type = 'U' And idx.type in (2,6)) -- Non-clustered index on a table
    Or obj.type = 'V') -- All indexes on indexed views
    And obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
    And idx.is_disabled = 1 -- Don't rebuild indexes that are already online
    And idx.is_hypothetical = 0 -- Don't rebuild hypothetical indexes!
  Order By iif(idx.type = 6, 1, 2), obj.name, idx.name;

Execute sp_executesql @sql;


-- 2. Foreign-key constraints
-- Build a list of foreign keys constraints in the schema and generate statements to enable them with checking.
Select @sql = @sql + 'ALTER TABLE ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' WITH CHECK CHECK CONSTRAINT ' + QuoteName(fk.name) + ';' + CHAR(13)
  From sys.foreign_keys fk
  Join sys.objects obj ON obj.object_id = fk.parent_object_id
  Where obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name, fk.name;

Execute sp_executesql @sql;


-- 3. Statistics
-- Build a list of tables in the schema and generate statements to update the statistics on them.
Select @sql = @sql + 'UPDATE STATISTICS ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' WITH COLUMNS;' + CHAR(13)
  From sys.objects obj
  Where obj.type = 'U' -- User defined
    AND obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name;

Execute sp_executesql @sql;
2
mendosi

あなたが考慮しなかったかもしれないいくつかの事柄について:

  1. インデックスが無効として開始された場合、スクリプトの終了後にインデックスが再構築されます。
  2. インデックスがページ圧縮で始まる場合は、圧縮せずに再構築します。

パフォーマンスについて:

  1. 他のプロセスがテーブルにアクセスしていないため、ONLINE = OFFオプションを使用して再構築すると、ロックが少なくなるためパフォーマンスがわずかに向上する可能性があります。
  2. Tempdbのサイズとインデックスに応じて、SORT_IN_TEMPDB = ONオプションを使用してパフォーマンスを向上させることができます。
  3. テーブルが変更されていないか、変更された行がほとんどない場合でも、すべてのテーブルの統計を更新しています。更新をさらに制限して、最後の統計が更新されてから変更されたか、まったく変更されていないテーブルのみを確認することもできます。
  4. これらのクエリをすべて1つのセッションで実行しているようです。作業を複数のセッションに分割することを検討しましたか?
5
Joe Obbish

データをロードする前に外部キーを無効にすることは、あなたのケースでは少し心配です。なぜなら、それらを有効にしているとき、あなたのscripはエラー処理をしません.. TRY .. CATCH blocks

データが読み込まれた後、データベースの参照整合性をどのようにチェックしていますか?外部キーを有効にするだけでは、データベースの参照整合性は保証されません。少なくとも実行する必要がありますDBCC CHECKCONSTRAINTSを実行し、問題なく実行されることを確認します。参照: 外部キーとその状態

私が目にするもう1つのポイントは二重の作業です-インデックスを再構築した後に統計を更新するポイントは何ですか?

インデックスを再構築すると、そのインデックスに関連する列の統計が更新されることに注意してください

ロードを実行できる大きなウィンドウがあるので、ロード中にユーザーがデータにアクセスすることを心配する必要はありませんが、データベース内の他のテーブルの無関係なデータに影響を与えたくありません。

データ読み込みパフォーマンスガイドここで私の答え

4
Kin Shah

架空のインデックスに注意してください。クラッシュしてそれらを削除しなかったために調整ツールによって残された場合、スクリプトはそれらを現実のものにし、これで単一のテーブルに30または40のインデックスがあり、そのテーブルのパフォーマンスはブロッキングとデッドロックでいっぱいになります。 。

SELECT dbid = DB_ID(),
       objectid = object_id,
       indid = index_id
FROM sys.indexes
WHERE is_hypothetical = 1 ;
2
Duane Lawrence

さまざまな回答者からのフィードバックを統合した後の最終的なスクリプトは次のとおりです(将来の読者のためにそれらをすべてまとめたかっただけです)。

制約とインデックスを無効にする

Declare @schema varchar(128) = 'dbo';
Declare @sql nvarchar(max) = '';

-- 1. Indices
-- Select a list of indexes in the schema and generate statements to disable them.
Select @sql = @sql + 'ALTER INDEX ' + QuoteName(idx.name) + ' ON ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' DISABLE;' + CHAR(13)
  From sys.indexes As idx
  Join sys.objects As obj On idx.object_id = obj.object_id
  Where ((obj.type = 'U' And idx.type in (2,6)) -- Non-clustered index/columnstore on a table
    Or obj.type = 'V') -- All indexes on indexed views
    And obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name, idx.name;

Execute sp_executesql @sql;


-- 2. Foreign-key constraints
-- Build a list of foreign keys constraints in the schema and generate statements to disable the constraint checking.
Select @sql = @sql + 'ALTER TABLE ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' NOCHECK CONSTRAINT ' + QuoteName(fk.name) + ';' + CHAR(13)
  From sys.foreign_keys As fk
  Join sys.objects As obj On fk.parent_object_id = obj.object_id  
  Where obj.schema_id = (Select schema_id From sys.schemas Where name = @schema);

Execute sp_executesql @sql;

**インデックスの再構築、制約の有効化、統計の更新**

Declare @schema varchar(128) = 'dbo';
Declare @sql nvarchar(max) = '';

-- 1. Indices
-- Build a list of tables in the schema and generate statements to enable the indices on them.
Select @sql = @sql + 'ALTER INDEX ' + QuoteName(idx.name) + ' ON ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + 
    ' REBUILD WITH (' + iif(idx.type = 6, 
                            'MAXDOP = 1', 
                            'FILLFACTOR = 100, DATA_COMPRESSION = ' + IsNull(p.data_compression_desc Collate Latin1_General_CI_AS, 'None') + ', ONLINE = OFF, SORT_IN_TEMPDB = ON') 
                    + ');' + CHAR(13)
  From sys.indexes idx
  Join sys.objects obj ON obj.object_id = idx.object_id
  Left Join sys.partitions As p On idx.object_id = p.object_id And idx.index_id = p.index_id
  Where ((obj.type = 'U' And idx.type in (2,6)) -- Non-clustered index on a table
    Or obj.type = 'V') -- All indexes on indexed views
    And obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
    And idx.is_disabled = 1 -- Don't rebuild indexes that are already online
    And idx.is_hypothetical = 0 -- Don't rebuild hypothetical indexes!
  Order By iif(idx.type = 6, 1, 2), obj.name, idx.name;

Execute sp_executesql @sql;


-- 2. Foreign-key constraints
-- Build a list of foreign keys constraints in the schema and generate statements to enable them with checking.
Select @sql = @sql + 'ALTER TABLE ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' WITH CHECK CHECK CONSTRAINT ' + QuoteName(fk.name) + ';' + CHAR(13)
  From sys.foreign_keys fk
  Join sys.objects obj ON obj.object_id = fk.parent_object_id
  Where obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name, fk.name;

--DBCC CheckConstraints('fForeignKey_Table'); -- Does a soft check of the constraints and returns any values which violate them.
Execute sp_executesql @sql;


-- 3. Statistics
-- Build a list of tables in the schema and generate statements to update the statistics on them.
Select @sql = @sql + 'UPDATE STATISTICS ' + QuoteName(@schema) + '.' + QuoteName(obj.name) + ' WITH COLUMNS;' + CHAR(13)
  From sys.objects obj
  Where obj.type = 'U' -- User defined
    AND obj.schema_id = (Select schema_id From sys.schemas Where name = @schema)
  Order By obj.name;

Execute sp_executesql @sql;
1
mendosi