在使用 efcore 插入 PostgreSQL 数据库时尝试避免 UNIQUE 违规,还是捕获由此产生的异常会更快?

Is it faster to try and avoid UNIQUE violations when inserting into a PostgreSQL database with efcore, or to catch the resulting exception?

假设我对我的 postgresql 数据库中的列有 UNIQUE 约束,在尝试插入新值之前查询数据库是否更高效,或者当数据库拒绝查询时捕获抛出的异常是否可以接受?

我的假设是 postgres 将比 EF 核心构造和执行查询 + 然后 运行 插入更快地检查这些违规。是这样吗?

try
{
    // _dctx is my DbContext
    _dctx.SomeTable.Add(newEntity);
    await _dctx.SaveChangesAsync();
}
catch (DbUpdateException ex)
{
    if (ex.InnerException is PostgresException npgex && npgex.SqlState == PostgresErrorCodes.UniqueViolation)
    {
        // Reached only when the UNIQUE constraint was violated
    }
    throw; // How other exceptions are handled isn't relevant to the question
}

try
{
    if (await _dctx.SomeTable.AnyAsync(x => x.UniqueProperty == hopefullyUniquePropertyValue))
    {
        // Handle duplicate insertion here
    }
    _dctx.SomeTable.Add(newEntity);
    await _dctx.SaveChangesAsync();
}
catch (DbUpdateException ex) {}

由于这将同时/在该服务的多个实例中完成,我仍然希望偶尔会遇到这些异常,但问题是 AnyAsync() 调用的开销是否会大幅增加大于让数据库+ORM来搞定?

在插入之前检查行是否存在绝对是更糟糕的选择,原因有两个:

  • 您正在执行两个 SQL 命令:一个查询检查行是否存在,另一个查询插入一个新行。这意味着两次网络往返,在数据库中执行两个命令......这比单个插入要重得多。
  • 数据库可能在您的检查和插入之间发生了变化,因此您在任何情况下都可能会违反唯一约束(您没有在上面的示例中检查)。

但是,与其从理论上讨论性能,不如简单地对这两个选项进行基准测试(使用 BenchmarkDotNet 之类的东西)总是更好。