データのバルクインサート(bulk insert)は、大きなテーブルの移行、インポート、または補充時に典型的な作業です。この操作の効率は、いくつかの要因に依存します:
BULK INSERTやCOPY(PostgreSQL)など、通常のINSERTループよりも高速に動作します。BULK INSERT my_table FROM 'C:\data\bulkdata.csv' WITH ( FIELDTERMINATOR = ',', ROWTERMINATOR = ' ', BATCHSIZE = 5000, TABLOCK );
TABLOCKは、バルクインサート時のロックの競合を減少させます。
質問: トランザクションに関与するテーブルで、バルクインサートを高速化するためにいつでもインデックスを無効化し再作成できますか?
回答: いいえ、テーブルがアクティブなトランザクションに関与している場合、インデックスの無効化や再作成はロックの発生、データ整合性の違反、あるいはトランザクションがロールバックされた場合のデータ損失を引き起こす可能性があります。この操作はトランザクション外でのみ実行するか、メンテナンスウィンドウを事前に計画する必要があります。
-- 不適切: BEGIN TRAN; ALTER INDEX ALL ON my_table DISABLE; -- ... bulk insert ... ALTER INDEX ALL ON my_table REBUILD; COMMIT;
長いトランザクション内でのこのような無効化は許可されません!
ストーリー1:あるプロジェクトで、複数の一意のインデックスを持つテーブルへの並行バルクインサートが、頻繁なデッドロックとパフォーマンスの急落を引き起こしました。解決策は、インポート期間中の非キーインデックスの一時的な無効化と、バッチ操作のサイズの縮小でした。
ストーリー2:開発者たちはデータロードの期間中に外部キーの制約を無効にするのを忘れており、各インサートは他の大規模テーブルに関連するレコードの存在を確認していました。これにより、ロード時間が40分から9時間に増加しました。制約を無効にした後、挿入には12分かかりました。
ストーリー3:大きなファイルを単一のクエリで挿入しようとした(バッチ処理せず、トランザクションなし)ため、トランザクションログの容量が満杯になり、データベースサーバーがクラッシュしました。バッチ処理に移行した後、問題は解消されました。