为啥插入重复主键时 Kudu 不会失败?

Posted

技术标签:

【中文标题】为啥插入重复主键时 Kudu 不会失败?【英文标题】:Why doesn't Kudu fail when inserting duplicate primary key?为什么插入重复主键时 Kudu 不会失败? 【发布时间】:2019-05-31 14:41:48 【问题描述】:

来自 Impala 文档:

在大多数关系数据库中,如果您尝试插入已经插入的行,则插入会失败,因为主键会重复。 然而,Impala 不会使查询失败。相反,它会生成一个警告,但会继续执行插入语句的剩余部分。

为什么 Impala/Kudu 会这样? 请注意,插入不会更新值(有一个 upsert 命令),它只会静默失败。

有没有办法知道我正在插入重复的主键?

【问题讨论】:

我不确定“为什么”,但我不认为这是一个问题。如果您预计重复的唯一主键,则选择新的主键或使用 UPSERT。除此之外,对警告做出反应,以便您可以进行下一步(更改键或切换到 upsert)。 【参考方案1】:

这是因为 kudu 本身不会抛出任何异常(只会引发警告),因此 impala 将(正确地)假设任务成功。

至于Kudu为何选择这样,我们只能猜测了。

这只是我的看法。 Kudu(和 Impala)专为分析工作负载而不是事务工作负载而设计。这通常涉及大量数据的批处理。由于具有重复键的记录数量很少,因此应用程序失败是不可取的。

因此默认行为会插入所有具有非重复键的记录并跳过所有重复键。这可以通过使用 upsert 来更改,它替换替换重复项。

根据Imapala documentation

如果 INSERT 语句尝试插入具有与现有行相同的主键列值的行,则该行将被丢弃并继续插入操作。当由于重复的主键而丢弃行时,语句以警告结束,而不是错误。 (这是 Kudu 早期版本的一个变化,默认情况下在这种情况下返回错误,并且需要语法 INSERT IGNORE 才能使语句成功。IGNORE 子句不再是 INSERT 语法的一部分。)

对于您喜欢用重复的主键值替换行而不是丢弃新数据的情况,您可以使用 UPSERT 语句而不是 INSERT。 UPSERT 插入全新的行,对于与表中现有主键匹配的行,更新非主键列以反映“更新”数据中的值。

如果您确实想要存储新行,而不是替换现有行,但由于主键唯一性约束而无法这样做,请考虑使用包含在主键中的其他列重新创建表。

【讨论】:

他们选择这样做是因为如果一个插入语句有多个值子句(在一个语句中插入多行),Kudu 会在多个线程上处理这些子句。如果其中一个失败了,挑选那些已经完成的并将它们回滚将是他们不想承担的挑战。 (抱歉,我不记得我在哪里读到的了。)

以上是关于为啥插入重复主键时 Kudu 不会失败?的主要内容,如果未能解决你的问题,请参考以下文章

当有外键和主键时获得唯一项目?重复项(具有唯一弱键)?

MS SQL 2008 设置主键 该列值为啥还能重复

为啥mysql PDO不会在失败时抛出错误[重复]

mysql主键对应的值不能重复

为啥 Hashmap 值在使用重复键时被替换,即使它在内部为每个存储桶使用链表? [复制]

使用 T-SQL Merge 语句时如何避免插入重复记录