这个问题刚刚开始在分析器中出现。我们得到的结果如下:
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "INSERT INTO #Ids VALUES (@0);";
cmd.Parameters.Add(cmd.CreateParameter() { ParameterName = "@0", DbType = GetDbType() });
cmd.Prepare();
foreach (var value in values)
{
((IDbDataParameter)cmd.Parameters[0]).Value = value;
cmd.ExecuteNonQuery();
}
}
我们正在研究通过减少往返次数来加快速度的可能性。在这里使用 DataTable 会很麻烦,但有一种类型SqlDataRecord
似乎适合,所以我们应该能够做这样的事情:
using (var cmd = connection.CreateCommand())
{
cmd.CommandText = "INSERT INTO #Ids SELECT * FROM @0;";
var param = cmd.CreateParameter();
param.ParameterName = "@0";
// FIXME more properties
cmd.Parameters.Add(param);
param.Value = values.Cast<T>().Select((x) => {
// FIXME Create new SqlDataRecord
}.ToList();
cmd.ExecuteNonQuery();
}
与其他示例不同的是,这里的主要困难在于T
;此代码是动态的,接收大量可能的类型;因此CREATE TYPE
无法工作。不可能为每种可能的 VARCHAR 长度创建一个类型。
我该如何填写上面的 FIXME 注释?
相关问题,没有好的答案:当我有一个很大的 ID 列表时,如何在 SQL Server 中创建临时表
评论中有人要求看大图。这里确实没有很好的办法通过缩小范围来获取更多信息。代码库中只有一个例程副本,用于设置所有 SQL 调用(即存储过程)的参数,就是这样。
行数的比例因子是长尾的;平均行数小于 10,但最大大小非常大,并且超过一千次的调用经常发生。因此,我们加载一个临时表;并且在转换为执行循环以外的操作时,foreach
我们仍然加载一个临时表。
一个完整工作的例子。
听起来 TVP 可能不太适合您。
但是您可以使用临时表
SqlBulkCopy
,这比单独插入要快得多。您可以传递
SqlBulkCopy
或DataTable
。DbDataReader
前者创建起来很简单,但占用的内存很大。您可以使用免费的FastMember 库简单地创建一个读取器。