BULK INSERT
スキーマが変更されたため、SQL Serverのコマンドを使用してかなり古いコードを書き直さなければならないところです。代わりに、TVPを使用してストアドプロシージャに切り替えることを検討する必要があると思いましたが、どのような影響があるのでしょうか。パフォーマンスに影響する可能性があります。
私がこの質問をしている理由を説明するのに役立つかもしれないいくつかの背景情報:
データは実際にはWebサービスを介して受信されます。Webサービスは、データベースサーバー上の共有フォルダーにテキストファイルを書き込みます。共有フォルダーは、を実行します
BULK INSERT
。このプロセスは元々SQLServer 2000に実装されていましたが、当時INSERT
はサーバーで数百のステートメントをチャックする以外に方法はありませんでした。これは実際には元のプロセスであり、パフォーマンスの低下でした。データは永続的なステージングテーブルに一括挿入されてから、はるかに大きなテーブルにマージされます(その後、ステージングテーブルから削除されます)。
挿入するデータの量は「大規模」ですが、「巨大」ではありません。通常は数百行、まれに5〜1万行がトップになります。したがって、
BULK INSERT
ログに記録されていない操作であってもそれほど大きな違いはないというのが私の直感です(もちろん、私にはわかりません。したがって、質問です)。挿入は実際にははるかに大きなパイプラインバッチプロセスの一部であり、連続して何度も実行する必要があります。したがって、パフォーマンスは重要です。
をBULK INSERT
TVPに置き換えたい理由は次のとおりです。
NetBIOSを介してテキストファイルを書き込むことは、おそらくすでにある程度のコストがかかり、アーキテクチャの観点からはかなり厄介です。
ステージングテーブルは削除できる(そして削除すべきである)と私は信じています。その主な理由は、挿入されたデータを挿入と同時に他のいくつかの更新に使用する必要があり、ほとんど空のステージングを使用するよりも、大規模な本番テーブルから更新を試みる方がはるかにコストがかかるためです。テーブル。TVPでは、パラメータは基本的にあるステージング表、私はメインの挿入後/前に私が欲しいものを行うことができます。
重複チェック、クリーンアップコード、および一括挿入に関連するすべてのオーバーヘッドをほぼなくすことができました。
サーバーがこれらのトランザクションのいくつかを一度に取得する場合、ステージングテーブルまたはtempdbでのロックの競合について心配する必要はありません(回避しようとしますが、発生します)。
明らかに、本番環境に移行する前にこれをプロファイリングするつもりですが、この目的でTVPを使用することについて、誰かが厳しい警告を発するかどうかを確認するために、時間を費やす前にまず周りに尋ねるのは良い考えかもしれません。
つまり、SQL Server 2008に慣れていて、これを試したり、少なくとも調査したりした人にとって、評決は何でしょうか。たとえば、かなり頻繁に発生する数百から数千行の挿入の場合、TVPはマスタードをカットしますか?バルクインサートと比較してパフォーマンスに大きな違いはありますか?
更新:疑問符が92%少なくなりました!
(別名:テスト結果)
最終結果は、36段階の展開プロセスのように感じられた後、現在本番環境にあります。両方のソリューションが広範囲にテストされました。
- 共有フォルダーコードをリッピングし、
SqlBulkCopy
クラスを直接使用します。 - TVPを使用したストアドプロシージャへの切り替え。
読者が正確に何がテストされたかを知ることができるように、このデータの信頼性に関する疑問を和らげるために、このインポートプロセスが実際に行うことのより詳細な説明を以下に示します。
通常は約20〜50データポイントの時間データシーケンスから始めます(ただし、数百になることもあります)。
データベースからほとんど独立している、クレイジーな処理をたくさん実行します。このプロセスは並列化されているため、(1)のシーケンスの約8〜10が同時に処理されています。各並列プロセスは、3つの追加シーケンスを生成します。
3つのシーケンスすべてと元のシーケンスを取得し、それらを1つのバッチに結合します。
現在完了している8〜10個の処理タスクすべてのバッチを1つの大きなスーパーバッチに結合します。
BULK INSERT
ストラテジー(次のステップを参照)またはTVPストラテジー(ステップ8にスキップ)のいずれかを使用してインポートします。SqlBulkCopy
クラスを使用して、スーパーバッチ全体を4つの永続的なステージングテーブルにダンプします。JOIN
(a)いくつかの条件を含む2つのテーブルで一連の集計ステップを実行し、(b)MERGE
集計データと非集計データの両方を使用して6つの本番テーブルで実行するストアドプロシージャを実行します。(終了)または
DataTable
マージするデータを含む4つのオブジェクトを生成します。そのうちの3つにはCLRタイプが含まれていますが、残念ながらADO.NET TVPでは適切にサポートされていないため、文字列表現として組み込む必要があり、パフォーマンスが少し低下します。TVPをストアドプロシージャにフィードします。ストアドプロシージャは、基本的に(7)と同じ処理を実行しますが、受信したテーブルを直接使用します。(終了)
結果はかなり近いものでしたが、データが1000行をわずかに超えた場合でも、TVPアプローチは最終的に平均してパフォーマンスが向上しました。
このインポートプロセスは何千回も連続して実行されるため、すべてのマージを完了するのにかかった時間(はい、時間)を数えるだけで、平均時間を取得するのは非常に簡単でした。
元々、平均的なマージが完了するまでにほぼ正確に8秒かかりました(通常の負荷の下で)。NetBIOSクラッジを削除し、に切り替えるとSqlBulkCopy
、時間がほぼ正確に7秒に短縮されました。TVPに切り替えると、バッチあたりの時間がさらに5.2秒に短縮されました。これは、実行時間が時間単位で測定されるプロセスのスループットが35%向上するため、悪くはありません。また、SqlBulkCopy
。よりも約25%向上しています。
私は実際、真の改善はこれよりもはるかに大きいとかなり確信しています。テスト中に、最終的なマージはもはやクリティカルパスではないことが明らかになりました。代わりに、すべてのデータ処理を実行していたWebサービスは、着信する要求の数に応じて座屈し始めていました。CPUもデータベースI / Oも実際には限界に達しておらず、重要なロックアクティビティはありませんでした。場合によっては、連続するマージの間に数秒のアイドル秒のギャップが見られました。わずかなギャップがありましたが、を使用するとはるかに小さくなりました(0.5秒程度)SqlBulkCopy
。しかし、それはまた別の日の話になると思います。
結論:テーブル値パラメーターはBULK INSERT
、中規模のデータセットで動作する複雑なインポート+変換プロセスの操作よりも実際に優れたパフォーマンスを発揮します。
プロステージングテーブルである人々の一部の不安を和らげるために、もう1つポイントを追加したいと思います。ある意味で、このサービス全体は1つの巨大なステージングプロセスです。プロセスのすべてのステップは徹底的に監査されるため、特定のマージが失敗した理由を特定するためのステージングテーブルは必要ありません(実際にはほとんど発生しませんが)。サービスにデバッグフラグを設定するだけで、デバッガーにブレークするか、データベースではなくファイルにデータをダンプします。
言い換えれば、私たちはすでにプロセスについて十分な洞察を持っており、ステージングテーブルの安全性を必要としません。そもそもステージングテーブルを用意した唯一の理由は、他の方法で使用しなければならなかったであろうすべてのステートメントINSERT
とUPDATE
ステートメントをスラッシングしないようにするためでした。元のプロセスでは、ステージングデータはとにかくステージングテーブルに数分の1秒しか存在しなかったため、メンテナンス/メンテナンスの観点からは何の価値もありませんでした。
また、すべての操作をTVPに置き換えたわけではないことにも注意しBULK INSERT
てください。大量のデータを処理する、および/またはデータをDBにスローする以外に特別なことを行う必要がないいくつかの操作では、引き続きが使用されますSqlBulkCopy
。 TVPがパフォーマンスの万能薬であることを示唆しているのではなくSqlBulkCopy
、最初のステージングと最後のマージの間のいくつかの変換を含むこの特定のインスタンスで成功したことだけを示しています。
だからあなたはそれを持っています。ポイントは、最も関連性の高いリンクを見つけるためにTToniに行きますが、他の回答にも感謝します。再度、感謝します!