1

所以我最近开始使用 postgres。而且由于我无法执行“IF else”,除非在一个函数中我很好奇哪个是更好的资源明智和性能明智。1. 创建如下函数来查询存储id的数据库。检查 id 是否为 null,如果它是插入则返回 id;

CREATE OR REPLACE FUNCTION getallfoo() RETURN INT AS
$BODY$
DECLARE
id INTEGER := (SELECT id FROM foo where (lots of condition checks 15+);
BEGIN
IF id is null then
   INSERT INTO foo(a,b,c,d,e,f) SELECT (1,2,3,4,5,6) RETURNING id INTO id;
   return id;
ELSE 
  RETURN id;
END IF;
END;
$BODY$
Language 'plpgsql';
select * from getallfoo();

或 2:首先尝试插入数据库,执行如下操作。假设插入失败,然后查询数据库。我有理由先进行插入,这不是这个问题的重点。我知道大多数人会说先查询,然后如果不存在插入。

INSERT INTO foo (a,b,c,d,e,f, ........, 15+) SELECT (1,2,3,4,5,6, ........., 15+) 
WHERE NOT EXIST(SELECT 1 from foo where a=1, b=2, c=3, up to 15);

因为我在java中工作,所以我会检查 rs.getGeneratedKeys() = 0; 如果插入失败,我将重新查询数据库以获取 id;

SELECT id from foo where a=1, b=2, c=3, ect;

所以问题是因为我在查询中的条件检查很长,创建一个函数并查询一次数据库是否更好。或者只是跳过该功能并查询两次。我在大约 50 个不同的表上进行这些类型的插入。

附带的问题是你可以使用preparedStatement(上述函数)ResultSet rs = ps.executeUpdate()在java中创建一个函数吗?

4

2 回答 2

2

对于相同的数据多次访问数据库是不可取的,因为它会降低应用程序的性能。因此,如果您可以在单个函数中执行任务而不是多次查询 DB,那么您应该使用 function.

于 2013-07-03T18:22:12.250 回答
0

像往常一样,“这取决于”。

如果您与数据库的连接是低延迟的(例如本地主机),那么触发 PL/PgSQL 过程的开销将变得非常重要,并且启动单独的查询可能会更快。

基准,不要猜测。

在这种情况下,我怀疑在 PL/PgSQL 中这样做会赢,但不仅仅是出于性能原因。您的代码受几个竞争条件的约束。如果两个人同时运行“getallfoo()”会发生什么?

  1. Tx 1 确实INSERT ... WHERE
  2. Tx 2 确实INSERT ... WHERE
  3. Tx 1 的WHERE条件运行子查询并没有找到任何行
  4. Tx 2 的WHERE条件运行子查询并没有找到任何行
  5. Tx 1 INSERTs 行
  6. Tx 2 INSERTs 行
  7. Tx 1 COMMITs 并返回 ID 1 Tx 2 COMMITs 并返回 ID

如果您对业务键有UNIQUE约束(即:不使用生成的主键或也有约束),第二个INSERT将失败并出现错误。如果不这样做,您将获得该行的两个副本。

把事情放在一个程序中没有帮助。甚至没有一条语句在执行中是原子的。不相关的子查询在外部查询之前运行,等等。MVCC 可见性规则通常意味着您不会注意到或关心这一点,但在这种情况下,它们只是意味着您的竞争条件暴露范围更广。

要正确处理这个问题,您需要一个重试循环,就像在文档中密切相关的 PL/PgSQL 的 upsert 示例中找到的那样。您可以在应用程序或过程中执行此操作,但在过程中执行此操作应该会显着缩小竞争条件窗口。

因为您想一次执行多个键,所以处理起来要复杂得多。您可以进行比赛,其中一个转换试图选择/插入1 2 3 4 5而另一个想要4 5 6 7 8。第一个 tx 将成功插入12然后3...然后发现另一个 tx 已经插入4并在收到重复键错误时回滚整个更改。它不会看到4已经插入,因为第二个 tx 还没有提交并且该行将不可见。

我建议一次做一个键,或者有一个外部过程,使用一个执行错误处理和重试循环的子过程一个接一个地插入每个键。

听起来很复杂?是的。PostgreSQL 真的可以使用一些内置的 SQL 扩展来帮助解决这个问题。

于 2013-07-11T01:27:59.820 回答