这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

命名序列

命名序列是由 CREATE SEQUENCE 定义的序列。虽然可以将表列的值设置为命名序列,但与 AUTO_INCREMENT 和 IDENTITY 序列不同,命名序列独立于表而存在。

当应用程序要求表或表达式中使用唯一标识符时,最常使用命名序列。在命名序列返回一个值后,它永远不会在同一会话中再次返回相同的值。

1 - 创建和使用命名序列

使用 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)

在表中引用序列

表可以将任何列的默认值设置为命名序列。表创建者必须具有以下权限: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)

2 - 分发命名序列

当创建命名序列时,其 CACHE 参数决定了每个节点在会话期间所保留的序列值的数量。默认缓存值为 250K,因此每个节点在每个会话期间为每个序列保留 250,000 个值。此默认缓存大小为大规模插入或复制操作提供了一种有效的方式。

如果将序列缓存设置为较低的数字,则节点可能会更频繁地请求一组新的缓存值。提供新缓存时,Vertica 必须锁定编录。在 Vertica 释放锁之前,其他数据库活动(例如表插入)会被阻止,这将对整体性能产生不利影响。

当一个新会话启动时,节点缓存最初为空。默认情况下,启动程序节点会为群集中的所有节点请求和保留缓存。可以通过将配置参数 ClusterSequenceCacheMode 设置为 0 来更改此默认值,以便每个节点都请求其自己的缓存。

有关 Vertica 如何请求缓存并在群集中的所有节点之间分发缓存的信息,请参阅序列缓存

分布式会话的影响

Vertica 在所有节点之间分发会话。群集节点第一次对序列调用 NEXTVAL 函数以递增(或递减)其值时,该节点会请求其自己的序列值缓存。然后,该节点会为当前会话维护该缓存。当其他节点调用 NEXTVAL 时,它们也会创建和维护其自己的序列值缓存。

在会话期间,节点会以不同的频率独立调用 NEXTVAL。每个节点都使用其自己的缓存来填充序列。所有序列值都保证唯一,但是可能与另一个节点上执行的 NEXTVAL 语句出现乱序。因此,序列值通常不连续。

在所有情况下,每行仅递增序列一次。因此,如果多个列引用了同一序列,则 NEXTVAL 会将该行中的所有列设置为相同的值。这适用于联接表的行。

计算命名序列

Vertica 按如下方式计算序列的当前值:

  • 在每个语句结束时,会话中使用的所有序列的状态都会返回到启动程序节点。

  • 启动程序节点计算每个序列在所有节点上的所有状态下的最大 CURRVAL

  • 此最大值将用作后续语句中的 CURRVAL,直到调用另一个 NEXTVAL。

丢失序列值

在下列情况下,缓存中的序列值可能会丢失:

  • 如果在调用 NEXTVAL 后某条语句失败了(因此耗用了缓存中的一个序列值),则值就会丢失。

  • 如果连接断开了(如删除了会话),则缓存中尚未通过 NEXTVAL 返回的所有剩余值都会丢失。

  • 一个或多个节点尚未用完其当前缓存分配时,启动程序节点便为每个节点分发新的缓存块。有关此场景的信息,请参阅序列缓存

可以使用 ALTER SEQUENCE...RESTART 恢复丢失的序列值,这会在下一个会话中将序列重置为指定的值。

3 - 更改序列

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;

4 - 删除序列

使用 DROP SEQUENCE 移除命名序列。例如:

=> DROP SEQUENCE my_sequence;

如果满足以下条件之一,则不能删除序列:

  • 其他对象依赖该序列。 DROP SEQUENCE 不支持级联操作。

  • 列的 DEFAULT 表达式引用该序列。在删除该序列之前,必须移除对它的所有列引用。