26

20 を超えるインデックスを持つテーブルに何百万ものレコードを挿入しようとしています。

前回の実行では、100.000 行あたり 4 時間以上かかり、クエリは 3 日半後にキャンセルされました...

これをスピードアップする方法について何か提案はありますか。

(インデックスが多いことが原因だと思います。あなたもそう思うなら、操作前にインデックスを自動的に削除し、後で同じインデックスを再度作成するにはどうすればよいですか?)

追加情報:

  • インデックスが使用するスペースは、データのみが使用するスペースの約 4 倍です。
  • 挿入は、100.000 行ごとにトランザクションでラップされます。

ステータスの更新:

受け入れられた答えは、私がそれをはるかに速くするのに役立ちました.

4

4 に答える 4

43

インデックスを無効または有効にすることができます。それらを無効にすると、インデックスを再度有効にした場合にのみ見られる望ましくない副作用 (主キーの重複や一意のインデックスなど) が発生する可能性があることに注意してください。

--Disable Index
ALTER INDEX [IXYourIndex] ON YourTable DISABLE
GO

--Enable Index
ALTER INDEX [IXYourIndex] ON YourTable REBUILD
GO
于 2009-04-15T10:23:44.333 に答える
9

これは、データウェアハウス操作のように聞こえます。挿入前にインデックスを削除し、後で再構築するのが通常です。

インデックスを再構築するときは、最初にクラスター化インデックスを構築し、逆に最後にドロップします。それらはすべてfillfactor100%を持っている必要があります。

コードは次のようになります

if object_id('Index') is not null drop table IndexList
select name into Index from dbo.sysindexes where id = object_id('Fact')

if exists (select name from Index where name = 'id1') drop index Fact.id1
if exists (select name from Index where name = 'id2') drop index Fact.id2        
if exists (select name from Index where name = 'id3') drop index Fact.id3
.
.
BIG INSERT

RECREATE THE INDEXES
于 2009-04-15T10:30:52.587 に答える
4

別の回答で指摘されているように、インデックスを無効にすることは非常に良いスタートになります。

100.000行あたり4時間[...]挿入は100.000行あたりのトランザクションにラップされます。

数を減らすことを検討する必要があります。サーバーはトランザクション中に大量の状態を維持する必要があり(ロールバックできるように)、これは(インデックスとともに)データの追加が非常に困難な作業であることを意味します。

各挿入ステートメントを独自のトランザクションでラップしてみませんか?

また、使用しているSQLの性質を確認します。ステートメントごとに1行を追加しますか(およびネットワークラウンドトリップ)、それとも多数追加しますか?

于 2009-04-15T10:31:02.397 に答える
3

そのような場合は、インデックスを無効にしてから再度有効にすることをお勧めします。ただし、次の理由から、このアプローチには疑問があります。

(1) アプリケーションのDB利用者は、通常は持つべきでないスキーマ変更権限を必要とします。(2) 選択された挿入アプローチおよび/またはインデックス スキーマは、そもそも最適ではない可能性があります。それ以外の場合、完全なインデックス ツリーの再構築は、適切なバッチ挿入よりも高速ではありません (たとえば、クライアントが一度に 1 つの挿入ステートメントを発行すると、数千のサーバー ラウンドトリップ、またはクラスター化されたインデックスの不適切な選択により、一定のインデックス ノード分割が発生します)。

そのため、私の提案は少し異なって見えます。

  • ADO.NET BatchSize を増やす
  • ターゲット テーブルのクラスター化インデックスを慎重に選択して、挿入によってクラスター化インデックス ノードの分割が発生しないようにします。通常、ID 列は適切な選択です
  • クライアントが最初に一時ヒープ テーブルに挿入できるようにします (ヒープ テーブルにはクラスター化インデックスがありません)。次に、1 つの大きな「insert-into-select」ステートメントを発行して、ステージング テーブル データをすべて実際のターゲット テーブルにプッシュします。
  • SqlBulkCopy を適用する
  • 一括ログ復旧モデルを選択してトランザクション ログを減らす

詳細については、この記事を参照してください。

于 2011-10-09T19:00:13.490 に答える