如何在 C# 中比较 SQL Server CDC LSN 值?
在 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
在 C# 中,它更困难:
byte[] mySeqval = ...
foreach(var row in cdcData)
{
if(row.seqval > mySeqval) // Cannot perform this
...
}
LSN / SeqVal 值可以转换为可以轻松比较的数字吗? 它们的大小为 10 字节(80 位)。
我的项目是.Net 3.5
In SQL its easy as it supports the binary(10) LSN values for comparison:
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
In C# it's more difficult:
byte[] mySeqval = ...
foreach(var row in cdcData)
{
if(row.seqval > mySeqval) // Cannot perform this
...
}
Can the LSN / SeqVal values be converted into a number than can be compared easily?
These are 10 bytes (80 bits) in size.
My project is in .Net 3.5
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
当我过去几周查看时,我很惊讶没有在任何地方找到这个问题的半体面的答案。
LSN 的主要问题是它们是 10 个字节,因此不能简单地将它们转换为
Int64
并进行比较(旁白:你真的会生成那么多 LSN 吗?!Int64
真的很大)。正如OP发现的那样,逐一比较字节有点痛苦/容易出错(比较相等性很好 - 比较大于/小于则更好)。然而,从 .Net Framework 4 开始,我们有了 BigInteger 类,它可以用来轻松比较超过 8 字节的整数。所以问题只是如何将 varbinary(10) 从 LSN 转换为 BigInteger。从检查[1]来看,SQL似乎以big-endian格式存储LSN,因此您必须:
varbinary(10)
放入内存中。 LinqToSql 将为您提供Binary
,其他提供程序将直接映射到 byte[]。IEnumerable.Reverse().ToArray()
会执行此操作,new BigInteger(bytes)
这可能看起来像这样:
[1] 我进行了连续的更改,并查看了 LSN。最后一个字节明显递增,因此是大端字节序。
I was surprised not to find a half-decent answer to this problem anywhere when I looked over the last few weeks.
The main problem with LSNs is that they are 10 bytes, so they can't simply be converted to
Int64
and compared (aside: will you really generate that many LSNs?!Int64
is really big). And as the OP discovered, comparing the bytes one-by-one is a bit painful/error prone (comparing for equality is fine - comparing for greater-than/less-than less so). However, as of .Net Framework 4 we have theBigInteger
class, which can be used to easily compare integers exceeding 8 bytes.So the problem is just how to get the varbinary(10) from a LSN into a BigInteger. From inspection[1] it appears that SQL stores the LSN in big-endian format, so you have to:
varbinary(10)
into memory. LinqToSql will give youBinary
, other providers will map to byte[] directly.IEnumerable.Reverse().ToArray()
will do that if you don't want to do a reverse-loop yourselfnew BigInteger(bytes)
This might look something like this:
[1] I made sequential changes, and looked at the LSNs. The last byte was clearly incrementing, hence big-endian.
目前正在调查 http://intx.codeplex.com/ 作为其 .Net 2.0
Currently investigating http://intx.codeplex.com/ as its .Net 2.0
最后写了我自己的LSN比较器:
Wrote my own LSN comparer in the end:
最终不需要使用以上任何一个。只有我的同事最终解决了这个问题(感谢托尼·布罗迪)。这样做的方法是与 seqval 进行比较,然后取+1。简单。
Didn't need to use any of the above in the end. Ony of my collegues solved the problem in the end (Thanks Tony Broodie). The way to do this was to compare to seqval, then take+1. Simples.
受到 @casperOne 的固定长度解决方案的启发,我创建了一个扩展方法允许您像这样按字节数组排序:
这是扩展方法:
Inspired by @casperOne's fixed length solution here https://stackoverflow.com/a/10658931/8478013 I created an extension method that allows you to order by byte array like this:
here's the extension method: