在INSERT之前检查UNIQUE约束与检查

Ste*_*eam 25 mysql sql sql-server oracle

我有一个SQL服务器表RealEstate与列 - Id,属性,Property_Value.该表有大约5-10百万行,并且将来可以增加更多.我只想在此表中不存在Id,Property,Property_Value的组合时插入行.

示例表 -

1,Rooms,5
1,Bath,2
1,Address,New York
2,Rooms,2
2,Bath,1
2,Address,Miami
Run Code Online (Sandbox Code Playgroud)

2,Address,Miami不应允许插入.但是,2,Price,2billion没关系.我很想知道这是"最好的"方法,为什么这样做.为什么这部分对我来说最重要.两种检查方式是 -

  1. 在应用程序级别 - 应用程序应在插入行之前检查是否存在行.
  2. 在数据库级别 - 在所有3列上设置唯一约束,让数据库执行检查而不是人员/应用程序.

是否有任何一种情况会比另一种更好?

谢谢.

PS:我知道有一个类似的问题,但它没有回答我的问题 - 唯一约束与预检查 另外,我认为UNIQUE适用于所有数据库,所以我认为我不应该删除mysql和oracle标签.

iva*_*tpr 14

我认为在大多数情况下,这两者之间的差异将足够小,以至于选择应该主要通过选择最初对于第一次查看代码的人来说最容易理解的实现来驱动.

但是,我认为异常处理有一些优点:

  • 异常处理可避免潜在的竞争条件.如果另一个进程在您的检查和插入之间插入记录,则"检查,然后插入"方法可能会失败.因此,即使您正在进行'检查然后插入',您仍然需要对插入进行异常处理,如果您已经在进行异常处理,那么您也可以取消初始检查.

  • 如果您的代码不是存储过程并且必须通过网络与数据库交互(即应用程序和数据库不在同一个框中),那么您希望避免两个单独的网络调用(一个用于检查和其他用于插入)并通过异常处理进行处理提供了一种通过单个网络调用处理整个事物的简单方法.现在,有很多方法可以执行"检查然后插入"方法,同时仍然避免第二次网络调用,但只是捕获异常可能是最简单的方法.

另一方面,异常处理需要一个唯一约束(这实际上是一个唯一索引),它具有性能权衡:

  • 在非常大的表上创建唯一约束会很慢,并且会对该表的每个插入产生性能影响.在真正大型的数据库上,您还必须为用于强制执行约束的唯一索引所占用的额外磁盘空间进行预算.
  • 另一方面,如果您的查询可以利用该索引,则可以更快地从表中进行选择.

我还要注意,如果你的实际情况是'更新其他插入'(即如果已经存在具有唯一值的记录,那么你想要更新该记录,否则你插入一个新的记录)然后你真正想要使用的是你的特定数据库的UPSERT方法,如果有的话.对于SQL Server和Oracle,这将是一个MERGE语句.

  • 我不认为这些差异是"小"的.差别很大:除非您对表执行完全独占*write*锁定,否则您无法保证应用程序的唯一性,这意味着应用程序内部的解决方案要么不可扩展,要么根本无法正常工作.两者都不是很好的选择. (3认同)

Ben*_*Ben 6

取决于#1(进行查找)合理的成本,我会做两件事.至少,在Oracle中,这是我最熟悉的数据库.

理由:

  • 唯一/主键应该是数据模型设计的核心部分,我看不出任何不实现它们的理由 - 如果您有太多数据导致性能受到维护唯一索引的影响:
    • 这是很多数据
    • 对其进行分区或将其存档远离OLTP工作
  • 您拥有的约束越多,数据对应用程序逻辑错误的安全性就越高.
  • 如果您首先检查是否存在行,则可以轻松地从该行中提取其他信息以用作错误消息的一部分,或者以其他方式分叉应用程序逻辑以应对重复.
  • 在Oracle中,回滚DML语句相对昂贵,因为Oracle希望COMMIT默认情况下成功(即已编写的更改).