命名序列是由
CREATE SEQUENCE
定义的序列。虽然可以将表列的值设置为命名序列,但与 AUTO_INCREMENT 和 IDENTITY 序列不同,命名序列独立于表而存在。
当应用程序要求表或表达式中使用唯一标识符时,最常使用命名序列。在命名序列返回一个值后,它永远不会在同一会话中再次返回相同的值。
命名序列是由
CREATE SEQUENCE
定义的序列。虽然可以将表列的值设置为命名序列,但与 AUTO_INCREMENT 和 IDENTITY 序列不同,命名序列独立于表而存在。
当应用程序要求表或表达式中使用唯一标识符时,最常使用命名序列。在命名序列返回一个值后,它永远不会在同一会话中再次返回相同的值。
使用
CREATE SEQUENCE
创建命名序列。该语句只需提供序列名称即可;所有其他参数均为可选参数。要创建序列,用户必须对包含该序列的架构具有 CREATE 权限。
以下示例将创建一个起始值为 100 的升序命名序列 my_seq
:
=> CREATE SEQUENCE my_seq START 100;
CREATE SEQUENCE
在创建命名序列对象时,还可以通过设置其 INCREMENT
参数指定其递增量或递减量值。如果省略此参数(如上一示例中所示),则默认值设置为 1。
可以通过对序列调用函数
NEXTVAL
来递增或递减序列(直接在序列本身上递增或递减,或通过向引用该序列的表中添加新行来间接地递增或递减)。对新序列第一次调用时,NEXTVAL
将该序列初始化为其起始值。Vertica 还会为序列创建缓存。随后对序列调用 NEXTVAL
会递增其值。
下面对 NEXTVAL
的调用会将新 my_seq
序列初始化为 100:
=> SELECT NEXTVAL('my_seq');
nextval
---------
100
(1 row)
可以通过对序列调用
CURRVAL
来获取该序列的当前值。例如:
=> SELECT CURRVAL('my_seq');
CURRVAL
---------
100
(1 row)
CURRVAL
在以下情况下将返回错误:如果对尚未由 NEXTVAL
初始化的新序列或对尚未在新会话中访问的现有序列调用它。例如:
=> CREATE SEQUENCE seq2;
CREATE SEQUENCE
=> SELECT currval('seq2');
ERROR 4700: Sequence seq2 has not been accessed in the session
表可以将任何列的默认值设置为命名序列。表创建者必须具有以下权限:SELECT(对于序列)、USAGE(对于其架构)。
在以下示例中,列 id
从命名序列 my_seq
获取其默认值:
=> CREATE TABLE customer(id INTEGER DEFAULT my_seq.NEXTVAL,
lname VARCHAR(25),
fname VARCHAR(25),
membership_card INTEGER
);
对于插入到表 customer
中的每一行,该序列调用 NEXTVAL
函数来设置 id
列的值。例如:
=> INSERT INTO customer VALUES (default, 'Carr', 'Mary', 87432);
=> INSERT INTO customer VALUES (default, 'Diem', 'Nga', 87433);
=> COMMIT;
对于每一行,插入操作都会对序列 my_seq
调用 NEXTVAL
,这会将该序列递增至 101 和 102,并将 id
列设置为这些值:
=> SELECT * FROM customer;
id | lname | fname | membership_card
-----+-------+-------+-----------------
101 | Carr | Mary | 87432
102 | Diem | Nga | 87433
(1 row)
当创建命名序列时,其 CACHE
参数决定了每个节点在会话期间所保留的序列值的数量。默认缓存值为 250K,因此每个节点在每个会话期间为每个序列保留 250,000 个值。此默认缓存大小为大规模插入或复制操作提供了一种有效的方式。
如果将序列缓存设置为较低的数字,则节点可能会更频繁地请求一组新的缓存值。提供新缓存时,Vertica 必须锁定编录。在 Vertica 释放锁之前,其他数据库活动(例如表插入)会被阻止,这将对整体性能产生不利影响。
当一个新会话启动时,节点缓存最初为空。默认情况下,启动程序节点会为群集中的所有节点请求和保留缓存。可以通过将配置参数 ClusterSequenceCacheMode
设置为 0 来更改此默认值,以便每个节点都请求其自己的缓存。
有关 Vertica 如何请求缓存并在群集中的所有节点之间分发缓存的信息,请参阅序列缓存。
Vertica 在所有节点之间分发会话。群集节点第一次对序列调用 NEXTVAL 函数以递增(或递减)其值时,该节点会请求其自己的序列值缓存。然后,该节点会为当前会话维护该缓存。当其他节点调用 NEXTVAL 时,它们也会创建和维护其自己的序列值缓存。
在会话期间,节点会以不同的频率独立调用 NEXTVAL。每个节点都使用其自己的缓存来填充序列。所有序列值都保证唯一,但是可能与另一个节点上执行的 NEXTVAL 语句出现乱序。因此,序列值通常不连续。
在所有情况下,每行仅递增序列一次。因此,如果多个列引用了同一序列,则 NEXTVAL 会将该行中的所有列设置为相同的值。这适用于联接表的行。
Vertica 按如下方式计算序列的当前值:
在每个语句结束时,会话中使用的所有序列的状态都会返回到启动程序节点。
启动程序节点计算每个序列在所有节点上的所有状态下的最大
CURRVAL
。
此最大值将用作后续语句中的 CURRVAL
,直到调用另一个 NEXTVAL。
在下列情况下,缓存中的序列值可能会丢失:
如果在调用 NEXTVAL 后某条语句失败了(因此耗用了缓存中的一个序列值),则值就会丢失。
如果连接断开了(如删除了会话),则缓存中尚未通过 NEXTVAL 返回的所有剩余值都会丢失。
一个或多个节点尚未用完其当前缓存分配时,启动程序节点便为每个节点分发新的缓存块。有关此场景的信息,请参阅序列缓存。
可以使用 ALTER SEQUENCE...RESTART 恢复丢失的序列值,这会在下一个会话中将序列重置为指定的值。
ALTER SEQUENCE
可以通过两种方式更改命名序列:
重置控制序列行为的参数,例如其起始值或最小值和最大值的范围。这些更改仅在您启动新数据库会话时生效。
重置序列名称、架构或所有权。这些更改会立即生效。
ALTER SEQUENCE
语句不能同时进行这两种类型的更改。
ALTER SEQUENCE
可以通过以下参数更改一个或多个序列属性:
这些更改仅在您启动新数据库会话时生效。例如,如果创建一个从 10 开始并按 1(默认值)递增的命名序列 my_sequence
,则序列每次调用 NEXTVAL
都会按 1 递增其值:
=> CREATE SEQUENCE my_sequence START 10;
=> SELECT NEXTVAL('my_sequence');
nextval
---------
10
(1 row)
=> SELECT NEXTVAL('my_sequence');
nextval
---------
11
(1 row)
以下 ALTER SEQUENCE
语句指定重新启动序列时从 50 开始:
=>ALTER SEQUENCE my_sequence RESTART WITH 50;
但是,此更改在当前会话中不起作用。对 NEXTVAL
的下一次调用会将序列递增至 12:
=> SELECT NEXTVAL('my_sequence');
NEXTVAL
---------
12
(1 row)
只有在启动新的数据库会话后,该序列才会在 50 处重新启动:
=> \q
$ vsql
Welcome to vsql, the Vertica Analytic Database interactive terminal.
=> SELECT NEXTVAL('my_sequence');
NEXTVAL
---------
50
(1 row)
可以使用 ALTER SEQUENCE
对命名序列进行以下更改:
重命名它。
将其移动到另一个架构。
重新分配所有权。
这些更改中的每个更改都需要使用单独的 ALTER SEQUENCE
语句。这些更改会立即生效。
例如,以下语句将序列从 my_seq
重命名为 serial
:
=> ALTER SEQUENCE s1.my_seq RENAME TO s1.serial;
以下语句将序列 s1.serial
移动到架构 s2
中:
=> ALTER SEQUENCE s1.my_seq SET SCHEMA TO s2;
以下语句将 s2.serial
的所有权重新分配给另一个用户:
=> ALTER SEQUENCE s2.serial OWNER TO bertie;
使用
DROP SEQUENCE
移除命名序列。例如:
=> DROP SEQUENCE my_sequence;
如果满足以下条件之一,则不能删除序列:
其他对象依赖该序列。 DROP SEQUENCE
不支持级联操作。
列的 DEFAULT
表达式引用该序列。在删除该序列之前,必须移除对它的所有列引用。