在存储过程中看到一个语句:
select sql_log_id.nextval into vcSeq_log_id from dual;
序列 (SEQUENCE) 是序列号生成器,可以为表中的行自动生成序列号,产生一组等间隔的数值(类型为数字)。
不占用磁盘空间,占用内存。
其主要用途是生成表的主键值,可以在插入语句中引用,也可以通过查询检查当前值,或使序列增至下一个值。
通过 nextval
返回序列中下一个有效的值,任何用户都可以引用。
创建序列需要 create sequence
系统权限。序列的创建语法如下:
(序列名常定义为‘seq_XXX’的形式,创建序列不能使用replace)
create sequence 序列名
increment by n
start with n
maxvalue/minvalue n | nomaxvalue
cycle | nocycle
cache n | nocache
其中:
实例:
-- 创建序列
create sequence t_id_sql increment by 1 start with 1;
-- 删除序列
drop sequence t_id_sql;
-- 查询当前序列
select t_id_sql.currval from dual;
-- 查询下一个序列值
select t_id_sql.nextval from dual;
-- 测试
select t_id_sql.currval, t_id_sql.nextval from dual; -- 同时执行不报错 返回 1 1
-- 测试负数
drop sequence t_id_sql;
create sequence t_id_sql increment by -1 start with -5;
select t_id_sql.currval,t_id_sql.nextval from dual; -- -5 -5
-- 继续执行之后 返回 -6 -6 -7 -7
发现:针对新建的序列必须先使用 nextval 进行查询之后才能使用 currval 进行查询当前序列,否则会报错。
实例:
-- 创建测试表
create table temp_cwh_test_0530
(
id number,
money number,
age number
);
-- 插入数据
insert into temp_cwh_test_0530 values
(t_id_sql.nextval,1,1);
-- 插入8次之后
-- 查询
select * from temp_cwh_test_0530
1 1 1
2 1 1
3 1 1
4 1 1
5 1 1
6 1 1
7 1 1
8 1 1
-- 查询序列
select t_id_sql.currval from dual; -- 8
-- 查询下一个序列值
select t_id_sql.nextval from dual; -- 9 10 11 执行3次
修改序列需要注意:
实例:
-- 修改序列
alter sequence t_id_sql increment by 10 maxvalue 1000 cycle; -- 增长到1000之后重新开始
-- increment by 10 maxvalue 100 报错,可能 cache 中已经保存了20个值,所以无法直接修改
-- 继续插入数据
insert into temp_cwh_test_0530 values
(t_id_sql.nextval,1,1);
1 1 1
2 1 1
3 1 1
4 1 1
5 1 1
6 1 1
7 1 1
8 1 1
18 1 1
28 1 1
38 1 1
可以营销 sequence 的初始化参数:
sequence_cache_entries = 10 设置能同时被 cache 的 sequence 数量。
-- 修改测试
alter sequence t_id_sql increment by 2 maxvalue 10 cycle; -- 报错
-- ORA-04013: number to CACHE must be less than one cycle
-- 修改测试
alter sequence t_id_sql increment by 2 maxvalue 100 cycle;
-- sequence altered.
在数据库中可以通过数据字典 user_objects 查看用户拥有的序列。
select * from user_objects where object_type = ‘SEQUENCE‘
查看所有 user_objects 类型。
select distinct object_type from user_objects;
/*
INDEX PARTITION
SEQUENCE
TABLE PARTITION
PROCEDURE
DATABASE LINK
LOB
PACKAGE
PACKAGE BODY
TYPE BODY
MATERIALIZED VIEW
TABLE
VIEW
INDEX
FUNCTION
SYNONYM
TYPE
*/
通过数据字典 user_sequences 可以查看序列的设置。
select * from user_sequences; -- 包含以下字段
-- sequence_name
-- min_value
-- max_value
-- increment_by
-- cycle_flag
-- order_flag
-- cache_size
-- last_number
通过数据字典 all_sequences 可以查看所有用户下的序列。
select * from all_sequences;
select * from dba_sequences; -- 应该是一样的
通过 drop 删除序列。
drop sequence t_id_sql;
表设计中选择主键问题,用 sequence 作为主键有什么优缺点。
(1)如果一个事务中只是 insert 时需要序列,其他地方不会需要这个序列,那么只需要在 INSERT ... VALUES (seq.nextval ...)语句中使用即可;
(2)如果一个事务中 INSERT 一张表后,还需要插入时的主键ID值,作为外键插入其他表,那么就需要在 INSERT 第一张表前使用 select seq.nextval from dual 提前获取可用的 ID 保存到一个变量中,为后面使用。
使用序列时 Oracle 内部大体是按照如下步骤进行:
(1)一个序列会被定义到 Oracle 内部的一张数据字典表(seq$)的一行。
(2)第一次使用序列,序列的起始值会加上缓存大小,然后更新回行。
(3)Oracle内部会自动跟踪内存中的两个值,当前值和目标值。
(4)每次有会话调用 seq.nextval,Oracle 会递增当前值,然后检查是否超过了目标值,再返回结果。
(5)如果当前值和目标值相同,Oracle 会更新数据字典表中的行,为目标值加上缓存大小,同时内存中产生了一个新的目标值。
如果 cache 值较小,且序列使用的频率较高,那么会对 seq$ 表有频繁的更新操作,日志量会增加,尤其在RAC下,更新该行的时候,该数据块会在节点间不停的传送,就会产生可能的争用,这种问题会被放大。
因此为了减少这种情况,我们可以将 cache 缓存值设置大一些,例如1000,减少对字典表的更新。
序列还有一个问题,就是 cache 缓存是实例级的,对于RAC,比如第一个节点使用序列时会分配1-20,第二个节点会被分配21-40,Oracle保证不会重复,但若节点crash了,比如节点1坏了,那么序列就会出现断号,节点1再次使用时,只会从41-60,由于我们用主键只为了标示唯一,不关心段号,也不关心产生的顺序,所以这些可以忽略。
序列在下列情况下会出现裂缝:
参考链接1:Oracle中序列(Sequence)详解
参考链接2:Oracle 中select XX_id_seq.nextval from dual 什么意思呢?
参考链接3:Oracle序列的创建和使用
原文:https://www.cnblogs.com/hider/p/12993386.html