oracle - ORA_HASH 함수가 사용하는 알고리즘은 무엇입니까?




algorithm plsql (2)

나는 ORA_HASH 문자열에서 ORA_HASH 함수 ( ORA_HASH )를 호출하기 위해 데이터베이스 호출을 만드는 애플리케이션에서 일부 코드를 발견했다. 이 작업을 수행하는 이유는 분할을 위해 ORA_HASH 를 사용하는 것으로 보이는 다른 시스템에 대한 서비스 호출을 작성하는 값이 필요하기 ORA_HASH 입니다.

ORA_HASH 사용하는 알고리즘을 알고 싶습니다. 그래서 Oracle을 혼자 내버려 두지 않고 실제 데이터베이스에 대한 액세스 권한이없는 응용 프로그램에 대한 유사한 서비스 호출을 다시 구현할 수 있습니다. 지금까지 오라클 API 문서의 내용을 파악할 수있었습니다.

단지 매우 명료하게하기 위해서 : 나는 ORA_HASH 를 복제 할 필요가 있습니다. 왜냐하면 그것은 제 제어 시스템이 사용하지 않는 다른 시스템이고, 나는 그 시스템과 통합해야하기 때문입니다. 예, MD5와 같은 표준 알고리즘을 사용할 수 있다면 좋겠지 만, ORA_HASH 가 커버하지 않는 한 그렇게 할 수 없습니다.

ORA_HASH 이외에 해쉬 알고리즘의 사용을 제안하는 답변이나 의견은 도움이되지 않습니다. 이 질문은 특히 해시 또는 일반적으로 파티셔닝이 아닌 ORA_HASH 에 관한 ORA_HASH 입니다.


ORA_HASH를 사용하는 다른 시스템

글쎄, "사용하는 것"이라면 리버스 엔지니어링을 조금 해보고 정확히 무엇이 호출되는지 확인하고 함수의 코드를 분해하십시오.

그러나 Oracle 내부로 들어가기를 원한다면 다음과 같이하십시오.

우선, 내부 C 함수가 호출되는 것을 알아 내야합니다. 이를 위해 한 세션에서 장기 실행 코드를 실행할 수 있습니다. 나는 이것을 실행했다.

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가 ...-> evaopn2 () -> evahash () -> ... 인 것 같습니다.

이제 evahash에 대한 Google하자. 공식 사이트 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

지금까지 우리가 라이브러리 (Windows에서는 DLL)에 빌드하면 오라클에서 외부 C 함수를 사용할 수 있음을 기억합니다.

예를 들어 함수 서명을로 변경하면 Win x64에 표시됩니다.

extern "C" ub4 hash( ub1 *k, ub4 length, ub4 initval)

Oracle에서 성공적으로 실행할 수 있습니다. 그러나 보시다시피, 서명은 오라클의 ora_hash와 조금 다릅니다. 이 함수는 값, 길이, initval (seed가 될 수 있음)을 받아들입니다. Oracle의 서명은 ora_hash (expr, max_bucket, seed_value)입니다.

오라클 테스트를 해보 죠.

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

기음

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 + 16 진법을 사용하여 Oracle 바이너리의 리버스 엔지니어링을 진행할 수 있지만 며칠이 소요될 수 있습니다. 플랫폼 특정 세부 사항은 말할 것도 없습니다.

따라서 ora_hash를 모방하고 싶다면 오라클 익스프레스 에디션을 설치하고 ora_hash를 호출하는 것이 가장 쉬운 옵션 일 것입니다.

재미 있었으면 좋겠다. 행운을 빕니다.

최신 정보

ora_hash와 dbms_utility.get_hash_value는 서로 맵핑 될 수 있습니다 ( https://jonathanlewis.wordpress.com/2009/11/21/ora_hash-function/ )

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의 패키지 본문을 언랩하면 다음과 같은 선언이 표시됩니다.

  function get_hash_value(name varchar2, base number, hash_size number)
    return number is
  begin
    return(icd_hash(name, base, hash_size));
  end;

  function icd_hash(name      varchar2,
                    base      binary_integer,
                    hash_size binary_integer) return binary_integer;
  pragma interface(c, icd_hash);

icd_hash 대해 google을 사용하면 _psdhsh ( https://yurichev.com/blog/50/ )에 매핑 된 것을 알 수 있습니다. 이제 oracle.exe를 분해하고 _psdhsh에 대한 코드를 추출하십시오. 아마 내년에 시간을 보낼 것입니다.


이것은 ora_hash 뒤에있는 실제 알 고의 OP 질문에 대답하지 않습니다. 이것은 pl / sql에서 ora_hash를 사용하는 예입니다 (@JonHeller 주석에 응답).

함수:

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.

그리고 그것을 사용 :

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 출력 :

2662839991

RESULT_CACHE 또는 다른 기술을 사용하여 더 빠르게 작업을 진행할 수도 있습니다.

그것의 아주 빠른 이미. 예를 들어, 큰 테이블에서 함수를 1 백만 번 호출하면 다음과 같습니다.

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,000 개의 행이 있습니다. 여기에는 걱정할만한 모든 컨텍스트 스위치가 포함됩니다.

성능으로 인해 ORA_HASH를 재현해야하는 경우 성능 병목 현상이 다른 곳에서 발생할 수 있음을 제안합니다.







database-partitioning