ORACLE开发误区探索【三】(SEQUENCE )

梁敬彬梁敬弘兄弟出品

往期回顾
ORACLE开发误区探索【一】(空格、过程与权限、DDL)
ORACLE开发误区探索【二】(insert into、or)

在Oracle数据库开发中,SEQUENCE是生成唯一标识符的常用工具。然而,很多开发人员对其工作机制存在误解,特别是CACHE参数的作用及其对序列连续性的影响。本文深入剖析SEQUENCE的CACHE机制,帮助开发者正确使用这一重要特性。

6. SEQUENCE中的CACHE机制解析

SEQUENCE可以生成一系列连续的唯一数值,但许多开发人员没有意识到:默认情况下,SEQUENCE并不保证生成的值完全连续且无缺失。尤其在配置了CACHE参数后,这种情况更为明显。

6.1 CACHE机制如何工作

当配置CACHE参数时,Oracle会预先分配并缓存一批序列值到内存中,以提高性能。这种机制虽然提升了效率,但也带来了序列值可能断号的问题。

实验演示

-- 创建带20个缓存的序列
CREATE SEQUENCE ljb_test_seq
  MINVALUE 1
  MAXVALUE 1000
  START WITH 1
  INCREMENT BY 1
  CACHE 20
  ORDER;

-- 首次访问序列值
SELECT ljb_test_seq.NEXTVAL FROM dual;
-- 结果: 1

-- 查看当前值
SELECT ljb_test_seq.CURRVAL FROM dual;
-- 结果: 1

-- 清空共享池
ALTER SYSTEM FLUSH SHARED_POOL;

-- 查看当前值(不受清空共享池影响)
SELECT ljb_test_seq.CURRVAL FROM dual;
-- 结果: 1

-- 获取下一个值
SELECT ljb_test_seq.NEXTVAL FROM dual;
-- 结果: 21(而非预期的2!)

这一现象表明,当首次访问SEQUENCE时,Oracle就预先为该会话缓存了20个值(1-20)。当共享池被清空后,这些缓存值丢失,Oracle不得不再次分配20个新值(21-40),导致序列从21继续,中间跳过了19个值。

6.2 导致序列断号的其他情况

不仅是共享池清空会导致序列断号,以下操作也会导致类似问题:

数据库实例重启

-- 重启数据库后
SELECT ljb_test_seq.NEXTVAL FROM dual;
-- 结果将跳过当前缓存中所有未使用的值

事务回滚

-- 创建测试表
CREATE TABLE ljb_test(id1 INT);

-- 插入几条记录
INSERT INTO ljb_test VALUES (ljb_test_seq.NEXTVAL);  -- 值:42
INSERT INTO ljb_test VALUES (ljb_test_seq.NEXTVAL);  -- 值:43
INSERT INTO ljb_test VALUES (ljb_test_seq.NEXTVAL);  -- 值:44
COMMIT;

-- 插入后回滚
INSERT INTO ljb_test VALUES (ljb_test_seq.NEXTVAL);  -- 值:45
ROLLBACK;

-- 再次插入
INSERT INTO ljb_test VALUES (ljb_test_seq.NEXTVAL);  -- 值:46(而非45!)

事务回滚后,序列值45已被分配但未使用,导致序列断号。

插入操作失败

当INSERT语句因其他原因(如约束违反)失败时,已分配的序列值也不会被回收,同样会导致序列断号。

6.3 NOCACHE是否能解决问题?

有人认为使用NOCACHE选项可以避免序列断号,这是一个误解。

CREATE SEQUENCE no_cache_seq
  MINVALUE 1
  MAXVALUE 1000
  START WITH 1
  INCREMENT BY 1
  NOCACHE
  ORDER;

事实上,即使使用NOCACHE,以下情况仍会导致序列断号:

  • 事务回滚
  • 插入操作失败
  • 数据库实例崩溃

6.4 CACHE的性能优势

虽然CACHE机制可能导致序列断号,但它带来的性能优势是不容忽视的:

  1. 减少数据字典访问:每次分配新的序列值组时,只需一次数据字典访问
  2. 降低争用:在RAC环境中,不同实例可以缓存不同范围的序列值,减少争用
  3. 提高插入性能:特别是在大批量插入操作中,效果显著

最佳实践建议

1. 评估业务需求:

  • 如果业务对序列连续性没有严格要求(绝大多数情况),使用CACHE
  • 如果必须确保连续性,考虑自定义实现或使用应用级锁定机制

2. CACHE大小设置:

  • 一般应用:20-50之间
  • 高并发应用:50-200之间
  • 特大批处理:200-300之间(超过300提升不明显)

3. 性能考虑:

  • 对于RAC环境,适当增大CACHE值可减少实例间争用
  • 批量插入操作中,较大的CACHE值可提高性能

4. 避免误解:

  • 认识到SEQUENCE(无论是否使用CACHE)都不能保证完全连续
  • NOCACHE选项不能解决序列断号问题,反而会影响性能

实际应用对比

在这里插入图片描述

6.5 总结

SEQUENCE的CACHE机制是Oracle提供的一种性能优化方案,虽然可能导致序列值不连续,但在绝大多数应用场景中,这种不连续性是可以接受的。正确理解CACHE机制的工作原理,可以帮助开发者根据业务需求做出合理的配置选择。

  1. 序列断号是常态而非异常:无论是否使用CACHE,序列断号都可能发生
  2. NOCACHE并非解决方案:不使用缓存不能解决序列断号问题,反而会影响性能
  3. 适当配置CACHE:根据应用场景和并发需求,选择合适的CACHE大小
  4. 业务适应:设计业务逻辑时应考虑到序列可能断号的特性

再次强调:对于真正需要连续编号的应用(如票据号码),应考虑在应用层实现自定义序列生成逻辑,而不应完全依赖Oracle SEQUENCE机制。实际应用中,90%以上的序列都不会绝对要求是连续不中断的,此时sequence+cache就发挥了巨大的作用了。我的观点是没有特别的不断号需求,最好都使用sequence,并且加上cache,并且尽量不要太小,当然值太大也浪费,我们测试的结果是一般不要超过300,再往上性能提升不明显了。带cache的sequence能带来两个好处:1、速度能提高,2、RAC环境可避免争用,两个实例可各自缓存一部分sequence值。曾经和同事一起优化过sequence,就是要求开发将所有的带sequence的脚本都加上cache ,后来测试发现对表的插入速度有了显著的提高,并且也缓解了RAC环境的争用。
此外,既然sequence+nochache 也不能绝对保证不断号,这个nocache也没什么用了,所以sequece指定nocache的方式可以抛弃掉了。

在这里插入图片描述

未完待续…

ORACLE开发误区探索【四】(树形查询、保留字)

系列回顾

“大白话人工智能” 系列
“数据库拍案惊奇” 系列
“世事洞明皆学问” 系列

三分钟讲述个人感悟——感恩,回馈

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

收获不止数据库

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值