在解决任务和查看 Snowflake 文档的特定时间之后,我注意到查询的可读性和可能的性能改进的潜在改进。我的查询使用嵌套相关查询来检查主表是否有任何现有更新,使用单独的表进行更改。两个表都没有明确的 PK 或对允许值的任何其他约束。 这是一个简化查询的示例:
SELECT a.*
FROM tableA a
WHERE EXISTS (
SELECT 1
FROM tableA_CDC a_cdc
WHERE a.column1 = a_cdc.column1
AND a.column2 = a_cdc.column2
AND (a.column3 = a_cdc.column3 OR (a.column3 IS NULL AND a_cdc.column3 IS NULL))
)
我对最后一个谓词感兴趣(a.column3 = a_cdc.column3 OR(a.column3 IS NULL AND a_cdc.column3 IS NULL))。对于column3值可以为空,所以我们想从主表中获取行。 Column1和column2不能有空值,我们可以忽略空处理。
我发现的问题不仅在于可读性,而且正如我注意到的那样在于性能。基本上,如果我们仅通过“=”进行比较或检查两列是否均为 NULL,则一切正常(使用查询配置文件)。每个谓词的数据计数总和给出了正确的结果。但是,如果我们对 equals 或 is null 进行分组条件,那么我们就有正确的更改计数,但查询配置文件显示已执行全表扫描。
在文档中,我发现了名为“EQUAL_NULL”的函数,该函数允许空安全地比较两个表达式。如果我通过用 EQUAL_NULL 替换最后一个分组谓词来修改查询,那么结果是正确的并且没有全表扫描。
SELECT a.*
FROM tableA a
WHERE EXISTS (
SELECT 1
FROM tableA_CDC a_cdc
WHERE a.column1 = a_cdc.column1
AND a.column2 = a_cdc.column2
AND EQUAL_NULL(a.column3, a_cdc.column3)
)
有什么想法为什么我们在第一种情况下进行全表扫描吗?
我也遇到这个问题了。如果没有查询配置文件中的一些信息,就很难确切地知道查询发生了什么。然而,当我遇到这个问题时,WHERE 子句中的 OR 几乎就像笛卡尔连接一样。因为我正在相互比较两个不同表中的列(类似于联接),所以查询似乎是将一个表中的值与另一个表中的所有值进行比较(类似于像 the这篇文章中有一个)。我通过将表格合并在一起解决了这个问题:
SELECT 1
FROM tableA_CDC a_cdc
WHERE a.column1 = a_cdc.column1
AND a.column2 = a_cdc.column2
AND a.column3 = a_cdc.column3
UNION ALL
SELECT 1
FROM tableA_CDC a_cdc
WHERE a.column1 = a_cdc.column1
AND a.column2 = a_cdc.column2
AND a.column3 IS NULL AND a_cdc.column3 IS NULL
这极大地改善了我自己的查询,并且它反映了我上面共享的链接(以及许多其他链接)中的答案。
另外,只要想到这个表的功能,当我想到检查表更新时,我总是会想到streams。不确定您对它们有多熟悉,但根据您要使用这些更新执行的操作,我强烈推荐流和任务。