roc*_*ing 3 performance sql-server insert t-sql sql-server-2012
我有一个要求,我必须插入很多行。对于插入,我们像这样使用
insert into emp(name,age) values('abc',12);
Run Code Online (Sandbox Code Playgroud)
这将只插入一行。对于插入多行,我们可以多次编写插入查询或编写具有多个值的单个查询。例如
条件 1
insert into emp(name,age) values('abc1',121);
insert into emp(name,age) values('abc2',122);
insert into emp(name,age) values('abc3',12);
Run Code Online (Sandbox Code Playgroud)
条件2
insert into emp(name,age) values('abc',12),('abc2',122),('abc3',12);
Run Code Online (Sandbox Code Playgroud)
我的问题是上面的(条件 1 和条件 2)都需要时间吗?我猜条件 2 比条件 2 花费的时间少。如果我的猜测是真的,那么原因是什么?
至少在 SQL Server 中(不能代表你提到的其他 RDBMS,抱歉),单个语句在某种程度上比多个语句更好。当然,您可以使用您的确切陈述和数据自行测试;这里没有人可以用你的具体情况为你测试,你的具体情况可能会以一种或另一种方式倾斜事情。“哪个更快,x 还是 y?” 这里一般不鼓励提问,因为您可以在自己的环境中测试它们,这比我们任何人向您抛出的猜测和逻辑要快得多。特别是当您试图为您列出的所有数据库平台获得答案时 - 没有人是所有这些平台的专家,任何此类答案要么非常有偏见(如这个),要么过于笼统而无用.
但是,一般来说,准备单个语句(并可能根据您的代码和提供者的行为单独发送它们)的开销应该加起来,就像@mustaccio 所说的那样:
如果你要寄三封信,你会带着三封信去邮局一次,还是带着一封信去三次?
如果每个小语句都被分解为单个数据包甚至不同的连接,那么在您的场景中尤其如此。同样,我不知道您的提供程序如何工作或您的代码如何发送这些语句 - 如果它是一组可变数量的语句,实际上SQL Server 比单个单语句批处理更难优化,因为 SQL Server在批处理级别进行优化。
请注意,该VALUES()
子句具有1,000 个值的任意限制,因此您可能需要根据您拥有的值数量创建多个语句。原因是担心编译时间,正如Paul White 在此处解释的那样。另请注意:Oracle 具有相同的限制。
根据Martin Smith 的测试,编译时间至少是最短的,并且相对不变,最多可达 250 多个值。请参阅这些图表(有关详细信息,请参阅他的回答):
如果您使用VALUES()
子句,请注意每个变体(即实际值集的数量)都将生成自己的计划,无论您是使用正确的参数化语句还是仅使用内联常量,即使设置了数据库的参数化设置也是如此简单。因此,您可能需要考虑使用optimize for ad hoc workloads
服务器设置(此处和此处提供了大量信息以防止一次性变体填充计划缓存(无论如何对于大多数系统来说通常是个好主意,除非您受 CPU 限制并且编译成本被证明为过分)。
这个问题的一个更好的答案是使用表值参数 (TVPs),它允许您通过单个参数发送结构化数据集,为您提供一种有效的数据传递方式和一个可以重用的单一计划,而不管传递的值数。这里的问题是我不确定 Java 是否理解这些是什么(在 C# 中,您可以发送,例如,一个 DataTable 作为Structured
参数)。
对于 SQL Server:两者都不是。
要插入大量行,您应该使用批量插入 API,并努力实现最少记录的插入。
可以使用IRowsetFastLoad
(OleDB)、使用批量复制功能(ODBC) 或使用SqlBulkCopy
(.Net)来实现批量插入。所有这些 API 的共同点是它们与服务器建立了一个快速插入管道,然后它们开始推送行。这些不是 T-SQL 语句,而是 TDS批量加载消息的实现。在更高的抽象层,您可以使用bcp.exe、BULK INSERT
语句或启用快速加载选项的SSIS OleDB 目标。
第二个可选的改进是实现最少的日志记录。请参阅可以最少记录的操作(批量插入可以,普通插入不能)。有关详细信息,请阅读批量导入中最少日志记录的先决条件。
最后,我敦促您花一些时间阅读SQL Server 数据加载性能指南。
归档时间: |
|
查看次数: |
5151 次 |
最近记录: |