12.7.1 비결정적 함수(RAND, NOW 등)가 포함된 쿼리의 검증 불가 문제 해결
“오늘 날짜를 기준으로 최근 3일 이내에 시스템에 가입한 유저를 출력해 줘.” 또는 “이벤트 풀에서 임의의 직원 3명을 무작위로 추첨해 줘.”
이러한 자연어 프롬프트는 엔터프라이즈 비즈니스 환경에서 매일같이 숨 쉬듯 쏟아지는 극히 정상적이고 필수적인 질의 요구사항이다. 이 난제를 풀기 위해 위대한 AI 모델 에이전트와 휴먼 정답(Golden) 쿼리 작성자는 모두 필연적으로, 관계형 데이터베이스 엔진이 제공하는 현재 시간 시계열(NOW(), CURRENT_DATE, SYSDATE)이나 난수 생성기(RAND(), RANDOM())와 같은 **‘특권적 비결정적 내장 함수(Privileged Nondeterministic Function)’**를 쿼리 내부에 의존적으로 호출하게 된다.
하지만 편리해 보이는 이 작고 귀여운 내장 함수들은, 모든 튜플이 1비트의 오차도 없이 동일해야만 진리(Match=1)를 선고하는 ‘실행 기반(Execution-based) 채점 오라클’ 시스템에게는 악몽의 사신(Reaper)과도 같다.
골든 정답 쿼리가 먼저 실행되었을 때 엔진이 찍어낸 NOW()의 타임스탬프 값과, 아주 미세한 0.1초의 통신 딜레이(Delay) 뒤에 AI 예측 쿼리가 실행되면서 평가된 NOW()의 타임스탬프 밀리초(ms) 값은 물리적으로 영원히 다를 수밖에 없다. 또한, 난수(RAND()) 함수를 포함해 LIMIT를 걸어버린 쿼리는 본질적으로 평가 스레드를 돌릴 때마다 파이프라인에 매번 다른 튜플(Tuple) 집합을 제멋대로 뱉어낸다.
오라클의 차원 정규화 모듈이 아무리 훌륭하게 작동한다고 한들, 이 근본적이고 태생적인 ’결괏값의 비결정적 붕괴’는 두 텐서 간의 완벽한 해시 불일치를 야기하며 영구적인 “오검증 기각(False Negative)“의 패널티 늪으로 벤치마크를 끌고 간다.
1. 쿼리 AST 트랜스파일링(Transpiling)을 통한 함수 강제 치환 (Monkey Patching)
이 지독한 시간과 난수의 상대성 모순을 가장 우아하고 공학적으로 해결하는 베스트 프랙티스(Best Practice)는, 문제의 쿼리 문자열이 커넥터를 타고 샌드박스의 파서(Parser)로 넘어가기 바로 직전에, 파이썬 L7 계층의 오픈소스 구문 파서(sqlglot)를 이용하여 비결정적 함수 단위의 AST(추상 구문 트리) 노드만을 정밀하게 찾아내어, 이를 “절대 불변의 결정론적 상숫값“으로 하드코딩해 덮어 씌우는 AST 몽키 패칭(Monkey Patching) 트랜스파일링 기법이다.
- 시계열(Time)의 동결 패치:
NOW(),CURRENT_TIMESTAMP,TODAY()같은 날짜 함수 트리가 파싱되는 순간, 이를 오라클 마스터 시스템이 글로벌하게 선언해 둔 고정 텍스트(예:'2025-01-01 12:00:00.000') 스칼라 노드로 전역 강제 랩핑(Wrapping) 치환한다. - 난수(Random)의 고착화 패치:
RAND(),RANDOM()같은 난수 호출 트리는 단순한 정수 상수 트리0.42또는 고정 변수0.5등으로 철저히 짓눌러 교체한다.
이 무자비한 치환 과정(Mutation)을 거쳐 텍스트로 재조립된 쿼리들을 데이터베이스 하단으로 내려보내면, 오라클 시스템은 AI 모델이 시간이나 난수 함수 구문을 문법적, 의미론적으로 정확하고 적절한 뎁스(Depth)에 배치했는지는 온전히 평가하고 인정해 주면서도, 그 쿼리들이 추출해 낸 최종 결과 텐서 덩어리만큼은 완벽하게 동결(Freeze)된 가상의 시공간(Mocked Space) 안에서 100%의 멱등성(Idempotency)을 지닌 채 동일하게 반환되도록 엔진을 통제할 수 있게 된다.
2. 시드(Seed) 동기화 불능 시 타겟 컬럼 델타(Delta) 묵살 처리 (Agnostic Masking)
하지만 현실 세계는 가혹하다. 때로는 트랜스파일링(Transpiling) 엔진조차 인식하지 못하는 오라클 DB(Oracle Database) 특유의 극도로 파편화된 독자적 난수 함수 호출 패키지(DBMS_RANDOM.VALUE)를 쓰거나, UUID 자동 발급처럼 내부 트리거나 프로시저 함수 단위에서 시간 인덱스 시드(Seed)를 먹고 돌아가는 복잡한 레거시 쿼리들이 존재한다. 이 경우 AST의 노드 단 몇 개를 치환하는 것만으로는 텐서의 비결정성을 영구히 잡을 수 없다.
이 최악의 상황이 도래했을 때는, 샌드박스에서 뽑혀 올라온 원시 결과 텐서가 파이썬 메모리로 들어온 직후의 1차원 데이터 랭글링(Wrangling) 단계에서 마스킹(Masking)을 씌워야 한다. 정답 텐서와 예측 텐서 양측 프레임(DataFrame)에서 “값이 매번 런타임마다 변하는 것으로 오라클 환경 메타데이터에 사전에 정의 및 레이블링(Labeling)된 특정 타겟 컬럼” 전체의 데이터를, 의미 없는 범용 블라인드 상수 __IGNORE_DELTA_VAL__ 로 덮어 씌워버리는 폭력적인 스와핑(Swapping) 처리를 수행하는 것이다.
이 가차 없는 ‘결정성 차폐’ 방어 기법을 통해, 위대한 오라클은 텐서를 구성하는 다른 나머지 중요 비즈니스 컬럼들의 집합 동등성(Set Equality)은 여전히 1비트 단위로 엄밀하고 잔인하게 채점하면서도, 어쩔 수 없이 비결정성을 유발하는 그 저주받은 일부 열(Column)에 대해서만 비교 연산 대상에서 현명하게 제외(Agnostic)시키는 고도의 채점 유연성(Flexibility)을 인프라 레벨에서 확보하게 되는 것이다.