提问人:Johannes 提问时间:11/7/2023 更新时间:11/8/2023 访问量:76
Oracle ORA_HASH功能。结果会是恒定的吗?[复制]
Oracle ORA_HASH function. Will the results be constant? [duplicate]
问:
我们要求为ERP系统中的多个表提供唯一的(每个表)NUMERIC ID,因为与第三方系统的接口需要它。这些预言机表(包括 Objid)中的键通常是 Varchar2。如果可以阻止,我不想在 20+ 表中创建新列,所以我想知道ORA_HASH是否可以解决问题。
我的问题是: 如果我运行例如
Select ora_hash(order_no || release_no || line_no) from purchase_order_line
随着表中数据的变化,我是否总是为某个order_no获得相同的哈希值 ||release_no ||line_no组合?或者,如果表中的整体数据发生变化,则该哈希值在不同时间会有所不同。如果哈希值保持不变,我可以将其限制为第 3 方系统要求的 bigint 的最大大小,并始终为特定组合获得相同的唯一值,对吧?我的思路有什么问题吗? 如果我们切换到一个新的数据库,迁移我们所有的数据,会发生什么。我强烈认为,每次组合,我们会得到不同的数据集,对吧?
表中的行数不会超过 BIGINT 的最大值。
我在表中添加和删除数据时多次尝试查询,它总是返回相同的哈希值。
Select ora_hash(order_no || release_no || line_no) from purchase_order_line
我还快速检查了几个包含更多数据的表,我们似乎在主键上没有冲突。
答:
ora_hash可能会导致一些碰撞。最好使用standard_hash。这将返回原始数据,但不太可能发生冲突。而且,如果你对列的串联进行哈希处理,最好做类似 standard_hash(order_no ||'|'||release_no ||'|'||line_no,“MD5”)。将串联与 |以避免混淆,例如'ab'||'c' 给出与 'a'||' 相同的结果公元前'。
您需要向表添加唯一的数字 ID,并且您希望避免这种情况,因为您的表已经具有唯一的 ID,尽管是字母数字。您正在寻找一种方法来获取确定性数字 ID。
根据这些 ID 中允许的不同字符数以及这些 ID 可以变成多长时间,以下 PL/SQL 函数可能足以从字母数字 ID 获取到数字 ID。
CREATE OR REPLACE FUNCTION get_unique_id(p_objid VARCHAR2) RETURN INTEGER DETERMINISTIC
IS
PRAGMA UDF;
v_allowed VARCHAR2(4000) := 'ABCDEDGIJKLMNOPQRSTUVWXYZ1234567890';
v_factor INTEGER := 1;
v_result INTEGER := 0;
BEGIN
FOR i IN 1 .. LENGTHC(p_objid) LOOP
v_result := v_result + INSTRC(v_allowed, SUBSTRC(p_objid, i, 1)) * v_factor;
v_factor := v_factor * (LENGTHC(v_allowed) + 1);
END LOOP;
RETURN v_result;
END get_unique_id;
毕竟这很简单。您有一串允许的字符,用于从目标字符转换为数字。
假设允许有 99 个字符。objid 中的第一个字符将获得 1 到 99 之间的值,具体取决于其在允许的字符串中的位置。下一个字符将获得一个从 1 到 99 乘以 100 的值。等等。所有这些值的总和就是生成的数字 ID。 (当然,如果您觉得这更直观,则可以从右到左运行您的objid字符串。
如何测试功能:
select get_unique_id('0000000000') from dual;
将“00000000000”更改为对象中允许的最大字符数和v_allowed中最后一个允许字符的字符串。你得到结果还是异常?生成的数字是否太大,是否小到足以满足要求?
最后,看看(docs.oracle.com/../ORA_HASH.html)的文档:ORA_HASH
ORA_HASH(expr [,max_bucket])
expr 表示的数据长度没有限制
可选的 max_bucket 参数确定哈希函数返回的最大存储桶值。您可以指定介于 0 和 4294967295 之间的任何值。默认值为 4294967295。
这意味着输入值的数量不受限制,生成的哈希值数量有限。换句话说,不同的输入可以产生相同的输出。因此,您不能将此功能用于您的目的。对于您能找到的每个通用哈希函数也是如此。只有当编写哈希函数来为一组已知的、有限的输入数据生成唯一的结果时,它才适合您。好吧,在这种情况下,您可以在非泛型哈希函数之上调用我的函数。
关于确定性函数的注释:Oracle 知道明确声明为确定性的确定性函数,就像我声明我的函数一样。这些函数保证返回确定性结果,即相同的输入值始终具有相同的输出值。因此,如果是确定性的,这意味着当您在 Oracle 版本中使用它时,只要您使用相同的输入调用它,它就会可靠地产生相同的输出。无论您的 Oracle 版本是 12c、19c、21c 还是其他版本,都无关紧要。但是,不能保证 Oracle 永远不会更改算法。因此,虽然该函数在 Oracle 12c 中可能是确定性的,在 21c 中仍然是确定性的,但不能保证这两个版本会产生相同的结果。因此,除非 Oracle 明确说明,否则不能保证该函数在数据库版本之间具有确定性。ORA_HASH
评论
ora_hash('ABC' || 'DEF' || 'GHI')
将与 相同。这似乎是实现哈希的糟糕方法。ora_hash('A' || 'BCD' || 'EFGHI')
to_number ( sys_guid(), 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' )
ORA_HASH
dbms_crypto.hash
STANDARD_HASH
SHA1