表值参数:以小块发送数据

Posted

技术标签:

【中文标题】表值参数:以小块发送数据【英文标题】:Table Valued Parameter: sending data in small chunks 【发布时间】:2012-09-17 21:33:11 【问题描述】:

我正在读取 csv 文件并将数据作为表变量发送到存储过程。从我到目前为止的测试来看,我能够在 3 分 30 秒内处理 300k 条记录。该文件可能包含多达数百万条记录。我想知道一次性将所有这些记录发送到存储过程是否是个好主意,或者我应该分批发送它们,比如 500k?我已将命令超时设置为 1800。

【问题讨论】:

你是指表变量还是表值参数? 是的,你是对的,我正在使用 TVP 将数据发送到存储过程。 我以为@MartinSmith 发布了一些关于传递到 TVP 的最佳行数阈值的信息,但我现在很难找到他的帖子。 我使用 TVP 加载数据,不认为你需要分解它。如果你跟踪它 - 它似乎一次处理一个。你是如何实施的?您是否使用实现 IEnumerable 的类?我发现更快的 DataTable 和更少的内存。 @AaronBertrand 如果您指的是插入值。 ***.com/questions/8635818/… 【参考方案1】:

IEnumerable SqlDataRecord 使用示例 它的工作原理有点像反向数据阅读器

注意我排序。这是通过聚集索引。索引的碎片化绝对会降低加载速度。第一个实现使用了插入值(未排序),在 12 小时的运行中,这个版本实际上快了 100 倍。我还在加载结束时禁用了 PK 和重新索引以外的索引。从长远来看,我得到大约 500 行/秒。你的样本是 1400 / 秒,太棒了。如果您开始看到退化,那么需要注意的事项。

public class DocFTSinXsCollection : List<DocFTSinX>, IEnumerable<SqlDataRecord>

    // used by TVP for fast insert
    private int sID;
    private IEnumerable<DocFTSinX> docFTSinXs;
    IEnumerator<SqlDataRecord> IEnumerable<SqlDataRecord>.GetEnumerator()
    
        //todo fix the order in 3 to sID, wordID1, workID2
        var sdr = new SqlDataRecord(
        new SqlMetaData("wordID1", System.Data.SqlDbType.Int),
        new SqlMetaData("wordID2", System.Data.SqlDbType.Int),
        new SqlMetaData("sID", System.Data.SqlDbType.Int),
        new SqlMetaData("Delta", System.Data.SqlDbType.Int));
        foreach (DocFTSinX oh in docFTSinXs.OrderBy(x => x.Word1).ThenBy(x => x.Word2))
        
            sdr.SetInt32(0, oh.Word1);
            sdr.SetInt32(1, oh.Word2);
            sdr.SetInt32(2, sID);
            sdr.SetInt32(3, (Int32)oh.Delta);
            yield return sdr;
        
    

    public DocFTSinXsCollection(int SID, IEnumerable<DocFTSinX> DocFTSinXs)
    
        sID = SID;
        docFTSinXs = DocFTSinXs;
        //Debug.WriteLine("DocFTSinXsCollection DocFTSinXs " + DocFTSinXs.Count().ToString());
    

要考虑的其他工具是 SQLBulkCopy .NET 类和 Drapper。

OP询问如何批量执行。

 while (true)
 
     // if no more break;
     // fill list or datatable with next 100000
     // send list or datatable to db
 

【讨论】:

谢谢Blam,我实际测试过,效率很高。但是 DBA 和管理层希望我每个请求发送 10 万条记录。你知道我们可以如何处理吗?我的意思是向数据表发送 100K 请求或如何? 查看问题末尾的更新。请求不是正确的术语。它是一个插入。 TVP 实现将一次发送插入一条记录,而不管批量大小。您已经说过您在 SQL 分析器中看到了这一点。 是的,@Blam 谢谢你的纠正。我是新手,感谢您的帮助。所以问题是在 C# 中有没有办法可以向 TVP 发送 100k 插入? 我最终使用了以下建议的方法:***.com/questions/769373/…

以上是关于表值参数:以小块发送数据的主要内容,如果未能解决你的问题,请参考以下文章

表值参数

在 C# 中以小块下载大文件

sh 以小块剪切给定的声音文件。对有声读物非常有用。

如何以小块上传带有ajax的文件并检查失败,重新上传失败的部分。

mysql数据库表值乱码问题:

SQL Server存储过程中使用表值作为输入参数示例