INSERT RETURNING 是否保证以“正确”的方式返回内容?命令?

发布于 2024-10-26 16:17:49 字数 389 浏览 6 评论 0 原文

示例:

create table foo(
    id serial, 
    txt text
);

insert into foo(txt) values ('a'),('b'),('c') returning id;

返回:

 id 
----
  1
  2
  3
(3 rows)

似乎返回值中的第一个id将始终是id >'a',第二个 'b' 等等,但是这是 insert into 的定义行为,还是可能会失败的巧合在奇怪的情况下?

Example:

create table foo(
    id serial, 
    txt text
);

insert into foo(txt) values ('a'),('b'),('c') returning id;

Returns:

 id 
----
  1
  2
  3
(3 rows)

It seems that the first id in the return value will always be the id for 'a', the second for 'b' and so on, but is this defined behaviour of insert into, or is it a coincidence that may fail under odd circumstances?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

小霸王臭丫头 2024-11-02 16:17:56

免责声明:答案参考MariaDB 10.5+

与 PostgreSQL 一样,RETURNING 的顺序没有详细记录,所以我运行了一个原始测试用例其中返回的结果集肯定是连续的,并且与批量插入的值元组同步:

CREATE TABLE `returning_order_test_on_dup` (
    `ID` INT(11) NOT NULL AUTO_INCREMENT, 
    `VAL` INT(11) NOT NULL,
    PRIMARY KEY (`ID`), 
    UNIQUE INDEX `VAL` (`VAL`)
);

以下查询生成用于填充测试表的批量插入查询。两个查询均生成 25k 个插入值,第二个查询会偏移数千个值,以确保 ON DUPLICATE KEY UPDATE 正常工作:

SELECT CONCAT('INSERT INTO returning_order_test_on_dup (VAL) VALUES ', GROUP_CONCAT('(', seq, ')'), ' ON DUPLICATE KEY UPDATE VAL = VALUES(VAL) RETURNING *;')
FROM seq_1_to_25000;

SELECT CONCAT('INSERT INTO returning_order_test_on_dup (VAL) VALUES ', GROUP_CONCAT('(', seq, ')'), ' ON DUPLICATE KEY UPDATE VAL = VALUES(VAL) RETURNING *;')
FROM seq_20000_to_45000;

注意seq_ *_to_* 是一个内置序列生成器

为了“安全”,我查看了 INSERT ... RETURNING 实现的测试(PR #1384)并浏览了实现,但找不到任何值元组和 RETURNING 行被期望能够发散。

使用 MariaDB 10.6 进行测试

Disclaimer: Answer refers to MariaDB 10.5+

As with PostgreSQL, the order of RETURNING is not documented in detail, so I ran a primitive test case where the returned result sets were definitely sequential and in sync with the value tuples of the bulk insert:

CREATE TABLE `returning_order_test_on_dup` (
    `ID` INT(11) NOT NULL AUTO_INCREMENT, 
    `VAL` INT(11) NOT NULL,
    PRIMARY KEY (`ID`), 
    UNIQUE INDEX `VAL` (`VAL`)
);

The following queries generate the bulk insert queries used to populate the test table. Both queries generate 25k insert values each, with the second one being offset by a few thousands to make sure that ON DUPLICATE KEY UPDATE does work properly:

SELECT CONCAT('INSERT INTO returning_order_test_on_dup (VAL) VALUES ', GROUP_CONCAT('(', seq, ')'), ' ON DUPLICATE KEY UPDATE VAL = VALUES(VAL) RETURNING *;')
FROM seq_1_to_25000;

SELECT CONCAT('INSERT INTO returning_order_test_on_dup (VAL) VALUES ', GROUP_CONCAT('(', seq, ')'), ' ON DUPLICATE KEY UPDATE VAL = VALUES(VAL) RETURNING *;')
FROM seq_20000_to_45000;

Note: seq_*_to_* is a builtin sequence generator

To be "safe", I looked at the tests of the INSERT ... RETURNING implementation (PR #1384) and glanced over the implementation, and couldn't find a hint anywhere that value tuples and the RETURNING rows are exoected to be able to diverge.

Tested with MariaDB 10.6

吹泡泡o 2024-11-02 16:17:55

虽然文档并不完全清楚,但它确实指出:

如果 INSERT 命令包含 RETURNING 子句,则结果将类似于包含 RETURNING 列表中定义的列和值的 SELECT 语句,并根据该命令插入的行进行计算。

现在“类似于”并不是铁定的保证,我已经 提出这个问题是为了在邮件列表上进行讨论 ...但实际上,PostgreSQL 不会弄乱 RETURNING 中值的顺序。即使我们想要优化,我们也不太可能做到这一点,因为太多的应用程序依赖于它的排序与输入相同。

所以...对于 INSERT INTO ... VALUES (...), (...), ... RETURNING ... 和对于 INSERT INTO ... SELECT .. . ORDER BY ... RETURNING ... 应该可以安全地假设结果关系与输入的顺序相同。

While the documentation isn't entirely clear, it does state that:

If the INSERT command contains a RETURNING clause, the result will be similar to that of a SELECT statement containing the columns and values defined in the RETURNING list, computed over the row(s) inserted by the command.

Now "similar to" isn't an ironclad guarantee, and I've raised this for discussion on the mailing list ... but in practice, PostgreSQL won't mess with the order of values in RETURNING. It's unlikely we'll ever be able to even if we want to for optimisation, because too many apps rely on it being ordered the same as the input.

So... for INSERT INTO ... VALUES (...), (...), ... RETURNING ... and for INSERT INTO ... SELECT ... ORDER BY ... RETURNING ... it should be safe to assume that the result relation is the in the same order as the input.

洋洋洒洒 2024-11-02 16:17:55

我在 文档 中没有看到任何保证 RETURNING 订单的内容 所以我认为你不能依赖它。可能性是 RETURNING 订单将与 VALUES 订单匹配,但我没有看到任何关于 VALUES 将以什么顺序插入的保证; VALUES 几乎肯定会按从左到右的顺序插入,但同样,没有记录在案的保证。

此外,关系模型是基于设置的,因此排序是用户应用的而不是关系的固有属性。一般来说,如果无法显式指定排序,则不存在隐含的排序。

执行摘要:您看到的顺序可能总是会发生,但不能保证,所以不要依赖它。

I don't see anything in the documentation that guarantees an order for RETURNING so I don't think you can depend on it. Odds are that the RETURNING order will match the VALUES order but I don't see any guarantees about what order the VALUES will be inserted in either; the VALUES are almost certainly going to be insert in order from left to right but again, there is no documented guarantee.

Also, the relational model is set based so ordering is something applied by the user rather than an inherent property of a relation. In general, if there is no way to explicitly specify an ordering, there is no implied ordering.

Execute summary: the ordering you're seeing is probably what will always happen but it is not guaranteed so don't depend on it.

若无相欠,怎会相见 2024-11-02 16:17:55

虽然现在这对您没有帮助,但 9.1 将包含 "可写公用表表达式"。这是 WITH 语法的正式名称。 (Wikipedia。)

这项新功能应该可以让您放置INSERT ... RETURNING< /code> 在 WITH 中,给出一个别名,然后使用普通的旧 ORDER BY 子句以特定顺序进行 SELECT 操作。

While this won't help you now, 9.1 will include "writeable common table expressions". That's the official name for the WITH syntax. (Wikipedia.)

This new ability should let you place your INSERT ... RETURNING inside a WITH, give an alias, and then SELECT against that with a specific ordering with a plain old ORDER BY clause.

坦然微笑 2024-11-02 16:17:55

我已经用几千行一遍又一遍地对此进行了基准测试。

它不会按顺序返回值。

在此处输入图像描述

因此,我发现保证正确顺序的最佳方法是在目标表中创建一个临时表和一个临时列与要插入的值数组中的索引,然后通过 PrimaryKey 和数组索引将它们匹配回来,然后将其加载到返回函数中。

I have benchmarked this with a few thousand rows, over and over again.

It does NOT return the values in order.

enter image description here

So the best way I found out to guarantee the right order is to create a temporary table and a temporary column in the destination table with the index from the array of the values that shall be inserted and then match them back by PrimaryKey and Index of array before loading it into your return function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文