10

我不知道这是我使用它们还是Microsoft实现的问题,但SQL 2008表值参数很痛苦。表值参数性能问题

一般来说,如果我需要使用TVP,那是因为我有很多记录 - 目前它们看起来对于任何超过最少记录的速度都是不可用的缓慢。

我打电话给他们的.Net这样的:

// get the data 
DataTable data = GetData(); 

com.CommandText = "sprocName" 

// create the table-value parameter 
var tvp = com.Parameters.AddWithValue("data", data); 
tvp.SqlDbType = SqlDbType.Structured; 

com.ExecuteNonQuery(); 

我跑探查明白为什么,和实际的SQL语句是这样的:

declare @data table ... 

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

sprocName(@data) 

这是一个非常缓慢的尽管如此。 这将是更快,如果它这样做,而不是:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 
     -- for each row 
     (... values ...) 

我不知道为什么它不使用较新的,更快的语法。或者甚至无论它在SqlBulkCopy的引擎下做什么。

在SQL 2008中添加了新的语法,但TVP(我认为)也是如此。

有没有一些选择让它做到这一点?或者我错过了什么?

+3

如果SQL事件探查器跟踪被标记为RPC(未批),这意味着所显示的文字是不是被传送线一个真正的文本,而是从实际的RPC参数重新构建的文本。这并不能解释为什么它很慢,但它可能没有意义。 – 2011-05-20 12:40:29

回答

3

参看“表值参数与BULK INSERT操作”
http://msdn.microsoft.com/en-us/library/bb510489.aspx

引用:“......表值参数的表现良好,用于插入小于1000行。”

它还有一个表格,根据插入操作的速度显示使用哪种技术。

我希望这会有所帮助,祝你好运。

+0

干杯。然而,实际上,即使对于有几百行的表格,TVP仍然明显慢于值列表选项,甚至比第一次调用后的“SqlBulkCopy”慢(第一次运行'SqlBulkCopy'需要额外的1- 2s由于某种原因)。 – Keith 2011-05-20 13:24:40

+0

@Keith和Robert,该链接文档中的信息需要在上下文中进行。请参阅我的回答,特别是底部的白皮书。 – 2015-02-24 17:54:11

+1

@srutzky,谢谢你这是一个很好的答案。 – Robert 2015-02-25 08:36:01

9

如果TVPs比其他选项“明显慢”,那么很可能你没有正确实施它们。

  1. 您不应该使用DataTable,除非您的应用程序在向TVP发送值之外使用它。使用IEnumerable<SqlDataRecord>接口速度更快,并且使用的内存更少,因为您不会将内存中的集合复制到内存中,而只是将其发送到数据库。我有这样的记录在以下地方:
  2. 对于SqlParameter,您不应该使用AddWithValue,尽管这不可能是性能问题。但尽管如此,它应该是:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured); 
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection); 
    
  3. 台湾居民入境许可证是表变量,因此不维护统计数据。意思是,他们只向Query Optimizer报告1行。所以,在你的PROC,或者:
      上使用TVP的不是一个简单的SELECT以外的任何任何疑问
    • 使用语句级重新编译:OPTION (RECOMPILE)
    • 创建本地临时表(即单#)和复制内容在TVP到临时表

的关于为什么你看到:

insert into @data (... fields ...) values (... values ...) 
-- for each row 
insert into @data (... fields ...) values (... values ...) 

代替:

insert into @data (... fields ...) 
values (... values ...), 
     (... values ...), 

,如果这是真正发生了什么,然后:

  • 如果插入正在一个事务中完成的话就没有真正的性能差异
  • 较新的价值 - 列表语法(即VALUES (row1), (row2), (row3))仅限于1000行,因此对于没有这个限制的TVP来说不是一个可行的选择。

另请参阅从SQL Server客户顾问团队本白皮书:Maximizing Throughput with TVP