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 사용자 인 경우 TANEL PODER ( https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack-profiling-from-sqlplus-using-ostackprof/ ostackprof를 사용할 수 있습니다. https://blog.tanelpoder.com/2008/10/31/advanced-oracle-troubleshooting-guide-part-9-process-stack-profiling-from-sqlplus-using-ostackprof/ )
* nix에 있다면 dtrace ( http://www.oracle.com/technetwork/articles/servers-storage-dev/dtrace-on-linux-1956556.html ), 화염 그래프 (사용 시나리오 https://blog.dbi-services.com/oracle-database-multilingual-engine-mle/ )
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를 재현해야하는 경우 성능 병목 현상이 다른 곳에서 발생할 수 있음을 제안합니다.