在合并语句中使用哈希键作为比较列

sno*_*ser 3 hash snowflake-cloud-data-platform

我必须在雪花数据库中实现合并语句。Target 表中将有超过 60 亿行。比较起来有 20 多个列。我想HASH在 Snowflake 中的所有 20 列的基础上使用函数生成哈希键。但我阅读了文档哈希,其中提到在 40 亿行之后,可能会获得重复的哈希键。我的理解正确吗?那么我应该避免使用哈希键来比较记录并使用所有列吗?或者可以使用md5hexa 128 位或任何定制的哈希函数。请建议。

在此输入图像描述

Gre*_*lik 5

TL;DR 版本:根据您的行数,使用 HASH 函数使两行的哈希值发生冲突的可能性为 62%。使用 MD5 代替 HASH 会将发生冲突的几率降低到百分之几。在相同大小的仓库中,计算 MD5 而不是哈希值将需要大约 24% 的时间。建议:如果无法容忍非常罕见的冲突,请在 1) MD5 或 2) 哈希和列比较上进行匹配。选项 2 会更快,但如果架构随时间发生变化,则需要更多维护。

在合并中使用哈希的主题值得有自己的立场文件,而且我确信已经写了很多立场文件。我们将重点关注您的具体情况以及 Snowflake 如何响应。

让我们从您引用的文档部分开始。当唯一的输入导致相同的哈希值时,称为冲突。这是数学和计算中的一个经典问题,称为生日问题 ( https://en.wikipedia.org/wiki/Birthday_problem )。关于这个主题的文章有很多,因此我们将坚持与您的情况相关的内容。

如果您在 60 亿行表上使用 64 位哈希,则冲突的概率约为 62%。尽管如此,这仍然是一个可以管理的问题,我们将在稍后探讨。

如果对 60 亿个输入使用 128 位哈希(例如 MD5),则概率四舍五入为零。即使您的表增长到行数的 1000 倍,冲突的概率也将为 0.0000000000053%。

虽然表面上这似乎解决了碰撞问题,但它引入了一个新问题。MD5 函数比哈希函数的计算成本更高。我们可以通过对中型仓库进行一些简单的测试来确定多少。

select count(md5((concat(*)))) 
from "SNOWFLAKE_SAMPLE_DATA"."TPCH_SF10000"."ORDERS"; -- 18m 41s

select count(hash((concat(*)))) 
from "SNOWFLAKE_SAMPLE_DATA"."TPCH_SF10000"."ORDERS"; -- 15m 6s
Run Code Online (Sandbox Code Playgroud)

我使用 count 来消除结果收集时间,但它仍在计算 MD5 和哈希值。MD5 的计算时间比哈希值长约 24%。

这让我们进入了 TL;DR 讨论的最后部分,即使用哈希函数和列比较。这是更快的选项,也是唯一能保证不发生冲突的选项。它更快,因为这个操作是伪代码:

condition1 AND condition2

在此表达式中,如果第一部分失败,则无需测试第二部分。我还没有在 Snowflake 合并匹配子句中对此进行实验测试(尚未),但没有理由在匹配行时测试表达式的第二部分。这样,实际上所有匹配都可以通过比较哈希来快速处理,并且只有非常罕见的情况才需要测试列匹配。

最后一个想法:相对于表的大小,每次合并的行数越少,MD5 的额外计算时间就越不重要。您已经为表中 MD5 值的额外计算时间“付出了代价”。如果您要合并几千行,计算 MD5 的 24% 额外时间是无关紧要的,并且使您不必在 match 子句中维护列列表。