管理大容量复制的批大小

在大容量复制操作中,批的主要目的在于定义事务的范围。如果没有设置批大小,则大容量复制函数会将整个大容量复制视为一个事务。如果设置了批大小,则每个批构成一个事务,当批运行完成时,该事务也就被提交。

如果在没有指定批大小的情况下执行大容量复制并且遇到错误,则将回滚整个大容量复制。恢复长时间运行的大容量复制可能需要花费很长的时间。如果设置了批大小,则大容量复制将每个批视为一个事务并分别提交每个批。如果遇到错误,只需回滚最后一个未完成的批。

此外,批大小还会影响锁定开销。在针对 SQL Server 执行大容量复制时,可以使用 bcp_control 指定 TABLOCK 提示以获得表锁而不是行锁。对于整个大容量复制操作而言,持有单个表锁的开销最小。如果未指定 TABLOCK,则对各个行持有锁,并且在大容量复制操作期间维护所有锁的开销会导致性能降低。由于仅在事务执行期间才持有锁,因而可以通过指定批大小来解决此问题,因为这样可以定期生成能够释放当前持有的锁的提交。

如果要大容量复制大量的行,构成批的行的数目会对性能产生显著影响。建议采用的批大小取决于要执行的大容量复制的类型。

  • 在对 SQL Server 进行大容量复制时,请指定 TABLOCK 大容量复制提示并设置一个较大的批大小。

  • 如果不指定 TABLOCK,请将批大小限制为小于 1,000 行。

如果是从某个数据文件中进行大容量复制,则在调用 bcp_exec 之前,请首先通过调用带有 BCPBATCH 选项的 bcp_control 来指定批大小。如果使用 bcp_bindbcp_sendrow 从程序变量中进行大容量复制,可通过在调用 bcp_sendrow x 次之后(其中的 x 为一个批中的行数)再调用 bcp_batch 来控制批大小。

除了指定事务大小之外,批还会影响将行通过网络发送到服务器的时间。正常情况下,大容量复制函数缓存来自 bcp_sendrow 的行,直到填满一个网络数据包,然后将整个数据包发送到服务器。但是,如果应用程序调用 bcp_batch,则会不管当前数据包是否已填满而将其发送到服务器。使用很小的批大小可能导致向服务器发送许多部分填满的数据包,从而降低性能。例如,在每个 bcp_sendrow 后都调用 bcp_batch 会导致每个行都放在一个单独的数据包中进行发送,除非这些行很大,否则会浪费每个数据包中的空间。对于 SQL Server,网络数据包的默认大小为 4 KB,但是应用程序可以通过调用 SQLSetConnectAttr 并指定 SQL_ATTR_PACKET_SIZE 属性来更改此大小。

批的另一个副作用是,在使用 bcp_batch 完成每个批之前,每个批都被视为一个未完成的结果集。如果在批尚未完成之时对连接句柄尝试任何其他操作,SQL Server Native Client ODBC 驱动程序都会发出具有 SQLState = "HY000" 和以下错误消息字符串的错误:

"[Microsoft][SQL Server Native Client] Connection is busy with
results for another hstmt."