序列(SEQUENCE)是序列号生成器,可以自动产生一组等间隔的数值(类型为数字)。是Oracle实现自动增长的一种方式, 不占用磁盘空间,占用内存。其主要用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一个值。
1. 创建序列的语法
CREATE SEQUENCE 序列名
[INCREMENT BY n]
[START WITH n]
[{MAXVALUE/ MINVALUE n| NOMAXVALUE}]
[{CYCLE|NOCYCLE}]
[{CACHE n| NOCACHE}];
--例如:
create sequence SEQ_RIGHT
minvalue 1
maxvalue 9999999999
start with 1
increment by 1
nocache;
- INCREMENT BY用于定义序列的步长,如果省略,则默认为1,如果出现负值,则代表Oracle序列的值是按照此步长递减的。
- START WITH 序列的起始值,默认为1。
- MAXVALUE 序列最大值 选项NOMAXVALUE是默认选项,代表没有最大值定义,系统能够产生的最大值是10的27次方
- MINVALUE序列最小值。选项NOMAXVALUE是默认选项,代表没有最小值定义,系统能够产生的最小值是负10的26次方
- CYCLE和NOCYCLE 表示当序列生成器的值达到限制值后是否循环。CYCLE代表循环即到达例如最大值后重新从最小值开始
- CACHE(缓冲)定义存放序列的内存块的大小,默认为20。NOCACHE表示不对序列进行内存缓冲。对序列进行内存缓冲,可以改善序列的性能。
2. 删除序列
--DROP SEQUENCE 序列名称
DROP SEQUENCE SEQ_CUSTOMER;
3. 查询序列信息
select * from dba_sequences where sequence_owner='HLJ_633_20160417';
4. 序列应用
--获取下一个序列值
select seq_customeren.nextval from dual;
--获取当前的序列值
select seq_customeren.currval from dual;
当我们写一个存储过程的时候使用seq_customeren.nextval 获取下一个序列值,当事务没有commit提交的时候使用 seq_customeren.currval 可以获取刚刚生成的序列值
5.序列跳号问题
用Sequence当数据表的主键ID, 数据库中ID 变化为21\31\41 有序数字,而不是1\2\3依次增长 这个问题主要是由于CACHE设置了值引起
如果指定CACHE值,例如CACHE 设置为10,Oracle就可以预先在内存里面放置一些10个 Sequence 。Oracle获取序列的时候会优先从cache里取, cache里面的消耗完后,Oracle自动再取一组到cache。这种处理提高了新更能,但是会跳号, 比如数据库突然不正常down掉(shutdown abort),cache中的Sequence就会丢失。重启数据库后,sequence的值将从21开始重新cache里存的是(21-30)
6.序列性能问题
创建nocache sequence在高并发访问时,容易导致row cache lock等待事件,主要原因是每次获取nextval时都需要修改rowcache中的字典信息,使用nocache sequence,还会导致如下问题:由于每次修改字典信息都需要commit,可能导致log file sync等待
sequence相关保护机制:
- row cache lock:在调用sequence.nextval情况下需要修改数据字典时发生,对应row cache lock事件
- SQ lock:在内存缓存(并非rowcache)上获取sequence.nextval时发生,对应enq:SQ-contention事件
- SV lock:RAC环境下获取cache+order属性的sequence.nextval时发生,对应DFS lock handle事件
第一个问题:这个锁影响有多大呢?
我举个例子,之前的工作中有一次调优,系统处理有张表要插入1000W+ 数据,当序列设置为nocache的时候,系统任务处理时间大于6小时, 当我把序列设置为cache 5000的时候,系统任务处理时间只有1小时,所以创建序列的时候还是要关注自己的业务场景
第二个问题:什么情况下使用cache什么时间上使用nocache?
个人觉得按照以下方式
- 如果业务场景是高并发或者存在批处理,即序列的消耗速度很快,这种情况使用且cache数值根据业务量来确定,这样从cache中取序列,可以提高性能
- 如果你的业务要求是绝不能产生间断的序列号或者序列消耗速度比较慢,那么建议使用nochache了。
7.Oracle RAC序列顺序混乱问题
在数据库部署了RAC环境之后,偶尔会出现从Oracle Sequence取出来的数是混乱的,时间上先保存的数据的sequence的值比较大, 后保存的数据的sequence的值比较小. 当程序的逻辑依赖于ID的大小来排序时,就会产生系统处理错误。
Oracle RAC更多信息参考:https://blog.youkuaiyun.com/Beijing_L/article/details/118158407
Oracle Real Application Cluster (RAC,实时应用集群)用来在集群环境下实现多机共享数据库,以保证应用的高可用性;同时可以自动实现并行处理及负载均衡,并能实现数据库在故障时的容错和无断点恢复。它是oracle数据库支持网络计算环境的核心技术。它是oracle数据库支持网络计算环境的核心技术。
数据库是个RAC集群部署,序列是被共享。序列默认是有缓存的所以没有设置nocache序列属性的序列,每一个Oracle实例上都会缓存序列值。假设RAC上的两个节点上序列缓存设为20,第一个节点上缓存1-20,第二个节点缓存了21-40
第一个请求通过第2个节点先保存数据,记录的sequence 为21
第二个请求通过第1个节点保存数据, 记录的sequence 为1 , 这样时间上后保存的sequence反而大,
那么这个问题我们怎么解决呢
1. 设置cache为空,这样会影响性能
2. 创建序列的时候设置为order,即采用cache + order (这种方式我也没试过,从网上搜索到有些人提出这种方法会有未知问题或者oracle崩溃问题, 之前看到这里心里有点儿怕)
3. 好吧,你要性能,那么忽略排序的问题吧,修改业务代码按照别的方式排序。