Sql 是“选择”吗;“更快”;而不是嵌套插入的函数?

Sql 是“选择”吗;“更快”;而不是嵌套插入的函数?,sql,postgresql,concurrency,upsert,Sql,Postgresql,Concurrency,Upsert,我正在使用一个函数,如果表中不存在行,则将该行插入表中,然后返回该行的id 每当我将函数放入SELECT语句中时,其值在表中尚不存在,例如: 从id=function(123)的表格中选择*; 。。。它返回一个空行。但是,使用相同的值再次运行它将返回包含我希望看到的值的行 为什么会发生这种情况?INSERT是否在SELECT速度后面运行?或者,当表不存在时,PostgreSQL是否缓存该表,并在下次运行时显示结果 下面是一个随时可用的示例,说明了此问题是如何发生的: 创建表(如果不存在)测试表

我正在使用一个函数,如果表中不存在行,则将该行插入表中,然后返回该行的id

每当我将函数放入
SELECT
语句中时,其值在表中尚不存在,例如:

从id=function(123)的表格中选择*;
。。。它返回一个空行。但是,使用相同的值再次运行它将返回包含我希望看到的值的行

为什么会发生这种情况?
INSERT
是否在
SELECT
速度后面运行?或者,当表不存在时,PostgreSQL是否缓存该表,并在下次运行时显示结果

下面是一个随时可用的示例,说明了此问题是如何发生的:

创建表(如果不存在)测试表(
id整数,
t值布尔
);
创建或替换函数测试函数(用户id整数)
返回整数
语言“plpgsql”
作为$$
声明
__用户id整数;
开始
执行格式('SELECT*FROM test_table,其中id=$1')
使用用户id
输入用户id;
如果用户id不为空,则
返回用户id;
其他的
插入测试表(id,tvalue)
值(用户id,TRUE)
返回id
输入用户id;
返回用户id;
如果结束;
结束;
$$;
电话:


若要重现该问题,请传递表中尚不存在的任何整数。

该示例在多个位置被打断

  • 不需要使用
    EXECUTE
    执行动态SQL
  • 在函数中选择*
    是错误的
  • 您的表定义应该在
    (id)
    上具有
    唯一
    主键
    约束
  • 最重要的是,最后的
    SELECT
    语句肯定会失败。由于(必须是),因此对表中的每个现有行计算一次。即使这样做有效,也将是一场性能噩梦。但事实并非如此。与@user2864740一样,可见性也存在问题。Postgres根据函数的结果检查每个现有行,该函数依次添加1行或多行,而这些行还不在
    SELECT
    操作的快照中

    从test_表中选择*,其中id=test_函数(4)

这是可行的(但请参见下文!):

并将您的
选择
替换为:

SELECT * FROM test_function(1);
小提琴

相关的:

对于并发调用,仍然存在竞争条件。如果可能发生这种情况,请考虑:


这不是“速度”,听起来像是事务可见性。考虑一个完整的例子,它也应该显示插入/更新关系。IM试图做一个较小的例子,完整的一个是相当无聊阅读trough@user2864740完成了一个相当简单的例子,我希望它能给你一些背景知识
CREATE TABLE test_table (
  id     int PRIMARY KEY  --!
, tvalue bool
);

CREATE OR REPLACE FUNCTION test_function(_user_id int)
  RETURNS test_table LANGUAGE sql AS
$func$
   WITH ins AS (
      INSERT INTO test_table(id, tvalue)
      VALUES (_user_id, TRUE) 
      ON CONFLICT DO NOTHING
      RETURNING *
      )
   TABLE ins
   UNION ALL
   SELECT * FROM test_table WHERE id = _user_id
   LIMIT 1
$func$;
SELECT * FROM test_function(1);