주요 컨텐츠로 이동
제품

SQL 마이그레이션에 대한 오해 해소: 새로운 SQL 기능으로 레이크하우스로의 리프트 앤 시프트를 더 쉽게 만드는 방법

레거시 저장 프로시저를 Databricks로 이전하는 과정을 한 줄씩 자세히 살펴봅니다. 데이터 웨어하우스 마이그레이션의 일환으로 커서, 임시 테이블, 다중 문 트랜잭션이 모두 SQL 형태로 이전됩니다.

작성자: Abhishek Dey , 로랑 레튀르제

  • 커서는 매일 밤 실행되도록 예약된 프로시저에 존재합니다. 아무도 문서화하지 않은 임시 테이블, 그리고 세 개의 업데이트를 하나로 묶어 하나라도 실패하면 롤백하는 트랜잭션까지, 이 모든 것이 이제 한 줄 한 줄 그대로 마이그레이션됩니다.
  • 프로시저를 새로 작성할 필요 없이 그대로 번역하면 됩니다. PL/SQL은 동일한 비즈니스 로직, 동일한 제어 흐름, 동일한 SQL 팀을 유지하면서 Databricks SQL Scripting으로 하나씩 매핑됩니다.
  • 최종적으로 프로시저는 데이터 계보(lineage) 및 액세스 제어 기능과 함께 Unity Catalog에 저장되어, 기존 스키마에는 없었던 강력한 거버넌스를 제공합니다.

여러분의 데이터 웨어하우스 어딘가에서는 매일 밤 수백 개의 저장 프로시저가 실행되어 비즈니스를 묵묵히 운영하고 있습니다. 이 프로시저들은 이미 오래전에 회사를 떠난 SQL 개발자들이 수년 전에 작성한 것입니다. 여기에는 중첩된 커서가 있고, 즉석에서 임시 테이블을 생성하며, 여러 테이블에 걸친 업데이트를 단일 트랜잭션으로 묶어 처리합니다. 그리고 47번째 줄 부근에는 단순히 “이 부분을 수정하지 마시오.” 라고 적힌 주석이 있습니다. 이제는 아무도 이 프로시저들을 완전히 이해하지 못합니다. 하지만 모두가 여기에 의존하고 있죠. 매출 대시보드, 재무 마감, 운영 보고서 등 모든 것이 어떻게든 이 절차적 SQL 비즈니스 로직 레이어로 거슬러 올라갑니다.

데이터를 레이크하우스로 이동하는 방법은 이미 잘 알려져 있습니다. 걸림돌이 되었던 것은 데이터 웨어하우스 마이그레이션의 핵심인 절차적 요소들이었습니다. 즉, 저장 프로시저, 트랜잭션 처리, 임시 테이블, 제어 흐름, 그리고 여전히 많은 기업이 SQL 기술을 기반으로 운영된다는 사실입니다. 마이그레이션 이야기가 나올 때마다 사람들은 가장 먼저 이 프로시저들을 가리키며 이렇게 말했습니다. “최소한의 변경만으로 이를 실행할 수 있을 때까지는 이전할 수 없습니다. 우리 기업은 여전히 SQL 중심으로 운영되고 있으니까요.”

그래서 저희는 여러분이 지금 바로 떠올리실 만한 유스케이스, 즉 여러 마이그레이션 과정에서 흔히 볼 수 있었던 복합 프로시저를 예로 들어 레이크하우스에서 단계별로 어떻게 작동하는지 보여드리기로 했습니다. 이 예시는 Oracle 마이그레이션 유스케이스를 기반으로 하지만, 레거시든 클라우드 기반이든 모든 데이터 웨어하우스에 적용할 수 있습니다. 

기존 비즈니스 로직 살펴보기

이 예시 프로시저는 일별 주문을 처리합니다. 처리되지 않은 주문을 임시 테이블에 스테이징하고, 고객 마스터를 기준으로 유효성을 검사하며, 실패 건을 루프하면서 각 거부 건을 개별적으로 기록한 다음, 지역별 매출 요약을 업데이트하고 모든 주문을 처리됨으로 표시합니다. 이 모든 과정은 실패 시 롤백되는 단일 트랜잭션 내에서 이루어집니다.

절대 중단되어서는 안 되는 야간 작업 하나.

이전에는 이를 마이그레이션하려면 Python과 Spark로 완전히 새로 작성해야 했습니다. 수 주일의 작업이 필요했고, 새로운 버그를 찾아내야 했으며, SQL 팀은 더 이상 자신들의 비즈니스 로직을 유지 관리할 수 없게 되었습니다.

저희는 코드를 재작성하지 않았습니다. 그대로 전환했습니다.

이제 Databricks에서 기반 다지기

모든 프로시저는 시그니처와 안전장치로 시작합니다. 레거시 시스템에서는 본문을 BEGIN ... EXCEPTION ... END 로 감쌌습니다. Databricks는 대신 DECLARE EXIT HANDLER FOR SQLEXCEPTION 을 사용합니다. 개념은 같지만 구문이 약간 다릅니다. 세션에 적절한 카탈로그와 스키마가 설정되어 있다고 가정해 보겠습니다.

가장 큰 차이점은 코드에 있지 않습니다. 바로 배포 후에 일어나는 일에 있습니다. Databricks에서는 프로시저가 Unity Catalog에 등록됩니다. 이를 통해 모든 워크스페이스에서 액세스 제어, 열 수준 계보(lineage), 검색 가능성을 확보하게 됩니다. 기존 시스템에서는 단 세 명만 비밀번호를 알고 있는 스키마에 갇혀 있었습니다.

레거시

Databricks

CREATE OR REPLACE PROCEDURE name IS

CREATE OR REPLACE PROCEDURE [IF NOT EXISTS] <catalog>.<schema>.<procedure_name> ( [ procedure_parameter [, ...] ] )

   [ characteristic [...] ]

LANGUAGE SQL 

SQL SECURITY { INVOKER | DEFINER }

AS BEGIN

v_id NUMBER; BEGIN 이전

DECLARE v_id INT; BEGIN 내부

EXCEPTION WHEN OTHERS THEN

DECLARE EXIT HANDLER FOR SQLEXCEPTION

참고: docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-ddl-create-procedure

그다음으로 임시 테이블을 처리했습니다. 데이터 웨어하우스 마이그레이션에서 가장 쉽게 해결할 수 있는 부분이었죠.

기존 프로시저는 스테이징 및 검증 실패를 위해 두 개의 임시 테이블을 생성합니다. 이 테이블들은 나머지 로직이 의존하는 임시 작업 공간 역할을 합니다.

Databricks에서는 이 작업이 마이그레이션에서 가장 간단한 부분 중 하나가 됩니다. EXECUTE IMMEDIATE도, ON COMMIT PRESERVE ROWS도 필요 없습니다. 세션 범위의 CREATE TEMP TABLE이 이를 직접 대체하며, 한 가지 작은 주의 사항이 있습니다. CREATE OR REPLACE TEMP TABLE은 아직 지원되지 않으므로 동일한 세션에서 다시 실행해야 하는 경우 먼저 drop해야 합니다.

참고: docs.databricks.com/aws/en/tables/temporary-tables

커서가 까다로운 부분이었습니다. 적어도 저희는 그렇게 생각했죠.

이 부분은 모두가 새로 작성해야 할 것이라고 예상했던 부분이었습니다. 기존 프로시저는 검증 실패를 하나씩 루프하며 잘못된 주문을 거부하고 그 사유를 기록합니다. 전형적인 커서 패턴이자, 수십 년간 축적된 레거시(예: Oracle)의 습관이죠.

Databricks의 SQL 스크립팅은 런타임 18.1부터 OPEN, FETCH, CLOSE 커서를 기본적으로 지원합니다. %NOTFOUND 속성은 CONTINUE HANDLER FOR NOT FOUND로 변경됩니다. 루프 레이블과 LEAVE EXIT WHEN을 대체합니다.

스크립팅 로직은 아주 수월했습니다

처리할 행이 없으면 건너뛰고 기록하는 조건부 검사는 거의 바뀌지 않았습니다. SELECT ... INTO SET var = (SELECT ...)로 변경됩니다. 그 외의 모든 것은 동일합니다.

저희 SQL 스크립팅은 IF/ELSE, WHILE, FOR, LOOP, REPEAT, LEAVE, ITERATE, SIGNAL/RESIGNAL 등 전체 절차적 도구 키트를 지원합니다. 코드베이스에 .GOTO 및 .LABEL 지시어가 포함된 Teradata BTEQ 스크립트가 있는 경우, LEAVE 및 ITERATE를 사용하는 레이블이 지정된 루프로 매핑됩니다.

참고: docs.databricks.com/aws/en/sql/language-manual/sql-ref-scripting

트랜잭션을 처리하면서 마이그레이션이 비로소 실감 났습니다

이것이 마이그레이션을 실제로 가능하게 만든 마지막 조각이었습니다. 기존 프로시저는 regional_revenue를 업데이트하고, 주문을 처리됨으로 표시하며, 배치를 기록합니다. 어느 한 부분이라도 실패하면 모든 것이 롤백됩니다.

레거시 시스템에서 이는 명시적 COMMIT이 있는 암시적 트랜잭션입니다. Databricks에서는 BEGIN ATOMIC ... END가 동일한 의미 체계(성공 시 자동 커밋, 실패 시 자동 롤백)를 제공하며, 행 수준 충돌 감지라는 한 가지 중요한 이점이 있습니다. 동일한 테이블에 쓰는 동시 배치는 동일한 행을 건드릴 때만 충돌합니다. 예를 들어, Oracle과 Snowflake는 모두 테이블 수준 잠금을 사용하여 순차적 실행을 강제합니다.

MERGE 문은 그대로 Databricks로 마이그레이션할 수 있습니다. BEGIN ATOMIC이 이를 처리하므로 명시적인 COMMIT은 사라졌습니다. 그리고 팀은 동시 배치 작업이 서로 충돌하는 것에 대해 더 이상 걱정하지 않게 되었습니다.

이 패턴을 도입할 때 유용한 두 가지 참고 사항은 다음과 같습니다.

  • 원자적 블록(atomic block) 내에 정의된 모든 테이블은 catalogManaged 테이블 기능이 활성화되어 있어야 합니다. 기존 Delta 테이블에서 바로 활성화할 수 있습니다: ALTER TABLE <name> SET TBLPROPERTIES('delta.feature.catalogManaged'= 'supported');
  • BEGIN ATOMIC은 SQL 스크립트, 노트북 셀 또는 SQL 작업 태스크의 최상위 수준에 위치해야 합니다. 

참고: docs.databricks.com/aws/en/transactions/

마이그레이션이 완료된 전체 프로시저

동일한 비즈니스 로직, 동일한 제어 흐름이 Unity Catalog에 의해 제어됩니다. 

트랜잭션 내부에서 실행하려면 호출을 다음과 같이 감싸세요:

배운 점

이러한 프로그램의 마이그레이션 일정은 무거운 PL/SQL 패키지 종속성이 있는 복잡한 저장 프로시저의 경우에도 50~75%까지 단축될 수 있습니다. 이러한 효율성은 원래의 비즈니스 로직을 보존하는 기계적 변환 프로세스 덕분이며, 이를 통해 SQL 팀은 유지 관리 작업을 원활하게 계속할 수 있습니다. 마이그레이션 자체를 넘어, 팀은 강력한 새로운 이점을 얻게 됩니다. 바로 동일한 거버넌스 데이터가 대시보드, 머신러닝 모델 및 AI 이니셔티브에 동력을 공급하는 통합 플랫폼입니다.

프로시저가 제대로 변환되는지 확인하는 유일한 방법은 직접 시도해 보는 것입니다. 배치에서 가장 작은 저장 프로시저를 선택하세요. 가급적 아무도 디버깅하고 싶어 하지 않는 프로시저가 좋습니다. 워크스페이스에 마이그레이션 프로젝트를 생성하고 Agentic Code Convertor를 시작해 보세요!

(이 글은 AI의 도움을 받아 번역되었습니다. 원문이 궁금하시다면 여기를 클릭해 주세요)

최신 게시물을 이메일로 받아보세요

블로그를 구독하고 최신 게시물을 이메일로 받아보세요.