关于java:哪个更好:查询数据库两次或创建一个查询一次的函数

Which is better: Query database twice or create a function to query once

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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:首先尝试插入数据库,执行以下操作。接下来查询数据库因为插入失败。我有理由首先进行插入,这不是这个问题的重点。我知道大多数人会先说询问是否存在插入。

1
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;

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

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

可以使用preparedStatement(上面的函数)在java中创建一个函数
ResultSet rs = ps.executeUpdate();


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


像往常一样,"它取决于"。

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

基准,不要猜。

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

  • Tx 1 INSERT ... WHERE
  • Tx 2 INSERT ... WHERE
  • Tx 1的WHERE条件运行子查询并找不到行
  • Tx 2的WHERE条件运行子查询并且找不到行
  • Tx 1 INSERT s行
  • Tx 2 INSERT s行
  • Tx 1 COMMIT s并返回ID
    1 Tx 2 COMMIT s并返回ID
  • 如果您对业务键具有UNIQUE约束(即:不是使用生成的主键或者还有约束),则第二个INSERT将失败并显示错误。如果不这样做,您将获得该行的两个副本。

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

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

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

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

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