数据库 Upserts - 好的还是坏的做法?
Posted
技术标签:
【中文标题】数据库 Upserts - 好的还是坏的做法?【英文标题】:Database Upserts - Good or Bad Practice? 【发布时间】:2011-05-29 07:47:13 【问题描述】:寻找一些关于 Upsert(插入或如果存在,则更新)过程是否被认为是数据库编程中的不良做法的见解。如果有任何相关性,我会在 SQL Server 中工作。
几个月前,在我工作的一个地方,常驻数据库大师在新编写的数据库编码标准(大部分我同意)中指出,应避免使用 Upsert。
我真的看不出这是什么合乎逻辑的原因,并认为我自己合理地意识到了良好的编程实践。我认为它们对于直接的数据管理很有用,并有助于避免过多的存储过程数量。
寻找一些可以帮助我得出结论的见解/讨论。
谢谢。
针对 cmets 的更新:
我所指的具体上下文是在数据库中创建或更新域实体数据表示。例如,一个“Person”对象作为数据库中“Person”表的表示存在。我只需要一种创建新 Person 或更新现有 Person 的机制。在这里,我可以选择创建一个 Upsert 存储过程,或者创建两个单独的存储过程 - 一个用于更新,一个用于插入。
在任何人看来有什么优点或缺点吗?
【问题讨论】:
从 Oracle 的角度来看,请改用 MERGE 语句。 MERGE 也存在于 SQL Server 中(我相信 2005+) 【参考方案1】:取决于你在说什么。数据?嗯,这是由数据操作过程决定的,还是?如果我需要插入或更新,那么我需要这样做。如果是关于模式对象,类似。
【讨论】:
确实如此。很少有方法或实践本身是不好的,上下文和业务逻辑在这里绝对至关重要。 我指的具体上下文是数据库中域实体数据表示的创建或更新。例如,一个“Person”对象作为数据库中“Person”表的表示存在。我只需要一种创建新 Person 或更新现有 Person 的机制。在这里,我可以选择创建一个 Upsert 存储过程,或者两个单独的存储过程 - 一个用于更新,一个用于插入。 我经常有一个带有另一个参数的 upsert 方法,在这种情况下是否真的允许创建(有时我不想要)。【参考方案2】:主要问题是在打算添加新记录时覆盖现有记录,因为选择作为键的任何内容都是重复的。例如,说一个登录名。您看到登录存在,因此您应该在应该退出登录重复的错误时进行更新。
第二个问题是恢复已删除的记录。假设进程“A”查询记录,进程“B”删除它,然后进程“A”提交更改。原本要删除的记录现在又回到了数据库中,而不是将异常传递回“A”,说明它已被删除。
【讨论】:
谢谢,这就是我所追求的——两个很好的例子说明了这种代码会导致问题的地方。【参考方案3】:我喜欢有目的地编程。
要么我正在创建一些东西,在这种情况下,如果那里已经有一个实体,我希望插入失败(重复)。或者,我正在更新我知道存在的东西,在这种情况下,我希望更新失败(实际上不会发生)。
使用 upsert/merge 这有点模糊。我成功了还是没有成功?我部分成功了吗?该行中的一些值是我的(来自插入),其中一些之前存在?
话虽如此,Upsert 很有用(这就是为什么一开始就实施它们的原因),禁止它们只是愚蠢的。这就像禁止道路,因为犯罪分子利用它们来逃避警察。在无数情况下,upsert 是唯一合理的做事方式。任何从事过系统间数据同步的人都知道这一点。
【讨论】:
【参考方案4】:在两个进程的第一个示例中的反对意见——第二个进程通过添加具有相同键的新记录来“恢复”已删除的记录——仅在特定情况下有效,这可能是由于设计不佳或会导致无论“upsert”过程是用相同的键写入记录还是两个单独的过程写入插入的记录,都会发生这种情况。
如果必须避免使用相同的密钥,则在插入时使用自动递增的标识密钥。在不需要避免相同键的情况下,必须实施良好的数据库设计以避免创建“幻像连接”。例如,在电信世界中,电话号码经常被重复使用并且是“唯一”键。它们不能是主键,因为第 2 个人可能“继承”电话号码,但可能不应该“继承”第 1 个人的逾期未付账单或通话记录等。因此,自动递增主键加上服务日期或其他的组合唯一标识符将用于任何连接逻辑,以防止错误的数据链接。
【讨论】:
以上是关于数据库 Upserts - 好的还是坏的做法?的主要内容,如果未能解决你的问题,请参考以下文章
混合 Angular Material 和 Bootstrap。好的做法还是坏的做法?