在SQL Server上使用SqlBulkCopy的推动信封需要推荐(Need recommenda

2019-07-30 02:21发布

我设计的应用程序,其中一个方面是,它应该是能够接收大量数据到SQL数据库。 我设计了数据库狭窄作为一个单一的表BIGINT身份,这样的事情之一:

CREATE TABLE MainTable
(
   _id bigint IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    field1, field2, ...
)

我会忽略我怎么打算执行查询,因为它是不相关的我的问题。

我写了一个原型,其中中插入数据使用SqlBulkCopy的这个表。 它似乎在实验室中工作得很好。 我能够在3K〜记录/秒的速率插入数以千万计的记录(完整记录本身是相当大的,〜4K)。 由于在此表上唯一索引自动增量BIGINT,我还没有看到行显著量被推后也放缓。

考虑到实验室的SQL服务器是一个虚拟机相对较弱的配置(4GB内存,与其它的虚拟机磁盘sybsystem共享),我期待得到在物理机上显著更好的吞吐量,但它并没有发生,或者可以说,业绩增长可以忽略不计。 我可以,也许得到的物理机器上快25%的插入。 即使我配置3驱动RAID0,其进行比单个驱动器(用基准测试软件测量)快3倍,我没有改善。 基本上是:更快的驱动器子系统,专用物理CPU和RAM双几乎没有翻译成任何性能增益。

然后我重复使用Azure上的最大实例(8个核,16GB)的测试,并且我得到了相同的结果。 因此,增加更多的内核并没有改变插入速度。

在这个时候,我已经打得四处没有任何显著的性能增益以下软件的参数:

  • 修改SqlBulkInsert.BatchSize参数
  • 从多个线程同时插入,并调整线程#
  • 使用上SqlBulkInsert表锁选项
  • 通过使用共享存储器驱动从一个本地进程插入消除网络延迟

我想,以提高性能至少2-3次,和我原来的想法是,投入更多的硬件会得到吊环完成的,但到目前为止,没有。

因此,有人可以给我推荐:

  • 什么资源可以在这里怀疑瓶颈? 如何确认?
  • 有没有一种方法,我可以尝试得到可靠的可扩展的批量插入的改进考虑有一个单一的SQL服务器系统?

UPDATE我确信,负载的应用程序是没有问题的。 它创建一个临时队列记录在一个单独的线程,所以当有一个插入它是这样的(简化):

===>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的标准版本,所以不能依靠分区,因为它只有在企业版本。 但我想的分区方案的变体:

  • 创建文件组16(G0至G15),
  • 由16个表,用于插入只(T0至T15),每个结合到其各基团。 表是没有索引可言,甚至没有聚集INT身份。
  • 该插入穿过每个所有16个表的数据将周期线程。 这使得几乎每一个大容量插入操作使用它自己的表保证

这的确在BULK INSERT产量约20%的改善。 CPU核,LAN接口,驱动器I / O没有最大化,并在约25%的最大容量使用。

UPDATE4我认为现在是好得不能再好。 我是能推刀片使用下面的技术合理的速度:

  • 每个批量插入进入它自己的表,然后结果合并到一个主
  • 表重新创建新的,每批量插入,表锁使用
  • 二手IDataReader的执行从这里 ,而不是数据表。
  • 来自多个客户进行批量插入
  • 每个客户端使用单独的千兆VLAN访问SQL
  • 端进程访问主表使用NOLOCK选项
  • 我研究sys.dm_os_wait_stats,并sys.dm_os_latch_stats消除争

我也很难在这一点上谁得到的回答问题信用来决定。 你们当中谁没有得到一个“回答”,我道歉,这是一个非常艰难的决定,我感谢大家。

UPDATE5:下列项目可以使用一些优化:

  • 二手IDataReader的执行从这里 ,而不是数据表。

除非你有大量的CPU核心数的机器上运行您的程序,它可以使用一些重新分解。 由于它使用反射来生成get / set方法,变成对CPU的负载大。 如果性能是一个关键,它增添了不少的性能,当你手工编码的IDataReader,所以它被编译,而是采用反射

Answer 1:

对于调整的SQL Server的批量加载上的建议,请参阅数据加载和性能指南从MS的纸张,也指引优化大容量导入在线从书本。 虽然他们专注于批量加载从SQL Server,大多数建议适用于使用客户端API批量加载。 该文件适用于SQL 2008 - 你不说你靶向的SQL Server版本
两者都有相当多的,它的价值要通过详细信息。 然而,一些亮点:

  • 微创日志的批量操作。 使用大容量日志或简单恢复。 您可能需要启用跟踪标志610(但看到这样的警告)
  • 调整批量大小
  • 考虑分区目标表
  • 考虑批量加载过程中删除索引

精辟的总结从这个流程图数据加载和性能指南 :

正如其他人所说,你需要得到一些peformance柜台建立瓶颈的根源,因为你的实验表明,IO可能不是限制。 数据加载和性能指南包括SQL等待类型和性能计数器的列表监控(有链接到文档中没有锚,但是这是约75%是通过文件,在部分“优化大容量装载”)

UPDATE

我花了一段时间才能找到链接,但该SQLBits谈话由Thomas Kejser也非常值得关注-该幻灯片可如果你没有时间看整个事情。 它重复一些链接在这里的材料,而且还涵盖了如何处理的特定性能计数器高发几个其他的建议。



Answer 2:

看来你已经做了很多但我不知道如果你有机会学习阿尔贝托法拉利SqlBulkCopy的性能分析报告,该报告介绍了几种因素需要考虑与SqlBulkCopy的相关性能。 我会说很多在本文所讨论的东西还是值得尝试将好于先试。



Answer 3:

我不知道你为什么不上CPU,IO或内存获得100%的利用率。 但是,如果你只是想提高你的批量加载速度,这里是值得考虑:

  1. 分区上,数据文件分成不同的文件。 或者,如果他们是从不同来源,然后简单地创建不同的数据文件。
  2. 然后同时运行多个批量插入。

根据您的情况上面可能是不可行的; 但如果你能那么我相信它应该改善你的负载速度。



文章来源: Need recommendations on pushing the envelope with SqlBulkCopy on SQL Server