2

我有以下场景/要求,我不确定以最快的方式执行的最佳方法是什么,寻找一些使用功能的指导和它们的示例(如果有)

我将从我想要 upsert 的 Web 服务接收到 10k 到 100k 的实体(以 XML 格式)(有些行可能存在,其他行可能不存在)。

以下是一些要求:

  1. XML 的源是我从 C# 代码调用的 Web 服务。其实是两种不同的方法。对于其中一种方法,返回模式将是平坦的,我可以直接映射到我的一张表。另一方面,它将返回我可能需要在 C# 中使用的 XML 表示,以便能够将其映射到我的表的平面实体。在这种情况下,最好进行所需的修改,然后将文件写入 XML 以用作源?

  2. 返回的 XML 在 XML 中最多可以包含 150k 个实体,这些实体可能存在也可能不存在于我的表中,因此我希望更新它们。这些文件在写入磁盘时最大可达 20 兆字节。我问他们是否可以用 JSON 代替 XML,但显然这不是一个选择。

  3. SQL 数据库与我的 IIS 服务器位于不同的服务器上,因此我宁愿避免让 SQL 服务器从文件中检索 XML,而是将其从 C# 作为字符串或作为表值参数传递。

  4. 这些表相当简单,除了 PK 之外没有其他索引。

我从来没有对 XML 很感兴趣,虽然使用 LINQ to XML 变得更容易了,我最初用它来解析每条记录并发送单独的插入,但性能很差,所以根据我一直在做的一些研究,我想我可以使用:

  1. 通过 MERGE 语句从 SQL 服务器进行更新。
  2. 将整个 XML 作为参数传递并使用 OPENXML 作为 MERGE 语句中的源。
  3. 或者,以某种方式在 C# 中生成一个表值参数并将其传递给 SQL 以在 MERGE 上使用。
  4. 我读到了这个类似的问题(它没有访问 upsert/merge 的权限),而不是尝试直接从 XML 中进行 upsert,最好将所有内容插入临时表并对临时表进行合并/upsert?

这会工作并且相当快吗?

如果有人遇到过类似的情况,您能否分享您对哪种功能组合最好的想法/想法?

谢谢。

4

3 回答 3

0

你在正确的轨道上。我有一个类似的设置,使用 XML 在在线门户和客户端-服务器应用程序之间传输数据。其余的设置与您所拥有的非常相似。

如果您正在比较任何不是 PK 字段的字段,无论您如何索引临时表,您的表没有被索引的事实有点令人担忧。重要的是有一个索引包含合并匹配子句中使用的所有字段,或者每个索引都有一个索引 - 我发现前者会产生更好的性能。除此之外,还可以使用 XML 参数、OpenXML 和临时表。

以下代码尚未经过测试,因此可能需要进行一些调试,但它会让您走上正轨。几点注意事项:如果 OpenXML WITH 子句中的所有字段都是属性,那么您可以删除最后一个参数(即“, 2”)和字段源说明符(即详细表的“@id”)。尽管您描述中的数据是扁平的,在这种情况下您只需要一张表,但我确实经常需要导入链接记录。为了完整起见,我在下面的代码中包含了一个简单的主从关系示例。

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 回答
0

使用 (3)。在 C# 中处理准备好翻转的数据。C# 是为这种算法工作而设计的。它既是正确的编程语言,也是更快的编程语言。T-SQL 不是正确的工具。您不想将 XML 与 T-SQL 一起用于非常高性能的东西,因为它会疯狂地消耗 CPU。而是使用快速 TDS 协议来发送 TVP 或批量数据。

然后,使用 TVP 或批量插入 ( SqlBulkCopy) 将数据发送到服务器到临时表。后一种技术非常适合很多行(>10k?)。批量插入使用特殊的 TDS 功能。它不使用 SQL 批处理来传输数据。它不会比这更快。

然后使用MERGE您描述的语句。使用大批量,可能是一批中的所有行。

于 2013-06-01T11:16:42.580 回答
0

我发现的最佳方法是从 C# 代码批量插入临时表,然后在数据位于 SQL Server 中后发出合并。我的博客SQL Server Bulk Upsert上有一个示例

我在生产中使用它每天插入数百万行,但还没有找到更快的方法来做到这一点。试一试,我想您会对解决方案的性能印象深刻。

于 2016-02-16T04:43:46.083 回答