如何有效地避免重复密钥异常

本文关键字:密钥 异常 有效地 | 更新日期: 2023-09-27 18:27:16

我面临以下问题:

我正试图使sql server中的一个表与多个外部数据库同步。这些外部数据库没有共享的唯一主键,因此本地表有一个简单的整数PK

现在,为了使本地表保持最新,完成了以下操作:

  1. 将查询外部数据库
  2. 数据被转换为本地表的有效数据
  3. 插入用于尝试将数据写入本地表
  4. 如果insert返回重复条目异常,则选择查询将搜索PK,更新查询将数据写入表
  5. 使用插入或更新的行的PK修改另一个表

现在这很好用,但在我看来效率很低。大多数情况下,数据已经在本地表中,并导致插入时出现重复键异常。这意味着需要处理大量异常,这是非常昂贵的。此外,由于PK由DB管理,必须使用选择查询来查找要更新的行。

如何避免这种影响?我不想使用存储过程,因为我喜欢让查询由代码管理并包含在版本控制中。

我看过合并,但我看到太多人报告它的问题。

我想我需要使用一种追加销售的形式,但我不确定如何在DB管理PK的情况下做到这一点。

tl;dr:我需要的是一个查询,它将允许我插入或更新一行(取决于是否重复密钥),该行将始终返回该行的PK。

如何有效地避免重复密钥异常

我有一个我过去喜欢的实现。你可能觉得它有用,也可能不有用。

这就是它的工作原理。。。我使用一个同时适用于外部和本地数据的模型对象将它们加载到内存中。例如

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string PhoneNumber { get; set; }
    public string Address { get; set; }
    // This comparer will be used to find records that exist or don't exist.
    public class KeyFieldComparer : IEqualityComparer<Person>
    {
        public bool Equals(Person p1, Person p2)
        {
            return p1.FirstName == p2.FirstName && p1.LastName == p2.LastName;
        }
        public int GetHashCode(Person p)
        {
            return p.FirstName.GetHashCode() ^ p.LastName.GetHashCode();
        }
    }
    // This comparer will be used to find records that are outdated and need to be updated.
    public class OutdatedComparer : IEqualityComparer<Person>
    {
        public bool Equals(Person p1, Person p2)
        {
            return p1.FirstName == p2.FirstName && p1.LastName == p2.LastName && (p1.PhoneNumber != p2.PhoneNumber || p1.Address != p2.Address);
        }
        public int GetHashCode(Person p)
        {
            return p.FirstName.GetHashCode() ^ p.LastName.GetHashCode();
        }
    }
}

我们需要有一些方法来唯一地识别记录,我想你已经有了。在这个例子中,它由FirstNameLastName组成(我知道这不是很独特,但为了简单起见,让我们假设它工作得很好)。当列表加载到内存中时,IEqualityComparer<>将完成查找过时和新记录的工作。

现在我们只是简单地将现有的过时唱片和全新的唱片分开。。。

List<Person> local = loadLocalRecords();
List<Person> external = loadExternalRecords();
var newRecordsToInsert = external.Except(local, new Person.KeyFieldComparer());
var outdatedRecordsToUpdate = local.Intersect(external, new Person.OutdatedComparer());

我希望这是有道理的。如果你有问题,我可以回答。这种方法的好处是它能以最少的数据库点击量完成任务(我认为)。糟糕的是,它必须将所有内容加载到内存中,这对你来说可能不实用。但是你的桌子必须很大才能成为一个问题。根据列的数量,在几百万条记录之上的某个位置。