作者:微信小助手
发布时间:2018-10-05T10:38:04
1. sequence基本介绍
2. sequence性能问题
3. 18c的sequence新特性
4. 一些开发中sequence的使用经验
1. sequence基本介绍
下图是11g的《Reference》,对于create sequence语法的介绍,
可以知道,sequence有一系列参数,可以辅助序列的创建,实现各种需求,
INCREMENT BY:步长,不能为0,正值最大28位,表示升序,负值最大27位,表示降序。该参数的绝对值,必须小于MAXVALUE和MINVALUE之差。默认值为1。
START WITH:起始值,对于降序序列,默认值为序列的最大值,对于升序序列,默认值为序列的最小值。
MAXVALUE:最大值,正值最大28位,负值最大27位,MAXVALUE >= START WITH,MINVALUE > MAXVALUE。
NOMAXVALUE:对于升序序列,最⼤值为1028-1,对于降序序列,最⼤值为-1,该参数为默认值。
MINVALUE:最小值,正值最大28位,负值最大27位,MINVALUE <= START WITH,MINVALUE < MAXVALUE。
NOMINVALUE:对于升序序列,最小值为1,对于降序序列,最小值为-(1027 -1),该参数为默认值。
CYCLE:表示序列值到达最⼤或最⼩值后继续循环生成新值。
NOCYCLE:表示序列值到达最大或最小值后不会生成新值,该参数为默认值。
CACHE:表示在内存中缓存多少个序列值,最大28位,最小值为2,对于CYCLE=Y的序列,CACHE的值必须小于循环的序列值,CACHE允许的最大值必须小于如下公式:CEIL (MAXVALUE - MINVALUE)) / ABS (INCREMENT)如果数据库崩溃,还未提交的缓存序列,就会丢失。RAC下建议使用cache选项。
NOCACHE:不缓存序列值,如果不指定CACHE和NOCACHE,默认缓存20个的序列值。
ORDER:表示序列会按照请求的顺序,生成序列值,如果使用序列,作为时间戳,则此参数有用,但若作为主键,未必需要保证序列的顺序。如果用的RAC,ORDER是唯一可以保证按序创建序列值的方法,除此之外,序列都是按序产生的。
NOORDER:不需要保证序列按序创建,这是默认配置。
通常我们创建一个序列,会包含这些常用的参数,
要了解sequence背后,Oracle做了什么,可以执行10046事件,例如执行create sequence bisal_seq语句,10046的trace记录如下,会向seq$插入记录,从字段名称可以看出,存储的是sequence相应的参数值,
同样检索seq$,可以和上述trace对应起来,
同时,会向obj$插入一条对象的记录,标记序列对象,
执行检索select bisal_seq.currval, bisal_seq.nextval from dual语句,会更新seq$,主要更新highwater高水位,因为序列要保证值唯一,
创建序列,不带任何参数,默认参数值如下,
问题1:cache存储的是什么?
有些人可能认为存储的是1,2,3...20,但实际存储的是目标值,例如20,其他值存储在缓存中。
问题2:缓存在什么位置?
序列值是基于会话读取的,但并不是存储在会话中,而是存在SGA。
语法上,会话中首先要nextval,否则直接currval,会提示错误,使用nextval取出下一值,就可以用currval查看当前值了,
2. sequence性能问题
sequence是非常普通的Oracle对象,但如果使用不当,就可能会导致一些性能问题,如下介绍了三个场景。
场景1:RAC下,nocache选项创建频繁使用的sequence
从之前介绍中,我们了解了,当需要读取的sequence值,到达了当前cache的最大值,就会更新seq$的highwater,这样做的目的,就是为了保证序列值唯一。如果创建序列,不使用cache选项,相当于每次使用序列,都要更新seq$表。如果使用的是RAC,每个节点使用了序列,都要更新seq$,可能出现的场景,就是seq$表的数据块,会在实例之间频繁地传输,进而就可能产生一些gc相关的等待事件,造成性能问题。因此RAC下,对于频繁使用的序列,用nocache选项非常危险。
场景2:RAC下,order选项创建频繁使用的sequence
创建序列,可以采用order选项,为了可以按顺序产生序列值,在RAC下,由于存在多实例,为了保证不同节点间,序列产生的值是连续的,会使用特殊的全局锁(SV)来控制,序列当前值就是通过这个锁的流转来传送,实现跨实例串行化生成序列值,频繁使用序列,就可能会出现DFS lock handle、latch: gets resource hash list、row cache lock等待事件,造成性能问题,因此尤其对于RAC,用order选项创建频繁使用的sequence非常危险。
场景3:sequence作为主键或者唯一键
无论sequence无论作为主键还是唯一键,都会自动创建一个唯一索引,由于他的值是递增产生的,因此总会发生索引单向增长,如下图所示,对于递增的序列,总会在B树索引最右侧的索引块,插入新值,当数据块没有空间的时候,就会发生9-1分裂,创建新的数据块,因此争用总会发生在索引叶子节点的最右侧数据块上,
其实针对这问题,之前RWP的Andrew就有介绍,另外,我们系统设计初期的POC,碰见了相同的问题,有三种解决方案。
方案一:将索引重建为reverse-key index
这种方案,可以缓解索引热块的争用,但是随着数据量的增加,索引越大,对于范围检索,一次检索可能需要读取到buffer cache的索引数据块就会越多,一方面可能会产生磁盘IO方面的等待,另一方面可能会将其他表或索引的数据挤出内存,因此,很有可能只是从索引争用,转换成另一种资源的等待,没有从根本解决这个问题。
方案二:将索引重建为hash partition index
如果是单实例,这种方案会有效,因为他将原先争用的块数据,分散到了不同的数据块,但是,如果迁移RAC,由于频繁的使用,可能会出现索引数据块在节点间频繁的传输,而且随着节点数增加,传输的可能性就会越大,还是会产生性能的问题。
方案三:编码生成的智能主键
其实,我们所要解决的,就是这三个问题,
问题1:避免实例间传输
问题2:避免索引单向争用
问题3:保证序列取值不重复
针对问题1,我们选择实例号,作为序列的开始,保证数据插入,会保存在节点的一边,