0

我正在使用 Oracle 11.2g 实例。我想通过自己生成主键值将行插入表中来了解我所暴露的内容。我会从某些表中选择 max(pk);然后将接下来的一百个值用于我接下来的 100 个插入。是在玩火吗?

上下文是:我有大量的插入要做,它们被分成几个由外键链接的表。我试图获得良好的性能,而不是使用 PL/SQL。

[编辑]这里的代码示例看起来像我正在处理的:

QString query1 = "INSERT INTO table 1 (pk1_id, val) VALUES (pk1_seq.nextval, ?)"
sqlQuery->prepare(query);
sqlQuery->addBindValue(vec_of_values);
sqlQuery->execBatch();

QString query2 = "INSERT INTO table 2 (pk2_id, another_val, pk1_pk1_id) VALUES    (pk2_seq.nextval, ?, ?)"
sqlQuery->prepare(query);
sqlQuery->addBindValue(vec_of_values);

// How do I get the primary keys (hundreds of them)
// from the first insert??
sqlQuery->addBindValue(vec_of_pk1);
sqlQuery->execBatch();
4

2 回答 2

0

您将自己暴露在性能下降、逻辑错误和需要维护的额外代码中。Oracle 序列针对您的特定目的进行了优化。对于高 DML 操作,您还可以缓存序列:

ALTER SEQUENCE customers_seq CACHE 100;
于 2012-08-07T20:20:10.907 回答
0

为主表创建序列使用插入到
主表中your_sequence.nextval
插入子(从属)表使用完成your_sequence.currval

create table parent (id integer primary key not null);
create table child (id integer primary key not null, pid integer not null references parent(id));
create sequence parent_seq;
create sequence child_seq;

insert into parent (id) values (parent_seq.nextval);
insert into child (id, pid) values (child_seq.nextval, parent_seq.currval);
commit;

要解释为什么 max(id) 不能可靠地工作,请考虑以下场景:

  1. 事务 1 检索 max(id) + 1(产量,例如 42)
  2. 事务 1 插入一个 id = 42 的新行
  3. 事务 2 检索 max(id) + 1(也产生 42,因为事务 1 尚未提交)
  4. 事务 1 提交
  5. Transcation 2 插入一个 id = 42 的新行
  6. 事务 2 尝试提交并获得唯一的密钥违规

现在想想当你有很多事务这样做时会发生什么。你会得到很多错误。此外,您的插入会越来越慢,因为计算 max(id) 的成本会随着表的大小而增加。

序列解决这个问题的唯一合理(即正确、快速和可扩展)的方法。

编辑

如果您对另一个无法应对这种策略的 ORM 感到震惊(现在几乎所有 DBMS 都支持这种策略 - 甚至 SQL Server 现在也有序列),那么您应该能够在您的客户端代码中执行以下操作:

使用编程语言中的变量检索下一个 PK 值select parent_seq.nextval from dual(这是检索 PK 值的快速、可扩展且正确的方法)。

如果你可以运行 aselect max(id)你也可以运行一个select parent_seq.nextval from dual. 在这两种情况下,只需使用从该 select 语句获得的值。

于 2012-08-07T21:35:05.740 回答