如何减少批量nvarchar(max)更新的事务日志增长

时间:2010-01-06 17:01:34

标签: sql-server ado.net transactions sqltransaction

我们的应用需要向SQL Server 2005数据库添加大量文本(单条记录最多1 GB)。出于性能原因,这是通过对每个块(例如,usp_AddChunk)进行存储过程调用来以块的形式完成的。 usp_AddChunk没有任何明确的交易。

我所看到的是,将块大小从100MB减少到10MB会导致大量的事务日志。我被告知这是因为每次调用usp_AddChunk时,“隐式”(我的术语)事务将记录所有现有文本。因此,对于150MB的记录:

100MB块大小:100(记录0字节)+ 50(记录100 MB)= 100 MB记录

将小于

10 MB块大小:10(记录0字节)+ 10(记录10 MB)+ 10(记录20 MB)... + 10(记录140 MB)=记录1050 MB

我认为通过在我的C#代码中打开一个事务(在我添加第一个块之前,并在最后一个块之后提交),这个“隐式”事务不会发生,我可以避免巨大的日志文件。但我的测试表明,使用ADO.NET事务,事务日志的增长速度提高了5倍。

我不会发布代码,但这里有一些细节:

  1. 我调用SqlConnection.BeginTransaction()
  2. 我为每个块使用不同的SqlCommand
  3. 我将(1)中的SqlTransaction分配给每个SqlCommand
  4. 我经常在每次执行SqlCommand后关闭连接,但我也尝试不用相同的结果关闭连接
  5. 这个方案的缺陷是什么?如果您需要更多信息,请告诉我。谢谢!

    注意:使用简单或批量记录的恢复模型不是一个选项

2 个答案:

答案 0 :(得分:3)

如果用'chunks'表示类似的话:

UPDATE table
SET blob = blob + @chunk
WHERE key = @key;

然后你是对的,操作已完全记录。您应该遵循BLOB usage guidelines并使用.write方法进行分组更新:

UPDATE table
SET blob.Write(@chunk, NULL, NULL)
WHERE key = @key;

这将最低限度地记录更新(如果可能,请参阅Operations That Can Be Minimally Logged):

  

UPDATE语句已完全记录;   但是,部分更新到大   使用.WRITE来估计数据类型   条款记录最少。

不仅记录最少,而且因为更新是BLOB末尾的显式写入,引擎会知道您只更新了BLOB的一部分并且只记录那个。当您使用SET blob=blob+@chunk te引擎更新时,将看到整个BLOB已收到新值,并且不会检测到您实际上只是通过附加新数据来更改BLOB这一事实,因此它将记录整个BLOB(好几次,正如你已经发现的那样。)

顺便说一句,你应该使用大小为8040的块:

  

为获得最佳性能,我们建议您这样做   插入或更新数据   块大小是8040的倍数   字节。

答案 1 :(得分:0)

您可能需要做的是围绕每个“块”或一组块使用它自己的事务并在每个组之后提交。使用您自己的ADO事务围绕整个事务基本上与隐式事务执行相同的操作,因此这将无济于事。您必须提交较小的块以保持日志更小。