首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ORA_HASH函数所使用的算法是什么?

ORA_HASH函数所使用的算法是什么?
EN

Stack Overflow用户
提问于 2017-08-29 21:01:48
回答 2查看 14.5K关注 0票数 18

在我正在开发的应用程序中,我遇到了一些代码,这些代码使数据库调用仅仅是为了调用UUID字符串上的ORA_HASH函数(文档)。之所以这样做,是因为它需要对另一个似乎使用ORA_HASH进行分区的系统进行服务调用。

我想知道ORA_HASH使用的算法,这样我就可以重新实现它,以便对无法访问真正数据库的应用程序进行类似的服务调用,更不用说Oracle了。到目前为止,我只找到了相当于Oracle API文档的内容。

非常清楚:,我需要克隆ORA_HASH,因为这是我无法控制的另一个系统所使用的,我需要与该系统集成。是的,如果能使用一个真正标准的算法,比如MD5,那就太好了,但是我做不到,除非这就是ORA_HASH所隐藏的。

除了ORA_HASH之外,建议使用哈希算法的答案或评论是没有帮助的。这个问题是关于ORA_HASH的,而不是一般的散列或分区。

EN

回答 2

Stack Overflow用户

发布于 2017-12-17 13:33:59

另一个似乎使用ORA_HASH的系统

嗯,如果它“似乎使用”,那么做一些反向工程和检查什么是确切的调用和反汇编的函数代码是有意义的。

但是,如果您想深入研究Oracle的内部结构,那么下面的内容可能会有所帮助。

首先,您必须弄清楚调用什么内部C函数。要做到这一点,您可以在一个会话中执行一些长期运行的代码。我确实做了这个

代码语言:javascript
复制
select avg(ora_hash(rownum)) id from
(select rownum from dual connect by rownum <= 1e4),
(select rownum from dual connect by rownum <= 1e4);

它也可以是PL/SQL代码,您只需确保不断调用ora_hash即可。

当它在运行时

我在Windows上进行了测试,看起来ora_hash是ora_hash

现在让我们用谷歌搜索evahash。我们非常幸运,因为官方网站https://oss.oracle.com/projects/ocfs-tools/src/branches/new-dir-format/libocfs/Linux/inc/ocfshash.h上有一个头文件,链接到evahash。

最后是带有实际C代码http://burtleburtle.net/bob/hash/evahash.html的页面

到目前为止,我们还记得,如果我们将外部C函数构建到库(Windows上的DLL)中,就可以在Oracle中使用它。

例如,如果我将函数签名更改为

代码语言:javascript
复制
extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)

它可以从Oracle成功地执行。但是,正如您所看到的,签名与甲骨文中的ora_hash稍有不同。此函数接受值、其长度和initval (可能是种子),而在Oracle中的签名是ora_hash(expr、max_bucket、seed_value)。

让我们试着测试甲骨文

代码语言:javascript
复制
SQL> select ora_hash(utl_raw.cast_to_raw('0'), power(2, 32) - 1, 0) oh1,
  2         ora_hash('0', power(2, 32) - 1, 0) oh2,
  3         ora_hash(0, power(2, 32) - 1, 0) oh3,
  4         ora_hash(chr(0), power(2, 32) - 1, 0) oh4
  5    from dual;

       OH1        OH2        OH3        OH4
---------- ---------- ---------- ----------
3517341953 3517341953 1475158189 4056412421

C

代码语言:javascript
复制
int main()
{
    ub1 ta[] = {0};
    ub1* t = ta;
    cout << hash(t, 1, 0) << endl;
    ub1 ta0[] = {'0'};
    ub1* t0 = ta0;
    cout << hash(t0, 1, 0) << endl;
    return 0;
}

1843378377
4052366646

所有的数字都不符合。那么问题是什么呢?ora_hash接受几乎任何类型的参数(例如,select ora_hash(sys.odcinumberlist(1,2,3)) from dual),而C函数接受值作为字节数组。这意味着在函数调用之前会发生一些转换。因此,在使用上述C哈希函数之前,您必须先了解实际值在传递给它之前是如何转换的。

您可以使用IDA PRO +十六进制射线进行Oracle二进制文件的反向工程,但这可能需要几天时间。更不用说平台的具体细节了。

因此,如果您想模仿ora_hash,最简单的选择是安装Oracle版本并使用它调用ora_hash。

我希望那是有趣的。祝好运。

更新

ora_hash和dbms_utility.get_hash_value可以相互映射(参见散列函数/)

代码语言:javascript
复制
SQL> select dbms_utility.get_hash_value('0', 0 + 1, 1e6 + 1) ha1,
  2         ora_hash('0', 1e6, 0) + 1 ha2
  3    from dual;

       HA1        HA2
---------- ----------
    338437     338437

如果我们打开dbms_utility的包体,我们将看到以下声明

代码语言:javascript
复制
  function get_hash_value(name varchar2, base number, hash_size number)
    return number is
  begin
    return(icd_hash(name, base, hash_size));
  end;

代码语言:javascript
复制
  function icd_hash(name      varchar2,
                    base      binary_integer,
                    hash_size binary_integer) return binary_integer;
  pragma interface(c, icd_hash);

让我们为icd_hash谷歌,我们可以发现它被映射到_psdhsh (https://yurichev.com/blog/50/)。现在是时候拆解oracle.exe并从其中提取_psdhsh的代码了。也许明年我会花点时间在这个问题上。

票数 24
EN

Stack Overflow用户

发布于 2017-12-14 19:03:51

这并没有回答ora_hash后面的实际algo这个OP问题。这只是在pl/sql中使用ora_hash的一个例子(应答@JonHeller注释):

职能:

代码语言:javascript
复制
SQL> create or replace function get_ora_hash(i_str in varchar2, i_max_bucket in number default 4294967295, i_seed number default 0)
return number deterministic
parallel_enable
as
  rv number:= 0;
begin

select ORA_HASH(i_str, i_max_bucket, i_seed) 
into rv 
from dual;

return rv;

end;
Function created.

并使用它:

代码语言:javascript
复制
SQL> declare
  l_val number;
begin
  l_val := get_ora_hash('test');
  dbms_output.put_line(l_val);
end;
 PL/SQL procedure successfully completed.

Dbms输出:

代码语言:javascript
复制
2662839991

您还可以使用RESULT_CACHE或其他技术来加快速度。

已经很快了。例如,在大型表上调用函数100万次:

代码语言:javascript
复制
SQL> set serveroutput on
SQL> declare
  l_val number;
  l_start_dte timestamp;
  l_end_dte timestamp;
  l_interval INTERVAL DAY(9) TO SECOND(9);
  l_cnt number := 0;
begin
  l_start_dte:= systimestamp;
  --for rec in (select object_name from dba_objects)
  for rec in (select name from my_big_table where rownum <= 1000000)
  loop
    l_cnt := l_cnt + 1;
    l_val := get_ora_hash(rec.name);
  end loop;
  l_end_dte:= systimestamp;
  l_interval := l_end_dte - l_start_dte;
  dbms_output.put_line('Rows processed: ' || l_cnt 
    || ', Start: ' || l_start_dte  
    || ', End: ' || l_end_dte 
    || ', Interval: ' || l_interval);
end;
Rows processed: 1000000, Start: 14-DEC-17 02.48.31.138212 PM, End: 14-DEC-17 02.48.41.148884 PM, Interval: +000000000 00:00:10.010672000
 PL/SQL procedure successfully completed.

基本上是每秒100行,包括你可能担心的任何上下文开关。

如果由于性能原因需要复制ORA_HASH,我建议您的性能瓶颈可能在其他地方。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45948266

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档