bcp / BULK INSERT与表值参数的性能

时间:2010-01-27 20:07:02

标签: performance sql-server-2008 bulkinsert table-valued-parameters

4 个答案:

答案 0 :(得分:8)

我还没有真正的TVP经验,但在MSDN here中有一个不错的性能对比图表与BULK INSERT。

他们说BULK INSERT具有更高的启动成本,但此后更快。在远程客户端场景中,他们绘制大约1000行的行(对于“简单”服务器逻辑)。从他们的描述来看,我会说你使用TVP应该没问题。性能损失 - 如果有的话 - 可能是微不足道的,而且架构效益看起来非常好。

编辑:在旁注中,您可以避免服务器本地文件,并仍然使用SqlBulkCopy对象使用批量复制。只需填充DataTable,并将其提供给SqlBulkCopy实例的“WriteToServer”-Method。易于使用,速度非常快。

答案 1 :(得分:5)

关于@TToni回答中提供的链接所提到的图表需要在上下文中进行。我不确定这些建议的实际研究有多少(同时请注意,该图表似乎仅在该文档的20082008 R2版本中提供)。

另一方面,SQL Server客户咨询小组提供了这份白皮书:Maximizing Throughput with TVP

我自2009年以来一直在使用TVP,并且至少根据我的经验发现,除了简单地插入到目的地表而没有额外的逻辑需求之外的任何事情(这种情况很少发生),那么TVP通常是更好的选择。

我倾向于避免使用临时表,因为数据验证应该在应用层进行。通过使用TVP,可以轻松容纳,并且存储过程中的TVP表变量本质上是一个本地化的临时表(因此与使用真实表进行分段时获得的同时运行的其他进程不会发生冲突)。

关于在课题中进行的测试,我认为它可能比最初发现的更快:

  1. 您不应该使用DataTable,除非您的应用程序在将值发送到TVP之外使用它。使用IEnumerable<SqlDataRecord>接口更快并且使用更少的内存,因为您不在内存中复制集合仅将其发送到数据库。我在以下地方记录了这一点:
  2. TVP是表变量,因此不保留统计信息。这意味着,他们报告查询优化器只有1行。所以,在你的过程中,要么:
    • 对使用TVP的任何查询使用语句级重新编译,而不是简单的SELECT:OPTION (RECOMPILE)
    • 创建本地临时表(即单#)并将TVP的内容复制到临时表中

答案 2 :(得分:4)

我想我仍然坚持使用批量插入方法。您可能会发现tempdb仍然会被使用具有合理行数的TVP命中。这是我的直觉,我不能说我已经测试过使用TVP的表现(虽然我有兴趣听别人输入)

您没有提及是否使用.NET,但我采用优化以前解决方案的方法是使用SqlBulkCopy类进行大量数据加载 - 您不需要编写在加载之前首先将数据写入文件,只需给SqlBulkCopy类(例如)一个DataTable - 这是将数据插入数据库的最快方法。 5-10K行并不多,我已经将它用于最多750K行。我怀疑,一般来说,使用TVP几百行不会产生巨大的差异。但扩大规模将受到限制恕我直言。

SQL 2008中新的MERGE功能可能对您有所帮助吗?

此外,如果您现有的临时表是用于此进程的每个实例的单个表,并且您担心争用等,您是否考虑过每次创建一个新的“临时”但物理登台表,然后删除它什么时候结束?

请注意,您可以通过在不使用任何索引的情况下填充来优化对此临时表的加载。然后填充后,在该点添加任何所需的索引(FILLFACTOR = 100以获得最佳读取性能,因此此时不会更新)。

答案 3 :(得分:0)

临时表很好!真的,我不想以任何其他方式去做。为什么?因为数据导入可能会意外地发生变化(并且通常以您无法预见的方式,例如列仍被称为名字和姓氏但在姓氏列中具有名字数据的时间,例如,选择一个示例而不是随机。)易于使用临时表研究问题,以便您可以确切地看到导入处理的列中的数据。当你使用内存表时,我觉得更难找到。我知道有很多人像我一样以进口为生,所有人都建议使用临时桌。我怀疑这是有原因的。

与重新设计流程相比,进一步将小模式更改固定到工作流程更容易,耗时更少。如果它正在工作且没有人愿意花费数小时来更改它,那么只修复由于架构更改而需要修复的内容。通过改变整个过程,您可以引入更多潜在的新错误,而不是对现有的,经过测试的工作流程进行小的更改。

您将如何取消所有数据清理任务?您可能采用不同的方式,但仍需要完成它们。同样,以您描述的方式更改流程非常危险。

就我个人而言,听起来像是因为使用旧技术而不是有机会玩新玩具而被冒犯。你似乎没有真正的基础想要改变,除了批量插入是如此2000。