6 분 소요

최근 SQL 파이프 구문(pipe syntax)을 다시 살펴봤습니다. Google이 먼저 강하게 밀고 있고, BigQuery는 물론 Databricks도 지원하고 있습니다. 겉으로만 보면 꽤 매력적입니다. 특히 복잡한 SQL을 자주 읽고 고쳐야 하는 사람에게는 “왜 진작 이렇게 안 했지” 싶은 순간도 있습니다. SQL이 갑자기 조금 말이 통하는 척하는 느낌도 있습니다.

그런데 결론부터 말하면, 저희 팀은 당장 도입하지 않기로 했습니다.

이 글은 파이프 구문이 왜 편해 보였는지, 기존 복잡한 쿼리가 어떻게 바뀌는지, 유지보수 관점에서 무엇이 좋은지와 무엇이 애매한지, 그리고 결국 왜 지금은 쓰지 않기로 했는지를 정리한 기록입니다.

참고한 공식 자료는 아래입니다.

파이프 구문이 무엇인가

파이프 구문은 SQL을 |> 로 이어 붙여서, 데이터를 한 단계씩 변환하는 흐름으로 읽게 해주는 문법입니다.

전통적인 SQL은 보통 아래처럼 씁니다.

SELECT
  customer_id,
  SUM(amount) AS total_amount
FROM orders
WHERE status = 'paid'
GROUP BY customer_id
HAVING SUM(amount) > 100
ORDER BY total_amount DESC;

파이프 구문에서는 같은 흐름을 아래처럼 적을 수 있습니다.

FROM orders
|> WHERE status = 'paid'
|> AGGREGATE SUM(amount) AS total_amount GROUP BY customer_id
|> WHERE total_amount > 100
|> ORDER BY total_amount DESC;

핵심은 문법 자체보다 읽는 순서 가 달라진다는 점입니다. 전통적인 SQL은 SELECT 부터 시작하지만 실제 데이터는 FROM 에서 옵니다. 그래서 복잡해질수록 사람 머릿속에서는 자꾸 안쪽에서 바깥쪽으로 다시 해석해야 합니다.

반면 파이프 구문은 “어디서 시작해서, 무엇을 거쳐, 어디에 도착하는가”를 위에서 아래로 그대로 읽을 수 있습니다. SQL이 갑자기 데이터 파이프라인처럼 보이기 시작하는 지점이 여기입니다.

왜 편해 보였는가

Google 문서와 블로그에서도 강조하는 장점은 대체로 비슷합니다. 쿼리를 논리적 단계에 따라 위에서 아래로 읽을 수 있고, 각 단계가 self-contained 하다는 점입니다. BigQuery 문서에도 각 pipe operator 는 입력 테이블을 받아 새로운 테이블을 만든다고 설명합니다.
출처: BigQuery pipe syntax reference

제가 봤을 때 체감 장점은 아래 네 가지였습니다.

1. 복잡한 중간 변환이 더 잘 드러납니다

특히 집계, window function, 후속 필터링이 섞인 쿼리에서 장점이 큽니다.

예를 들어 전통적인 SQL에서는 이런 쿼리가 나옵니다.

WITH customer_sales AS (
  SELECT
    customer_id,
    region,
    SUM(amount) AS total_amount,
    COUNT(*) AS order_count
  FROM orders
  WHERE status = 'paid'
  GROUP BY customer_id, region
),
ranked AS (
  SELECT
    customer_id,
    region,
    total_amount,
    order_count,
    RANK() OVER (PARTITION BY region ORDER BY total_amount DESC) AS region_rank
  FROM customer_sales
)
SELECT
  region,
  customer_id,
  total_amount
FROM ranked
WHERE region_rank <= 3;

파이프 구문으로 옮기면 흐름은 아래처럼 읽힙니다.

FROM orders
|> WHERE status = 'paid'
|> AGGREGATE
     SUM(amount) AS total_amount,
     COUNT(*) AS order_count
   GROUP BY customer_id, region
|> EXTEND
     RANK() OVER (
       PARTITION BY region
       ORDER BY total_amount DESC
     ) AS region_rank
|> WHERE region_rank <= 3
|> SELECT region, customer_id, total_amount;

여기서는 중간 CTE가 사라진 것이 중요한 것이 아닙니다. 집계하고, 순위를 붙이고, 상위 3개만 남긴다 는 사고 흐름이 더 직접적으로 보인다는 점이 중요합니다.

2. 쿼리 수정이 조금 덜 괴롭습니다

기존 SQL에서는 중간 단계에 조건 하나 넣거나 컬럼 하나 더 추가하려고 해도 SELECT, GROUP BY, ORDER BY, CTE alias 를 같이 조정해야 할 때가 많습니다.

파이프 구문에서는 보통 해당 단계 근처만 보면 됩니다. 예를 들어 중간에 필터를 하나 더 끼우는 일은 아래처럼 끝나는 경우가 많습니다.

|> WHERE order_count >= 2

이 점은 Google 연구 논문이 이야기하는 readability, writability 개선 포인트와도 맞닿아 있습니다.
출처: SQL Has Problems. We Can Fix Them: Pipe Syntax In SQL

3. 로그 분석이나 단계형 데이터 탐색에 잘 맞습니다

Google도 pipe syntax를 로그 분석과 잘 맞는 흐름으로 설명합니다. 필터링, 필드 확장, 집계, 정렬을 단계적으로 읽을 수 있기 때문입니다.
출처: BigQuery pipe syntax guide

실제로 이런 쿼리는 꽤 잘 어울립니다.

FROM app_logs
|> WHERE log_level = 'ERROR'
|> EXTEND DATE(timestamp) AS event_date
|> AGGREGATE COUNT(*) AS error_count GROUP BY event_date, service_name
|> ORDER BY event_date DESC, error_count DESC;

4. AI가 읽고 생성하기에도 꽤 유리합니다

이건 공식 문서보다 실무 감각에 가까운 이야기입니다. 요즘은 사람이 직접 SQL을 쓰는 것만이 아니라, AI에게 초안을 만들게 하거나 기존 쿼리를 설명하게 하는 경우가 많습니다.

그런데 AI는 단계가 분명한 구조를 꽤 잘 따라갑니다.

  • 시작 테이블이 무엇인지
  • 어느 단계에서 컬럼이 생겼는지
  • 필터가 집계 전인지 후인지
  • 중간 결과가 어떤 shape 인지

이런 것이 위에서 아래로 이어지면 AI가 설명하거나 변환하기가 더 수월합니다. 최소한 SELECT 는 맨 위에 있는데 실제 데이터는 밑에서부터 읽어야 하는 전통 SQL보다는 인지 부하가 낮습니다.

유지보수 관점에서는 어떤가

유지보수는 생각보다 장점이 분명합니다.

좋은 점:

  • 단계별 의미가 잘 드러납니다
  • 중간 로직 삽입 위치가 비교적 명확합니다
  • 중첩 서브쿼리와 CTE 남발을 줄일 수 있습니다
  • 리뷰할 때 “이 단계에서 무엇을 했는가”를 따라가기 쉽습니다

하지만 유지보수는 팀 단위로 봐야 합니다. 여기서부터는 장점만 있는 것이 아닙니다.

단점도 분명합니다

1. 여전히 표준 SQL은 아닙니다

가장 큰 문제입니다. 익숙한 SQL과 닮아 있지만, 어디서나 통하는 문법은 아닙니다.

BigQuery는 공식 지원하고, Databricks도 Databricks SQL / Runtime 16.2+ 에서 지원합니다. 하지만 모든 실행 엔진, 모든 도구, 모든 SQL parser 가 이 문법을 자연스럽게 다루는 것은 아닙니다.
출처:

즉 엔진이 섞인 조직에서는 바로 “팀 표준”으로 가져가기 어렵습니다.

2. 문법 지원 범위와 성숙도가 엔진마다 다릅니다

BigQuery 문서만 봐도 pipe syntax 전반은 지원하지만 일부 기능은 preview 상태이거나 제한이 있습니다. 예를 들어 문서에는 differential privacy clause 관련 제한이 명시돼 있습니다.
출처: BigQuery pipe syntax guide - Limitations

이 말은 곧, “예뻐 보여서 전부 바꾸자”가 아직은 위험할 수 있다는 뜻입니다.

3. 팀의 SQL 독해 기준이 두 벌이 됩니다

기존 SQL도 읽어야 하고, 파이프 구문도 읽어야 합니다. 혼용 기간이 길어질수록 리뷰 규칙과 스타일 가이드도 두 벌이 됩니다.

특히 아래 상황에서는 피로도가 커집니다.

  • 오래된 쿼리는 전통 SQL
  • 새 쿼리는 pipe syntax
  • 일부 엔진은 pipe 가능, 일부는 불가
  • 공용 템플릿과 문서 예시는 아직 전통 SQL

이러면 쿼리 자체는 예뻐질지 몰라도 팀 운영은 덜 예뻐질 수 있습니다.

4. 익숙함의 장벽이 생각보다 큽니다

전통적인 SQL에 익숙한 사람에게는 처음 몇 주간 오히려 더 낯섭니다. SELECT 없이 FROM 으로 시작하는 것부터 심리적 저항이 생깁니다.

이건 시간이 해결해줄 수 있는 문제이긴 합니다. 다만 팀 전체가 같이 넘어갈 만한 가치가 있는지는 별도 판단이 필요합니다. 새 문법은 늘 멋져 보이지만, 팀 전체가 멋져지는 속도는 보통 문법 발표 속도보다 느립니다.

결국 저희 팀이 지금은 쓰지 않기로 한 이유

파이프 구문이 별로여서가 아닙니다. 오히려 꽤 좋아 보였습니다. 그런데 실무적으로는 아직 얻는 것보다 맞춰야 할 것이 더 많다고 판단했습니다. 보기 좋은 문법 하나 들어왔다고 팀의 SQL 품질이 자동으로 좋아지지는 않았습니다. 그런 버튼은 아직 못 봤습니다.

저희 팀이 당장 도입하지 않기로 한 이유는 대략 아래와 같습니다.

1. 실행 엔진과 도구 체인이 완전히 하나가 아닙니다

팀에서 다루는 SQL이 항상 하나의 엔진에서만 끝나지 않습니다. 쿼리가 BigQuery에서만 사는 것도 아니고, 변환/리뷰/문서화/이관 흐름까지 같이 봐야 합니다.

이런 상황에서 특정 엔진이 강하게 지원하는 문법을 팀 공통 표준으로 바로 올리면 portability 가 떨어집니다.

2. 리뷰 비용이 당장은 더 커집니다

저희 팀 기준으로는 아직 전통 SQL에 익숙한 사람이 훨씬 많습니다. 이 상황에서 일부만 pipe syntax를 쓰기 시작하면, 작성자 생산성보다 리뷰어 피로도가 먼저 올라갈 가능성이 큽니다.

특히 데이터팀 SQL은 “한 사람이 쓰고 끝”이 아니라, 나중에 다른 사람이 읽고 수정하고 운영해야 합니다. 팀의 평균 독해 비용을 낮추는 쪽이 우선이었습니다.

3. 스타일 표준을 다시 정해야 합니다

파이프 구문을 쓰기 시작하면 아래를 새로 정해야 합니다.

  • 언제 pipe syntax를 허용할지
  • 표준 SQL과 혼용을 어디까지 허용할지
  • CTE와 pipe를 같이 쓸 때 기준은 무엇인지
  • 리뷰 기준은 어떻게 가져갈지

즉 문법 하나 들여오는 문제가 아니라, 팀 SQL 스타일 가이드를 한 번 더 정비해야 하는 문제로 커집니다.

4. 지금 팀의 병목은 문법보다 모델링과 검증에 더 가깝습니다

솔직히 말하면 지금 저희 팀의 더 큰 문제는 SELECT-FROM-WHERE 순서가 아닙니다.

  • 같은 지표를 여러 곳에서 다르게 계산하는 문제
  • 모델 계층이 모호한 문제
  • 검증 쿼리가 부족한 문제
  • 리뷰 기준이 들쭉날쭉한 문제

이런 것이 더 큽니다. 이런 상태에서 문법만 바꾸면 SQL이 조금 예뻐질 수는 있어도, 운영 품질이 바로 좋아지지는 않습니다.

그래서 결론은

SQL 파이프 구문은 분명 좋은 아이디어라고 생각합니다. 특히 복잡한 변환을 단계형으로 읽어야 하는 환경에서는 실제로 더 읽기 쉽고, AI가 다루기에도 꽤 유리합니다.

다만 지금 저희 팀에서는 아직 “좋은 아이디어”와 “팀 표준으로 채택할 시점” 사이에 거리가 조금 있습니다.

결론은 단순합니다.

  • 개인적으로는 관심 있게 계속 볼 만한 문법입니다
  • 일부 실험 쿼리나 개인 탐색에는 충분히 써볼 만합니다
  • 하지만 팀 공용 SQL 표준으로는 아직 이르다고 판단했습니다

즉 파이프 구문이 틀려서 안 쓰는 것이 아니라, 지금 팀의 운영 맥락에서는 아직 이익보다 전환 비용이 더 크다 고 본 것입니다.

댓글 남기기

스팸 방지를 위해 짧은 시간에 반복 등록은 제한됩니다.

댓글 목록

관리자 보기