查找两个数据集是否相同,一个在.NET中,一个在SQL Server中

时间:2014-09-03 13:50:08

标签: c# sql-server-2012

我必须找到两个数据集是否相同而不使用主键,只有数据。

如果存在,我必须返回主键,否则我必须插入新行并返回新主键

不是单独比较每个字段,因为我觉得这可能很慢????,我提出了这个解决方案

(我将以地址为例)

在SQL Server端,persisted computed column上有index;

-- nice new function in 2012; concat
hashbytes('SHA2_256',
    concat(
        nchar(0x2460),[Address_Type_Id],
        nchar(0x2461),[Street_Name],
        nchar(0x2462),[Municipality],
        nchar(0x2463),[Postal_Zip_Code],
        nchar(0x2464),[Unit],
        nchar(0x2465),[Street_Number],
        nchar(0x2466),[PO_Box],
        nchar(0x2467),[Rural_Route_Number],
        nchar(0x2468),[Street_Type_Id],
        nchar(0x2469),[Country_Type_Id],
        nchar(0x246A),[Country_Division_Type_Id],
        nchar(0x246B),[Country_Division_Other],
        nchar(0x246C),[Direction_Type_Id]
    )
)

在.NET端;

using(var mySHA256 = System.Security.Cryptography.SHA256Managed.Create())
{
    var Value = string.Concat(
            (char)0x2460, PartyAddress.AddressTypeId,
            (char)0x2461, PartyAddress.StreetName,
            (char)0x2462, PartyAddress.Municipality,
            (char)0x2463, PartyAddress.PostalZip,
            (char)0x2464, PartyAddress.Unit,
            (char)0x2465, PartyAddress.StreetNumber,
            (char)0x2466, PartyAddress.POBOX,
            (char)0x2467, PartyAddress.RuralRouteNumber,
            (char)0x2468, PartyAddress.StreetTypeId,
            (char)0x2469, PartyAddress.CountryTypeId,
            (char)0x246A, PartyAddress.CountryDivisionTypeId,
            (char)0x246B, PartyAddress.CountryDivisionOther,
            (char)0x246C, PartyAddress.DirectionTypeId);

    var hashValue = mySHA256.ComputeHash(Encoding.Unicode.GetBytes(Value));
}

之后,我现在可以比较hashValuecomputed column,它确实有效。

我的问题是,在我开始在很多其他表上实现这个之前,我应该看看另一个更好的解决方案吗?

编辑**************

添加另一个解决方案,逐字段比较,因为我使用实体框架就像这样

var addressExist = Tombstone.Addresses
                            .FirstOrDefault(x => 
        x.Address_Type_Id == PartyAddress.AddressTypeId &&
        x.Street_Name == PartyAddress.StreetName &&
        x.Municipality == PartyAddress.Municipality &&
        x.Postal_Zip_Code == PartyAddress.PostalZip &&
        x.Unit == PartyAddress.Unit &&
        x.Street_Number == PartyAddress.StreetNumber &&
        x.PO_Box == PartyAddress.POBOX &&
        x.Rural_Route_Number == PartyAddress.RuralRouteNumber &&
        x.Street_Type_Id == PartyAddress.StreetTypeId &&
        x.Country_Type_Id == PartyAddress.CountryTypeId &&
        x.Country_Division_Type_Id == PartyAddress.CountryDivisionTypeId &&
        x.Country_Division_Other == PartyAddress.CountryDivisionOther &&
        x.Direction_Type_Id == PartyAddress.DirectionTypeId);

生成此查询

SELECT TOP (1) [Extent1].[Address_Id] AS [Address_Id]
    FROM [dbo].[Address] AS [Extent1]
    WHERE ([Extent1].[Address_Type_Id] = @p__linq__0) AND 
          (([Extent1].[Street_Name] = @p__linq__1) OR (([Extent1].[Street_Name] IS NULL) AND (@p__linq__1 IS NULL))) AND 
          (([Extent1].[Municipality] = @p__linq__2) OR (([Extent1].[Municipality] IS NULL) AND (@p__linq__2 IS NULL))) AND 
          (([Extent1].[Postal_Zip_Code] = @p__linq__3) OR (([Extent1].[Postal_Zip_Code] IS NULL) AND (@p__linq__3 IS NULL))) AND 
          (([Extent1].[Unit] = @p__linq__4) OR (([Extent1].[Unit] IS NULL) AND (@p__linq__4 IS NULL))) AND 
          (([Extent1].[Street_Number] = @p__linq__5) OR (([Extent1].[Street_Number] IS NULL) AND (@p__linq__5 IS NULL))) AND 
          (([Extent1].[PO_Box] = @p__linq__6) OR (([Extent1].[PO_Box] IS NULL) AND (@p__linq__6 IS NULL))) AND 
          (([Extent1].[Rural_Route_Number] = @p__linq__7) OR (([Extent1].[Rural_Route_Number] IS NULL) AND (@p__linq__7 IS NULL))) AND
          (([Extent1].[Street_Type_Id] = @p__linq__8) OR (([Extent1].[Street_Type_Id] IS NULL) AND (@p__linq__8 IS NULL))) AND 
          (([Extent1].[Country_Type_Id] = @p__linq__9) OR (([Extent1].[Country_Type_Id] IS NULL) AND (@p__linq__9 IS NULL))) AND 
          (([Extent1].[Country_Division_Type_Id] = @p__linq__10) OR (([Extent1].[Country_Division_Type_Id] IS NULL) AND (@p__linq__10 IS NULL))) AND 
          (([Extent1].[Country_Division_Other] = @p__linq__11) OR (([Extent1].[Country_Division_Other] IS NULL) AND (@p__linq__11 IS NULL))) AND 
          (([Extent1].[Direction_Type_Id] = @p__linq__12) OR (([Extent1].[Direction_Type_Id] IS NULL) AND (@p__linq__12 IS NULL)))

2 个答案:

答案 0 :(得分:2)

如果您认为比较每个字段的速度会很慢,请考虑您的替代解决方案:

  • 取每个字段并追加一个字符
  • 将每个字段与另一个字段连接起来,重复此过程n次(字段中没有字段)
  • 计算SHA256哈希

所以你只做了2n次操作2 x(2n + 2n + hash(n))。另外,你创建了很多字符串,每个字符串都增加了CPU周期和内存(字符串在.Net中是不可变的)。

你可以清楚地看到哪一个会变慢。

更新

  • 由于散列是经过计算和持久化的,因此您不会产生2n的开销,只需要在.Net端进行处理。
  • StringBuilder并没有神奇地为您带来任何节省,特别是对于如此少的操作。
  • 话虽如此,如果您在SQL Server上索引哈希值,哈希可能会更快。由于您需要通用解决方案,因此散列与访问所有这些列的性能差异可能会有所不同。我建议在最糟糕的情况下运行一些基准,以确定哪一个表现更好。
  • 关于附加字符的一个警告 - 您现在正在修改数据。如果你可以保证你附加的字符永远不会出现在实际数据中,那你很好。否则,你自己就会引发碰撞的可能性。
  • 另一个想法是你可以排除比较NULL值,因为你已经知道它们是相同的。

答案 1 :(得分:0)

如果我不必自动执行此操作(即您只是偶尔执行此操作,并且手动比较已经足够),那么我会考虑使用专门的SQL数据库比较工具。然后我将.NET DataTable加载到临时SQL Server数据库中,将它们命名为与它们相对应的SQL Server表,并使该工具将临时DB与实际DB进行比较。

除此之外,计算每行的校验和似乎是一种明智的方法。

(替代方案:并非我发现以下想法是一种好方法,而且我从未测试过;但从理论上讲,您还可以在所有表​​格列中定义UNIQUE约束,然后尝试将DataRow的{​​{1}}的每个数据插入其中。如果DataTable成功,则SQL Server表没有该记录,即您的两个表不相同。如果唯一约束使每个INSERT失败,并且INSERT和SQL Server表具有完全相同的行数,则它们只是相同的。)