在表中插入新记录时,可以有两种方法,一种是查找主键列的最大值,并为其添加1或使用序列。哪种方法更好,为什么?
如果我们通过在记录少于20,000条记录的表中递增主键列的最大值来找到下一个主键值会有什么影响?
感谢。
答案 0 :(得分:13)
问:哪种方法更好,为什么?
答:使用SEQUENCE
对象是一种更好的方法。
获取唯一 id值的MAX(id)+1
方法在多线程环境中已损坏,缺少并发查杀锁定。单个用户测试不会暴露此问题;但是使用两个不同的会话来演示这个很容易。考虑这一系列操作:
会话1:SELECT MAX(id)+1 AS next_id FROM mytable
- > 42
会话2:SELECT MAX(id)+1 AS next_id FROM mytable
- > 42
第1节:INSERT INTO mytable (id) VALUES (42)
会话2:INSERT INTO mytable (id) VALUES (42)
为防止两个(或多个)单独的会话返回相同的next_id
值,会话必须在执行查询之前获取表上的独占锁。在释放锁之前,还需要保持该锁,直到将具有next_id
值的行插入表中。虽然该会话持有表的独占锁,但没有其他会话可以查询或插入表中,其他会话将在它们尝试时阻止。 (我们不想通过引入这种锁定来破坏数据库性能,这不是正确的方法,所以我们不会演示如何做到这一点。)
Oracle提供SEQUENCE
对象作为获取唯一值的有效方法,而对SEQUENCE对象的查询在多线程环境中是“安全的”。对于高负载下的性能,我们会增加序列的“缓存”值,内存中可用的值的数量,这样我们就可以满足更多的NEXTVAL请求而无需写入重做日志。
考虑到这两个选项,SEQUENCE
是更好的方法。
问:如果我们通过在少于20,000条记录的表中递增主键列的最大值来找到下一个主键值会有什么影响?
A:检索索引列(作为索引中的前导列的列)的最大值并向其添加一个的查询应该非常高效,只要会话能够获得所需的共享锁(即,会话不会被独占锁阻止。)