如何在 C# 中比较 SQL Server CDC LSN 值?

Sim*_*hes 3 c# change-data-capture sql-server-2008

在 SQL 中,它很简单,因为它支持二进制 (10) LSN 值进行比较:

SELECT *, __$start_lsn, __$seqval
FROM cdc.fn_cdc_get_all_changes_dbo_sometable(@startLsn, @endLsn, 'all update old') 
WHERE __$seqval > @seqval 
ORDER BY __$start_lsn, __$seqval
Run Code Online (Sandbox Code Playgroud)

在 C# 中则更困难:

byte[] mySeqval = ...
foreach(var row in cdcData)
{
    if(row.seqval > mySeqval) // Cannot perform this
        ...
}
Run Code Online (Sandbox Code Playgroud)

LSN / SeqVal 值可以转换为可以轻松比较的数字吗?它们的大小为 10 字节(80 位)。

我的项目是.Net 3.5

pie*_*rs7 5

当我过去几周查看时,我很惊讶没有在任何地方找到这个问题的半体面的答案。

LSN 的主要问题是它们是 10 个字节,因此不能简单地转换Int64和比较它们(旁白:你真的会生成那么多 LSN 吗?! Int64真的很大)。正如OP发现的那样,逐一比较字节有点痛苦/容易出错(比较相等性很好 - 比较大于/小于则更好)。然而,从 .Net Framework 4 开始,我们有了这个BigInteger类,它可以用来轻松比较超过 8 字节的整数。

所以问题只是如何将 varbinary(10) 从 LSN 转换为 BigInteger。从检查[1]看来,SQL 以大端格式存储 LSN,因此您必须:

  • 进入varbinary(10)内存。LinqToSql 会给你Binary,其他提供者将直接映射到 byte[]。
  • 如果您使用的是小端架构(提示:您是),则翻转字节。IEnumerable.Reverse().ToArray()如果您不想自己进行反向循环,则会这样做
  • 称呼new BigInteger(bytes)
  • 闲暇时比较数值

这可能看起来像这样:

// https://gist.github.com/piers7/91141f39715a2ec133e5
// Example of how to interpret SQL server CDC LSNs in C# / .Net
// This is required when polling a server for updates in order to determine
// if a previously stored LSN is still valid (ie > min LSN available)

// Requires .Net 4 (or equivilent BigInteger implementation)
// Sample is a Linqpad script, but you get the idea

// NB: That SQL uses big-endian representation for it's LSNs is not
// (as best I know) something they guarantee not to change

Connection.Open();
var command = Connection.CreateCommand();
command.CommandText = @"select sys.fn_cdc_get_max_lsn() as maxLsn";
var bytes = (byte[])command.ExecuteScalar();

// dump bytes as hex
var hexString = string.Join(" ", bytes.Select(b => b.ToString("X2")))
    .Dump("Hex String");

if(BitConverter.IsLittleEndian)
    bytes = bytes.Reverse().ToArray();

var bigInt = new BigInteger(bytes)
    // dump Integer representation
    .Dump("Big Integer")
;
Run Code Online (Sandbox Code Playgroud)

[1] 我进行了连续的更改,并查看了 LSN。最后一个字节明显递增,因此是大端字节序。