【问题标题】:SQL Oracle, inserting into tables without sequenceSQL Oracle,无序插入表
【发布时间】:2012-08-07 20:09:28
【问题描述】:

我正在使用 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();

【问题讨论】:

  • 如果你只从一个会话中插入,这不是玩火,但它很多慢。创建一个具有大缓存的序列并使用它。
  • 使用max(pk) 不会扩展,会很慢,最糟糕的是:如果不止一个会话这样做,如果这样做就不正确。 Tom Kyte 关于创建自己的 PK 值的主题说:“您可以使其正确,快速可扩展”(这意味着你只能实现其中一个目标,而不是三个目标)
  • 如果第一个 INSERT 只创建一行,为什么会有“数百个 PK”?
  • 它不是在创建单行......一次调用数百行。
  • 那我不明白你使用的那种语言...我只看到一个 INSERT

标签: sql


【解决方案1】:

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

ALTER SEQUENCE customers_seq CACHE 100;

【讨论】:

  • 我明白了。但是在实践中我该如何进行,我在第一个表中进行插入(键是由序列生成的),然后我想在第二个表中进行插入,我需要第一个插入中的键,但是怎么做我明白了吗?我应该如何有效地做到这一点?
  • @v3h3mental:插入外键引用时只需使用customers_seq.currval
【解决方案2】:

为主表创建序列
使用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. 事务 2 插入一个 id = 42 的新行
  6. 事务 2 尝试提交并获得唯一密钥违规

现在想一想当您有 很多 交易执行此操作时会发生什么。你会得到很多的错误。此外,您的插入会越来越慢,因为计算 max(id) 的成本会随着表的大小而增加。

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

编辑

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

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

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

【讨论】:

  • 我可以在这样的一个小例子中解决它。问题是我认为我受到我使用的库(QtSql)的限制。我对第一组插入使用批处理查询,对第二组使用批处理查询,我不确定我是否理解如何应用您描述的方案。 (每个 exec() 只允许一个 SQL 语句)....
  • @v3h3mental:查看我的编辑。如果你只允许一个语句,你如何得到max(id)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-12
  • 2015-04-15
  • 2014-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多