2

次のシナリオ/要件があり、可能な限り最速の方法で実行するための最善の方法がわからないため、使用する機能のガイダンスとその例を探しています (利用可能な場合)

アップサートしたい Web サービスから 10k から 100k のエンティティ (XML 形式) を受け取ります (いくつかの行は存在するかもしれませんが、他の行は存在しないかもしれません)。

要件の一部を次に示します。

  1. XML のソースは、C# コードから呼び出す Web サービスです。実際には2つの異なる方法。メソッドの 1 つでは、返されるスキーマは、テーブルの 1 つに直接マップできるフラットなものになります。もう 1 つは、テーブルのフラット エンティティにマップできるようにするために C# で作業する必要がある XML 表現を返します。そのシナリオでは、必要な変更を行ってから XML にファイルに書き込んでソースとして使用するのが最善でしょうか?

  2. 返された XML には、テーブルにまだ存在する場合と存在しない場合がある XML で最大 150k のエンティティを含めることができるため、それらをアップサートしようとしています。ファイルは、ディスクに書き込まれると、最大 20 メガバイトになることがあります。XML の代わりに JSON を使用できるかどうか尋ねましたが、どうやらそれは選択肢ではないようです。

  3. SQL データベースは IIS サーバーとは別のサーバー上にあるため、SQL サーバーがファイルから XML を取得することは避け、C# から文字列またはテーブル値パラメーターとして渡します。

  4. テーブルはかなり単純で、PK 以外のインデックスはありません。

私は XML にあまり詳しくありませんでしたが、最初は各レコードを解析して個々の挿入を送信するために使用していた LINQ to XML で簡単になりましたが、パフォーマンスは悪かったので、私が行っているいくつかの調査に基づいて、私は使用できると考えています:

  1. MERGE ステートメントを介して SQL サーバーからアップサートします。
  2. XML 全体をパラメーターとして渡し、OPENXML を使用して MERGE ステートメントのソースとして使用します。
  3. または、何らかの方法で C# でテーブル値パラメーターを生成し、それを SQL に渡して MERGE で使用します。
  4. この同様の質問(更新/マージにアクセスできませんでした)を読みましたが、XML から直接更新/挿入しようとする代わりに、すべてを一時テーブルに挿入し、一時テーブルに対してマージ/更新/挿入を行う方がよいのではないでしょうか?

これは機能し、かなり高速ですか?

誰かが同様のシナリオを経験したことがある場合は、どの機能の組み合わせが最適かについての考えやアイデアを共有できますか?

ありがとう。

4

3 に答える 3

0

あなたは正しい軌道に乗っています。XML を使用して、オンライン ポータルとクライアント/サーバー アプリケーションの間でデータを転送する同様のセットアップがあります。セットアップの残りの部分は、あなたが持っているものと非常に似ています。

一時テーブルにインデックスを付ける方法に関係なく、PK フィールドではないフィールドを比較する場合、テーブルにインデックスが付けられていないという事実は少し心配です。マージ一致句で使用されるすべてのフィールドを含む 1 つのインデックス、またはそれらのそれぞれのインデックスを使用することが重要です。前者の方がパフォーマンスが優れていることがわかりました。さらに、XML パラメーターを使用して、OpenXML と一時テーブルを使用する方法があります。

次のコードはテストされていないため、多少のデバッグが必要になる場合がありますが、正しい軌道に乗せることができます。いくつかの注意事項: OpenXML WITH 句のすべてのフィールドが属性の場合、最後のパラメーター (つまり、", 2") とフィールド ソース指定子 (つまり、詳細テーブルの "@id") を削除できます。説明のデータはフラットですが、その場合、必要なテーブルは 1 つだけですが、リンクされたレコードにインポートする必要があることがよくあります。完全を期すために、単純な主従関係の例を以下のコードに含めました。

CREATE PROCEDURE usp_ImportFromXML (@data XML) AS
BEGIN
/*
    <root>
        <data>
            <match_field_1>1</match_field_1>
            <match_field_2>val2</match_field_2>
            <data_1>val3</data_1>
            <data_2>val4</data_2>
            <detail_records>
                <detail_data id="detailID1">
                    <detail_1>blah1<detail_1>
                    <detail_2>blah2<detail_2>
                </detail_data>
                <detail_data id="detailID2">
                    <detail_1>blah3<detail_1>
                    <detail_2>blah4<detail_2>
                </detail_data>
            </detail_records>
        </data>
        <data>
            ...
    </root>
*/
    DECLARE @iDoc INT
    EXEC sp_xml_preparedocument @iDoc OUTPUT, @data
    SELECT * INTO #temp
    FROM OpenXML(@iDoc, '/root/data', 2) WITH (
        match_field_1 INT,
        match_field_2 VARCHAR(50),
        data_1 VARCHAR(50),
        data_2 VARCHAR(50)
    )

    SELECT * INTO #detail
    FROM OpenXML(@iDoc, '/root/data/detail_data', 2) WITH (
        match_field_1 INT '../../match_field_1',
        match_field_2 VARCHAR(50) '../../match_field_2',
        detail_id VARCHAR(50) '@id',
        detail_1 VARCHAR(50),
        detail_2 VARCHAR(50)
    )

    EXEC sp_xml_removedocument @iDoc

    CREATE INDEX #IX_temp ON #temp(match_field_1, match_field_2)
    CREATE INDEX #IX_detail ON #detail(match_field_1, match_field_2, detail_id)

    MERGE data_table a
        USING #temp ta
        ON ta.match_field_1 = a.match_field_1 AND ta.match_field_2 = a.match_field_2
    WHEN MATCHED THEN
        UPDATE SET data_1 = ta.data_1, data_2 = ta.data_2
    WHEN NOT MATCHED THEN
        INSERT (match_field_1, match_field_2, data_1, data_2) VALUES (ta.match_field_1, ta.match_field_2, ta.data_1, ta.data_2)

    MERGE detail_table a
        USING (SELECT d.*, p._key FROM #detail d, data_table p WHERE d.match_field_1 = p.match_field_1 AND d.match_field_2 = p.match_field_2) ta
        ON a.id = ta.id AND a.parent_key = ta._key
    WHEN MATCHED THEN
        UPDATE SET detail_1 = ta.detail_1, detail2 = ta.detail_2
    WHEN NOT MATCHED THEN
        INSERT (parent_key, id, detail_1, detail_2) VALUES (ta._key, ta.id, ta.detail_1, ta.detail_2)    

    DROP TABLE #temp
    DROP TABLE #detail
END
于 2013-06-01T10:19:12.553 に答える