表值参数性能的问题

Kei*_*ith 13 .net sql-server performance sql-server-2008 table-valued-parameters

我不知道这是否是我使用它们或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();
Run Code Online (Sandbox Code Playgroud)

我运行探查器来查看原因,实际的SQL语句是这样的:

declare @data table ...

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

sprocName(@data)
Run Code Online (Sandbox Code Playgroud)

尽管如此,这是一个非常缓慢的方法.如果这样做会更快:

insert into @data ( ... fields ... ) 
values ( ... values ... ),
       ( ... values ... ),
       -- for each row
       ( ... values ... )
Run Code Online (Sandbox Code Playgroud)

我不确定为什么它没有使用更新,更快的语法.甚至无论它在引擎盖下做什么SqlBulkCopy.

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

有没有选择让它这样做?还是我错过的东西?

Sol*_*zky 14

如果TVP比其他选项"明显慢",那么很可能你没有正确实现它们.

  1. 您不应该使用DataTable,除非您的应用程序在将值发送到TVP之外使用它.使用IEnumerable<SqlDataRecord>接口更快并且使用更少的内存,因为您不在内存中复制集合仅将其发送到数据库.我在以下地方记录了这一点:
  2. 您不应该使用AddWithValueSqlParameter,尽管这可能不是性能问题.但是,它应该是:

    SqlParameter tvp = com.Parameters.Add("data", SqlDbType.Structured);
    tvp.Value = MethodThatReturnsIEnumerable<SqlDataRecord>(MyCollection);
    
    Run Code Online (Sandbox Code Playgroud)
  3. TVP是表变量,因此不保持统计数据.这意味着,他们报告查询优化器只有1行.所以,在你的过程中,要么:
    • 对使用TVP的任何查询使用语句级重新编译,而不是简单的SELECT: OPTION (RECOMPILE)
    • 创建一个本地临时表(即单个#)并将TVP的内容复制到临时表中

关于你为什么看到:

insert into @data ( ... fields ... ) values ( ... values ... )
-- for each row
insert into @data ( ... fields ... ) values ( ... values ... )
Run Code Online (Sandbox Code Playgroud)

代替:

insert into @data ( ... fields ... ) 
values ( ... values ... ),
       ( ... values ... ),
Run Code Online (Sandbox Code Playgroud)

如果这实际上是发生了什么,那么:

  • 如果插入是在事务中完成的,那么就没有真正的性能差异
  • 较新的值列表语法(即VALUES (row1), (row2), (row3))限于1000行,因此对于没有该限制的TVP而言不是可行的选项.

另请参阅SQL Server客户咨询团队的白皮书:使用TVP最大化吞吐量


Rob*_*ert 5

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

引用:“...表值参数在插入少于 1000 行时表现良好。”

它还有一个表格来显示根据插入操作的速度使用什么技术。

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