SQL MIN_ACTIVE_ROWVERSION() 函数的值长时间不变

16
We're troubleshooting a Sync Framework issue between two separate SQL Server databases, both running SQL Server 2008 Enterprise 64-bit SP2 - 10.0.4000.0. The databases are connected through linked server connections. However, we've encountered a problem and are currently stuck.
To identify records that need to be synced, we use the logic based on ROWVERSION values, which includes using MIN_ACTIVE_ROWVERSION() to avoid dirty reads. All SELECT operations are encapsulated in stored procedures on each source side. Here's a sample schematic of one stored procedure:
    PROCEDURE LoaderRetrieve(@LastStamp bigint, @Rows int)
    BEGIN
    ...
    (vars handling)
    ...

    SET TRANSACTION ISOLATION LEVEL SNAPSHOT

    Select TOP (@Rows) Field1, Field2, Field3
    FROM Table
    WHERE [RowVersion] > @LastStampAsRowVersionDataType    
    AND [RowVersion] < @MinActiveVersion  
    Order by [RowVersion] 

    END

这种方法效果很好,我们通常以每小时600k的预期速率同步记录(每30秒执行一次作业,批量大小为5k),但在某些时候,同步过程找不到任何单个记录需要传输,尽管有几千条记录的ROWVERSION值大于@LastStamp参数。
在检查原因时,我们发现MIN_ACTIVE_ROWVERSION()的值小于(或略大,只有5或10增量)正在搜索的@LastStamp。当然,这不应该是问题,因为引入MIN_ACTIVE_ROWVERSION()方法是为了避免脏读和后续问题,但是:
在上述情况发生时,我们有时会看到的问题是,MIN_ACTIVE_ROWVERSION()的值在长时间(真的很长)的时间内没有改变,如30/40分钟,有时甚至超过一小时。而且,这个值远远小于@@DBTS的值。
我们最初认为这与未提交的数据库事务有关。根据MSDN关于MIN_ACTIVE_ROWVERSION()(link)的定义:

返回当前数据库中最低的活动rowversion值。如果rowversion值在尚未提交的事务中使用,则该值是活动的。

但是,在检查持续时间期间具有open_tran > 0的会话(sys.sysprocesses)时,我们无法找到任何等待时间大于几秒钟的会话,只有一两个时间为+/- 5分钟的等待时间会话。 因此,我们现在正在努力理解情况:在很长一段时间内,MIN_ACTIVE_ROWVERSION()没有改变,并且在这个时间范围内没有发现长时间等待的未提交事务。 我不是DBA,可能我们缺少分析此问题的全貌,但在论坛和博客上进行了一些研究,没有找到其他线索。目前,open_tran > 0 是有效的原因,但根据我所提供的情况,很明显还有其他原因,但我不知道是什么。欢迎提供任何反馈。

3
感谢您提供如此精彩的问题,给您点赞。建议您将解决方案添加为答案而不是问题的一部分。 - Kermit
6
即使是您提供的解决方案,也应该发布为答案。请随意将那部分发布为答案。如果没有其他更好的答案,那么请接受它。 - ypercubeᵀᴹ
1个回答

7

好的,我在深入探究后终于找到了解决方案。

问题在于我们一直在寻找等待时间长的会话,但实际上应该寻找有活动批处理的会话。

如果存在 open_tran = 1 的会话,则需要检查 sys.sysprocesses 中的 last_batch 字段,以获取此事务开启的确切时间(当然还要检查是否仍处于活动状态,尚未提交)。

使用以下查询:

    select 
    batchDurationMin= DATEDIFF(second,last_batch,getutcdate())/60.0,
    batchDurationSecs= DATEDIFF(second,last_batch,getutcdate()),
    hostname,open_tran,* from sys.sysprocesses a
    where spid > 50
    and a.open_tran >0  
    order by last_batch asc

我们可以通过开启的tran活动时间超过30分钟来识别一个会话。通过主机名值和在Web服务内进行一些更多的检查(并且还使用dbcc inputbuffer),我们找到了负责的进程。
因此,最终的问题实际上是"确实存在一个未提交事务的活动会话",因此MIN_ACTIVE_ROWVERSION()不会改变。我们只是使用了错误的标准来寻找进程。
现在我们知道哪个进程行为如此,下一步将是对其进行改进。
希望这个结果对其他人有用。

我已确认:MIN_ACTIVE_ROWVERSION()在该版本启动的第一笔交易完成之前不会增加。 - Sal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接