Snowflake cloud data platform “合并”命令会导致序列号出现间隙

Snowflake cloud data platform “合并”命令会导致序列号出现间隙,snowflake-cloud-data-platform,Snowflake Cloud Data Platform,我试图使用MERGE命令在Snowflake中填充维度。为了实现代理键,我创建了一个默认为序列号的列,每当插入新行时,该列将自动递增。我曾在其他数据仓库平台上尝试过类似的方法,但从未引起任何问题。但是,我注意到,每当我在Snowflake中使用MERGE命令时,MERGE命令处理的每一行的序列号都会增加,而不管它是导致更新还是插入操作 下面是我所指内容的一个简单示例: -- Sequence CREATE OR REPLACE SEQUENCE seq1 START=1 INCREMENT=1;

我试图使用MERGE命令在Snowflake中填充维度。为了实现代理键,我创建了一个默认为序列号的列,每当插入新行时,该列将自动递增。我曾在其他数据仓库平台上尝试过类似的方法,但从未引起任何问题。但是,我注意到,每当我在Snowflake中使用MERGE命令时,MERGE命令处理的每一行的序列号都会增加,而不管它是导致更新还是插入操作

下面是我所指内容的一个简单示例:

-- Sequence
CREATE OR REPLACE SEQUENCE seq1 START=1 INCREMENT=1;

-- Source table
CREATE OR REPLACE TABLE source_table
(
row_key int,
row_value string
);

-- Target table: Column ID uses the sequence
CREATE OR REPLACE TABLE target_table 
(
id int DEFAULT seq1.nextval,
row_key int,
row_value string
);

-- Initial data
INSERT INTO source_table VALUES 
(1,'One'),
(2,'Two'),
(3,'Three');

MERGE INTO target_table D 
USING source_table s 
ON D.row_key=s.row_key
WHEN MATCHED AND D.row_value!=s.row_value THEN UPDATE SET row_value=s.row_value 
WHEN NOT MATCHED THEN INSERT(row_key,row_value) VALUES (s.row_key,s.row_value);
运行这些命令后,输出表将包含以下行:

ID、行\键、行\值
1,1,1
2,2,2
3,3,3

现在,让我们插入新行并再次运行相同的merge命令:

INSERT INTO source_table VALUES
(4,'Four');

MERGE INTO target_table D 
USING source_table s 
ON D.row_key=s.row_key
WHEN MATCHED AND D.row_value!=s.row_value THEN UPDATE SET row_value=s.row_value 
WHEN NOT MATCHED THEN INSERT(row_key,row_value) VALUES (s.row_key,s.row_value);
这一次,表的输出如下所示: ID、行\键、行\值
1,1,1
2,2,2
3,3,3
7,4,4

如果我插入另一行,下一个MERGE命令将插入ID设置为12的新行,并且同样的情况会继续下去。看起来MERGE命令会增加从源表读取的每一行的序列号,即使它们最终根本没有插入到目标表中

这是故意的行为吗?我尝试了标识功能,而不是序列,它没有改变输出


我的解决方法是用多个UPDATE和INSERT语句替换MERGE命令,但我仍然很想知道这种行为背后的原因

这是雪花开发团队正在解决的一个已知问题。正如您所提到的,解决方法是用多个UPDATE和INSERT语句替换MERGE命令。

根据Snowflake文档,Snowflake不保证序列中没有间隙

从文档中可以看出,Snowflake不能保证生成没有间隙的序列号。序列将在达到数据类型的最大正整数值后环绕

您可以尝试使用row_number()作为解决方法
您可能在其他事务数据库(Oracle、SQL Server)上执行了此操作。如果您在仓储/分析数据库(如Netezza)上这样做,您也会发现类似的序列行为;这是因为这些系统是为速度和批量处理而构建的;因此,它得到一个序列值块,它可以使用,也可以不使用。这确实留下了差距;但是,考虑到序列和工作流程的最大价值,在30到300年内你会达到最高点吗?可以说两者都不在乎

这些分析数据库通常具有更高的内在成本来运行任何查询;这在事务数据库中非常小。因此,他们可以在每次需要序列值时请求序列值(无孔!)——通过执行单个插入,您可以很容易地看到巨大的差异——您可能已经知道,雪花不鼓励这样做。不过,这里有一个简单的测试:创建一个表并生成200条insert语句,每条语句插入一行。在你的笔记本电脑上运行mysql;在一个中等大小的雪花上运行这个测试(或XS,但只是说明一点)——笔记本电脑上的mysql只是为了这个特定的测试而粉碎雪花;因为这是它被设计用来做的事情。对于单个插入,时间上会有巨大的差异,您将看到即使只进行一小批200行的插入,时间积累的速度也是如此之快

请注意,merge本身是一个相当事务性的命令,在这些类型的数据库上也不总是受支持。简单地自己进行单独操作可能更快,也可能更快;如前所述,您可能会在单独的新文件运行之间留下漏洞,但是,在单个操作中,您可以期望顺序序列的分配没有间隙

update target from source where business key exists in target;
insert into target from soure where business key not exists in target;
更新实际上是一个删除+插入的过程,如果您在某种序列-业务密钥映射中保留序列,那么您也可以简化(可能加快?)该过程

insert sequence, key into map where key in source and not in target;
begin;
delete from target where key exists in source and target;
insert source joined to map on key to retrieve sequence into target;
commit;

如果实际更新会变得更加丑陋,那么可能值得考虑。(也是一个奇怪的速度实验)

值得注意的是,IDENTITY只是利用了序列对象,因此它们的行为不会有所不同。正如其他人在这里所说的,序列漏洞可能会被视为一种不便,但不是一个bug。为了堵塞漏洞,可能需要额外的最终中央同步步骤,否则处理可以完全并行完成。如果您需要紧凑的序列,请使用
ROW\u NUMBER()
或类似的方法。我可以向您保证,Oracle的序列中也可能存在漏洞。我想这取决于数据库版本,如果您将Enterprise edition与并行服务器一起使用,可能会出现漏洞。填补这些差距总是会受到与同步相关的性能惩罚。