从 C# SQLCLR 存储过程批量插入 SQL Table 的最快方法

Fastest way to bulk insert in SQL Table from C# SQLCLR Stored Procedure

我有一个 C# SQLCLR 存储过程,其中首先将数据填充到一些字典中并进行计算,然后将输出存储在其他一些字典中。

这个计算完成得非常快,因为使用了字典,完全证明了我需要使用 CLR 存储过程而不是普通的 SQL 存储过程。

但是,我必须从这些输出词典中将数据保存在 SQL 中的某些表中,这部分需要很多时间并且无法满足我对整个 SQLCLR proc 的需求更快。

我必须遍历每个输出字典的每个键,然后必须创建插入查询,然后必须 运行 以下列方式执行 ExecuteNonQuery:

那么我该如何改进我的这种方法,以便插入数据时不花时间。我不能将 SqlBulkCopy 用作 it does not accept the in-process Context Connection(即 "Context Connection = true;")作为 connectionString。那么还有其他更快的方法可用吗?提前致谢。

使用SqlBulkCopy Class or you can create your own User-Defined Table Type in sql, in c# - generate your data into a DataTable, instead of some collection, which will match your user-defined type, then pass your DataTable as SqlParameter and execute. Or you can add your Collection directly into table value parameter, as shown HereuseDataTable == false部分)

当然,为此您应该使用 sql 存储过程。 sql 用户定义的 table 类型的调用部分将如下所示:

cmd = new SqlCommand{ Connection = conn, ...
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "sp_YourStoredProcedureName";
cmd.Parameters.Add(new SqlParameter("@UserDefinedTypeParameterName", yourDataTable));
cmd.ExecuteNonQuery();

您有几个选择:

  1. 创建用户定义的 Table 类型 (UDTT) 和接受该 UDTT 作为参数的 T-SQL 存储过程(即 Table - 值参数(TVP))。由于您已经在集合中拥有数据,绝对 NOT 创建一个单独的 DataTable 来将数据传输到其中,因为那只是浪费时间、内存和 CPU。您可以通过创建 returns IEnumerable<SqlDataRecord>、使用 yield return; 并用作 SqlParameter 的值的方法,将其本机集合中的数据直接流式传输到 TVP代表UDTT。我在 SO 上有两个这样的例子:

    • How can I insert 10 million records in the shortest time possible?
    • Pass Dictionary<string,int> to Stored Procedure T-SQL
  2. 如果只有 1 个 table 需要填充(因此有 1 个结果集),那么您可以将集合作为结果集从存储过程中输出并按如下方式使用它:

    INSERT INTO schema.table (column_list)
      EXEC schema.SQLCLR_stored_procedure @param1, ....;
    
  3. 如果只有 1 个 table 可以填充(因此有 1 个结果集), 如果您没有对上下文执行任何操作违反标量函数规则的连接,那么你可以尝试将 SQLCLR 存储过程更改为 TVF,return IEnumerable,并通过 [= 迭代 return 13=] 将其流出。我几年前在 SQL Server Central 上写了一篇文章,其中有一个例子:CLR Table-Valued Function Example with Full Streaming (STVF / TVF)