1

我们的应用程序需要向 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 执行后关闭连接,但我也尝试过不关闭连接,结果相同

这个方案有什么缺陷?如果您需要更多信息,请告诉我。谢谢!

注意:不能选择使用简单或批量日志恢复模式

4

2 回答 2

3

如果通过“块”,您的意思是:

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

那么您是对的,该操作已完全记录。您应该遵循BLOB 使用指南并使用 .Write 方法进行分块更新:

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

这将最少记录更新(如果可能,请参阅可以最少记录的操作):

UPDATE 语句已完全记录;但是,使用 .WRITE 子句对大值数据类型的部分更新被最小化记录。

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

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

为了获得最佳性能,我们建议以 8040 字节的倍数大小插入或更新数据。

于 2010-01-06T18:31:23.247 回答
0

您可能需要做的是用它自己的事务围绕每个“块”或块组,并在每个组之后提交。用您自己的 ADO 事务围绕整个事物本质上是在做与隐式事务相同的事情,所以这无济于事。您必须以较小的块提交以保持日志更小。

于 2010-01-06T17:05:39.963 回答