我正在设计一个应用程序,其中一个方面是它应该能够将大量数据接收到SQL数据库中。我将数据库stricture设计为具有bigint标识的单个表,如下所示:
CREATE TABLE MainTable
(
_id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
field1, field2, ...
)
我将省略我打算如何执行查询,因为它与我的问题无关。
我编写了一个原型,它使用SqlBulkCopy将数据插入到该表中。它似乎在实验室中运作良好。我能够以~3K记录/秒的速率插入数千万条记录(完整记录本身相当大,~4K)。由于此表上唯一的索引是自动递增bigint,因此即使推送了大量行,我也没有看到减速。
考虑到实验室SQL服务器是配置相对较弱的虚拟机(4Gb RAM,与其他VM磁盘sybsystem共享),我期望在物理机上获得明显更好的吞吐量,但它没有发生,或者说让性能提升可以忽略不计。我可以,也许在物理机器上插入速度提高25%。即使我配置了3驱动器RAID0,其执行速度比单个驱动器快3倍(由基准测试软件测量),但我没有任何改进。基本上:更快的驱动子系统,专用的物理CPU和双RAM几乎没有转化为任何性能增益。
然后我使用Azure上的最大实例(8核,16Gb)重复测试,我得到了相同的结果。因此,添加更多内核并未改变插入速度。
此时我已经使用了以下软件参数而没有任何显着的性能提升:
我试图将性能提升至少2-3次,而我最初的想法就是投入更多的硬件才能完成,但到目前为止还没有。
所以,有人可以推荐我:
更新我确定加载应用不是问题。它在一个单独的线程中创建一个临时队列中的记录,所以当有一个插入时它就像这样(简化):
===>start logging time
int batchCount = (queue.Count - 1) / targetBatchSize + 1;
Enumerable.Range(0, batchCount).AsParallel().
WithDegreeOfParallelism(MAX_DEGREE_OF_PARALLELISM).ForAll(i =>
{
var batch = queue.Skip(i * targetBatchSize).Take(targetBatchSize);
var data = MYRECORDTYPE.MakeDataTable(batch);
var bcp = GetBulkCopy();
bcp.WriteToServer(data);
});
====> end loging time
记录时间,创建队列的部分永远不会占用任何重要的块
UPDATE2 我已经实现了收集该周期中每个操作所需的时间,布局如下:
queue.Skip().Take()
- 可忽略不计MakeDataTable(batch)
- 10%GetBulkCopy()
- 可忽略不计WriteToServer(data)
- 90%UPDATE3 我正在为标准版本的SQL设计,所以我不能依赖分区,因为它只在企业版中可用。但我尝试了一种分区方案的变体:
这确实使散装插入物的产量提高了约20%。 CPU内核,LAN接口,驱动器I / O没有最大化,并且使用的最大容量约为25%。
UPDATE4 我认为它现在已经很好了。我能够使用以下技术将插入物推到合理的速度:
我现在很难决定谁会因为回答的问题而获得赞誉。那些没有得到回答的人,我道歉,这是一个非常艰难的决定,我感谢你们所有人。
UPDATE5 :以下项目可以使用一些优化:
除非您在具有大量CPU核心数的计算机上运行程序,否则它可能会使用一些重新分解。由于它使用反射生成get / set方法,因此成为CPU的主要负载。如果性能是关键,那么当您手动编写IDataReader时,它会增加很多性能,因此它会被编译,而不是使用反射
答案 0 :(得分:4)
有关针对批量加载调优SQL Server的建议,请参阅MS中的Data Loading and Performance Guide论文,以及联机丛书中的Guidelines for Optimising Bulk Import。虽然它们专注于从SQL Server批量加载,但大多数建议都适用于使用客户端API进行批量加载。本文适用于SQL 2008 - 您没有说明您要针对哪个SQL Server版本 两者都有相当多的信息,值得详细介绍。但是,有些亮点:
在Data Loading and Performance Guide的流程图中很好地总结了:
正如其他人所说,你需要得到一些性能计数器来确定瓶颈的来源,因为你的实验表明IO可能不是限制。 Data Loading and Performance Guide包括要监视的SQL等待类型和性能计数器的列表(文档中没有要链接的锚点,但在“优化批量加载”一节中,这大约是文档的75%)
更新
我花了一段时间才找到这个链接,但是Thomas Kejser的this SQLBits talk也非常值得一看 - 如果你没有时间观看整个事情,slides可用。它重复了这里链接的一些材料,但也涵盖了如何处理特定性能计数器的高发生率的其他一些建议。
答案 1 :(得分:2)
看来你已经做了很多但是我不确定你是否有机会学习Alberto Ferrari SqlBulkCopy Performance Analysis报告,该报告描述了考虑与SqlBulkCopy相关的性能的几个因素。我会说在那篇论文中讨论的很多东西仍然值得尝试,首先尝试。
答案 2 :(得分:1)
我不确定为什么你没有100%利用CPU,IO或内存。但是,如果您只是想提高批量加载速度,请考虑以下事项:
根据您的情况,上述情况可能不可行;但如果可以,那么我相信它可以提高你的加载速度。