2013-06-20 19 views
9

我使用的是Oracle甲骨文:MAX(ID)之间的差值+1和sequence.nextval

是什么,当我们使用IDmax(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有时给出了重复记录错误...

请帮我在这无疑

回答

30

随着select max(id) + 1方法,两会同时插入将se e表中的当前最大ID相同,并且都插入相同的新ID值。安全地使用这种方法的唯一方法是在开始事务之前锁定表,这很痛苦并且将事务序列化。 (正如Stijn指出的那样,如果最高记录被删除,值可以重复使用)。基本上,不要使用这种方法。 (可能偶尔有一个令人信服的理由这样做,但我不知道我曾见过一个)。

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

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

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

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

9

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

如果你做了一个max(id) + 1并且你允许多个用户,那么同时运行的多个会话将定期看到相同的max,因此会生成相同的新密钥。假设你正确地配置了你的约束,那会产生一个你必须处理的错误。您将通过重试INSERT来处理它,如果在会话重试之前其他会话阻止您,它可能会一次又一次地失败,但对于每个INSERT操作而言,这是额外的代码。

它也会序列化你的代码。如果我在会话中插入新行并在我记得提交之前去吃午饭(或者我的客户端应用程序在我可以提交之前崩溃),那么每个其他用户都将被阻止插入新行,直到我回来并提交或者DBA杀死我的会话,强制重新启动。

+0

但过一段时间,为什么我得到重复记录错误与sequ​​ence.nextval允许和它的工作原理当我运行与max(id)+1 –

+2

@PriyaPrajapati相同的查询 - 因为您的序列的当前值低于表中的最大ID。如果您在表中手动插入值,则序列不会被修改。您不应该混淆两种方法 - 获取序列,使其高于表格值,然后仅使用序列。 –

+0

@Alex - 感谢您的回复,这可能是错误的原因 –

4

添加到其他答案,几个问题。

你的MAX(ID),如果在已经表中没有行+1语法也会失败,所以使用:

Coalesce(Max(id),0) + 1 

这没有什么错用这种方法,如果你只有一个单一的过程中进行的插入放入表中,数据仓库负载可能就是这种情况,如果max(id)很快(很可能是这样)。例如,如果要将数据恢复到测试系统,它还可以避免代码同步表和序列之间的值所需的代码。

您可以通过使用扩展这种方法多行插入:

Coalesce(max(id),0) + rownum 

我预计可能连载并行插入,虽然。

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

+0

或并行加载... –

+1

添加了一个注释,并扩大了对SQL * Loader的评论。 –

0

假设MAX(ID)实际上是速度不够快,是不是有可能:

  • 首先获得MAX(ID)+1
  • 然后得到NEXTVAL
  • 比较这两个,并增加顺序,以便在NEXTVAL越小则MAX(ID)+1
  • 使用NEXTVAL在INSERT语句

在这种情况下,我想有一个完全稳定程序和手动插入也将无需担心更新序列

+0

你正在引入差距,这不是一个真正的问题;并且你仍然有一个窗口,两个会话查询相同的'max(id)'值,但'nextval'调用应该使它工作。尽管如此,你不能在普通的SQL中这样做,并且允许混合仍然是混乱的。另一种类似的方法是在循环中尝试使用'nextval'的插入,如果*不*获得ORA-00001,则退出,假设列上有PK/UK。这避免了必须查找最大值,并填补空白,这可能会或可能不需要。只有使用序列比较容易,虽然... –