Oracle:max(id)+1和sequence.nextval之间的区别

时间:2013-06-20 10:04:31

标签: oracle sequence

我正在使用Oracle

使用ID创建max(id)+1并使用sequance.nexval,在哪里使用以及何时使用时,有什么区别?

像:

insert into student (id,name) values (select max(id)+1 from student, 'abc');

insert into student (id,name) values (SQ_STUDENT.nextval, 'abc');

SQ_STUDENT.nextval有时会出现重复记录的错误......

请帮我解决这个疑问

4 个答案:

答案 0 :(得分:33)

使用select max(id) + 1方法,同时插入的两个会话将从表中看到相同的当前最大ID,并且两者都插入相同的新ID值。安全使用它的唯一方法是在启动事务之前锁定表,这很麻烦并且序列化事务。 (正如Stijn指出的那样,如果删除最高记录,则可以重复使用值)。基本上,永远不要使用这种方法。 (可能偶尔有一个令人信服的理由这样做,但我不确定我是否见过一个)。

sequence guarantees that the two sessions will get different values,不需要序列化。它性能更好,更安全,更容易编码,更易于维护。

使用序列可以获得重复错误的唯一方法是,如果表中已存在ID高于序列值的记录,或者某些内容仍未插入记录而未使用该序列。因此,如果您有一个手动输入ID的现有表,例如1到10,并且您创建了一个默认开始值为1的序列,则使用该序列的第一个插入将尝试插入ID为1 - 已存在。在尝试了10次之后,序列会给你11次,这将起作用。如果您随后使用max-ID方法执行下一次使用12的插入,但序列仍然在11上,并且下次调用nextval时也会给出12。

序列和表格无关。如果将手动生成的ID值插入表中,则序列不会自动更新,因此这两种方法不会混合。 (除此之外,相同的序列可用于为多个表生成ID,如文档中所述)。

如果您要从手动方法更改为序列方法,则需要确保使用高于表中所有现有ID的start-with值创建序列,并确保执行插入操作的所有内容仅在将来使用序列。

答案 1 :(得分:10)

如果您打算拥有多个用户,则使用序列。使用max不会。

如果您执行max(id) + 1并允许多个用户,则同时运行的多个会话将定期查看相同的max,从而生成相同的新密钥。假设您已正确配置了约束,则会产生您必须处理的错误。您可以通过重试INSERT来处理它,如果其他会话在您的会话重试之前阻止了您,那么可能会一次又一次失败,但是每个INSERT操作会有很多额外的代码。< / p>

它还会序列化您的代码。如果我在会话中插入一个新行并在我记得提交之前去吃午餐(或者我的客户端应用程序在我提交之前崩溃),那么在我回来并提交或者提交之前,将禁止每个其他用户插入新行DBA终止我的会话,强制重启。

答案 2 :(得分:4)

要添加其他答案,还有几个问题。

如果表中没有行,则max(id)+1语法也会失败,因此请使用:

Coalesce(Max(id),0) + 1

如果您只有一个插入到表中的进程,就像数据仓库加载的情况一样,并且如果max(id)很快(可能是这样),那么这种技术没有任何问题。

例如,如果要将数据恢复到测试系统,它还可以避免代码在表和序列之间同步值。

您可以使用以下方法将此方法扩展为多行插入:

Coalesce(max(id),0) + rownum

我希望可能会将并行插入序列化。

某些技术不适用于这些方法。他们当然依赖于能够发出select语句,因此可能会排除SQL * Loader。但是,SQL * Loader通常通过列规范的SEQUENCE参数支持此技术:http://docs.oracle.com/cd/E11882_01/server.112/e22490/ldr_field_list.htm#i1008234

答案 3 :(得分:0)

假设MAX(ID)实际上足够快,那么就不可能:

  
      
  • 首先获得MAX(ID)+1
  •   
  • 然后获得NEXTVAL
  •   
  • 比较这两者并在NEXTVAL小于MAX(ID)+1
  • 的情况下增加序列   
  • 在INSERT语句中使用NEXTVAL
  •   

在这种情况下,我会有一个完全稳定的程序,也可以允许手动插入,而不必担心更新序列