我正在使用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
有时会出现重复记录的错误......
请帮我解决这个疑问
答案 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
在这种情况下,我会有一个完全稳定的程序,也可以允许手动插入,而不必担心更新序列