MSSQL 기반 애플리케이션의 ClickHouse 전환
MSSQL 기반 애플리케이션의 ClickHouse 전환

MSSQL 기반 애플리케이션의 ClickHouse 전환

ClickHouse 분류
Competition
Type
Introduction
작성자

Ken

본 문서는 Microsoft SQL Server(MSSQL) 기반으로 개발된 분석 애플리케이션을 ClickHouse로 전환할 때 필요한 쿼리 변환 사항을 정리한 가이드입니다.

  • 개요
  • 1. 연결 방식
  • 2. 데이터 타입 매핑
  • 3. 기본 구문 변환
  • 4. 문자열 함수 변환
  • 5. 날짜/시간 함수 변환
  • 6. NULL 처리
  • 7. 조건문
  • 8. 집계 함수
  • 9. 윈도우 함수
  • 10. CTE (Common Table Expression)
  • 11. PIVOT 변환
  • 12. 타입 변환
  • 13. 기타 변환 사항
  • 14. 주의사항
  • 15. 마이그레이션 체크리스트
  • 16. 결론

개요

ClickHouse는 ODBC/JDBC 드라이버를 공식 지원하므로, 기존 MSSQL 연결 방식을 사용하던 애플리케이션에서 연결 문자열과 드라이버만 교체하면 동일한 방식으로 ClickHouse에 접속할 수 있습니다. 따라서 애플리케이션 아키텍처의 변경 없이 쿼리 구문만 ClickHouse 방식으로 변환하면 마이그레이션이 완료됩니다.

1. 연결 방식

1.1 ODBC 연결

ClickHouse는 공식 ODBC 드라이버를 제공하며, 기존 MSSQL ODBC 연결을 사용하던 애플리케이션에서 드라이버와 연결 문자열만 변경하면 됩니다.

MSSQL ODBC 연결 문자열 예시:

Driver={ODBC Driver 17 for SQL Server};Server=myserver;Database=mydb;Uid=user;Pwd=password;

ClickHouse ODBC 연결 문자열 예시:

Driver={ClickHouse ODBC Driver};Host=myserver;Port=8123;Database=mydb;Uid=user;Pwd=password;

1.2 JDBC 연결

Java 기반 애플리케이션의 경우 ClickHouse JDBC 드라이버를 사용할 수 있습니다.

ClickHouse JDBC URL 예시:

jdbc:clickhouse://myserver:8123/mydb?user=user&password=password

2. 데이터 타입 매핑

MSSQL과 ClickHouse 간 데이터 타입 매핑은 다음과 같습니다.

MSSQL
ClickHouse
비고
INT
Int32
동일
BIGINT
Int64
동일
SMALLINT
Int16
동일
TINYINT
UInt8
부호 없음 주의
FLOAT
Float64
동일
REAL
Float32
동일
DECIMAL(p,s)
Decimal(p,s)
동일
VARCHAR(n), NVARCHAR(n)
String
길이 제한 없음
CHAR(n)
FixedString(n)
고정 길이
DATETIME, DATETIME2
DateTime64(3)
밀리초 정밀도
DATE
Date 또는 Date32
Date32는 더 넓은 범위 지원
BIT
Bool 또는 UInt8
Bool 권장
UNIQUEIDENTIFIER
UUID
동일
MONEY
Decimal(19,4)
직접 매핑

3. 기본 구문 변환

3.1 SELECT TOP → LIMIT

MSSQL:

SELECT TOP 100 * FROM sales ORDER BY amount DESC

ClickHouse:

SELECT * FROM sales ORDER BY amount DESC LIMIT 100

3.2 OFFSET FETCH → LIMIT OFFSET

MSSQL:

SELECT * FROM sales ORDER BY id
OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY

ClickHouse:

SELECT * FROM sales ORDER BY id LIMIT 10 OFFSET 20

4. 문자열 함수 변환

MSSQL
ClickHouse
사용 예시
LEN(str)
length(str)
length('hello') → 5
CHARINDEX(sub, str)
position(str, sub)
position('hello', 'l') → 3
SUBSTRING(str, start, len)
substring(str, start, len)
동일 (1-based 인덱스)
LEFT(str, n)
left(str, n)
동일
RIGHT(str, n)
right(str, n)
동일
LTRIM(str)
trimLeft(str)
왼쪽 공백 제거
RTRIM(str)
trimRight(str)
오른쪽 공백 제거
TRIM(str)
trimBoth(str)
양쪽 공백 제거
REPLACE(str, old, new)
replace(str, old, new)
동일
UPPER(str)
upper(str)
동일
LOWER(str)
lower(str)
동일
CONCAT(a, b, ...)
concat(a, b, ...)
동일
str1 + str2
concat(str1, str2)
+ 연산자 사용 불가

4.1 STRING_AGG 변환

MSSQL:

SELECT category, STRING_AGG(product_name, ', ') AS products
FROM products GROUP BY category

ClickHouse:

SELECT category, arrayStringConcat(groupArray(product_name), ', ') AS products
FROM products GROUP BY category

5. 날짜/시간 함수 변환

5.1 현재 시간

MSSQL
ClickHouse
GETDATE()
now()
GETUTCDATE()
now('UTC')
SYSDATETIME()
now64()
CURRENT_TIMESTAMP
now()

5.2 DATEADD 변환

MSSQL:

SELECT DATEADD(day, 7, order_date) FROM orders
SELECT DATEADD(month, -1, GETDATE())

ClickHouse:

SELECT order_date + INTERVAL 7 DAY FROM orders
SELECT now() - INTERVAL 1 MONTH

5.3 DATEDIFF 변환

MSSQL:

SELECT DATEDIFF(day, start_date, end_date) FROM projects

ClickHouse:

SELECT date_diff('day', start_date, end_date) FROM projects

5.4 DATEPART 변환

MSSQL
ClickHouse
DATEPART(year, dt)
toYear(dt)
DATEPART(quarter, dt)
toQuarter(dt)
DATEPART(month, dt)
toMonth(dt)
DATEPART(week, dt)
toWeek(dt)
DATEPART(day, dt)
toDayOfMonth(dt)
DATEPART(dayofyear, dt)
toDayOfYear(dt)
DATEPART(weekday, dt)
toDayOfWeek(dt)
DATEPART(hour, dt)
toHour(dt)
DATEPART(minute, dt)
toMinute(dt)
DATEPART(second, dt)
toSecond(dt)

5.5 EOMONTH 변환

MSSQL:

SELECT EOMONTH(order_date)

ClickHouse:

SELECT toLastDayOfMonth(order_date)

5.6 날짜 자르기

MSSQL (SQL Server 2022+):

SELECT DATETRUNC(month, order_date)

ClickHouse:

SELECT toStartOfMonth(order_date)
SELECT toStartOfYear(order_date)
SELECT toStartOfWeek(order_date)
SELECT toStartOfDay(order_date)
SELECT toStartOfHour(order_date)

6. NULL 처리

MSSQL
ClickHouse
설명
ISNULL(a, b)
ifNull(a, b)
NULL이면 b 반환
COALESCE(a, b, c)
coalesce(a, b, c)
동일
NULLIF(a, b)
nullIf(a, b)
동일

7. 조건문

7.1 CASE WHEN (동일)

SELECT
    CASE
        WHEN amount > 1000 THEN 'High'
        WHEN amount > 100 THEN 'Medium'
        ELSE 'Low'
    END AS tier
FROM sales

7.2 IIF → if

MSSQL:

SELECT IIF(quantity > 0, 'In Stock', 'Out of Stock') FROM products

ClickHouse:

SELECT if(quantity > 0, 'In Stock', 'Out of Stock') FROM products

7.3 다중 조건 (multiIf)

ClickHouse에서는 CASE WHEN 대신 더 간결한 multiIf 함수를 사용할 수 있습니다.

SELECT multiIf(
    amount > 1000, 'High',
    amount > 100, 'Medium',
    'Low'
) AS tier FROM sales

8. 집계 함수

8.1 기본 집계 함수

MSSQL
ClickHouse
비고
COUNT(*)
count()
동일
COUNT(DISTINCT col)
uniq(col)
근사치, 고성능
COUNT(DISTINCT col)
uniqExact(col)
정확한 값
SUM(col)
sum(col)
동일
AVG(col)
avg(col)
동일
MIN(col)
min(col)
동일
MAX(col)
max(col)
동일
STDEV(col)
stddevSamp(col)
표본 표준편차
STDEVP(col)
stddevPop(col)
모집단 표준편차
VAR(col)
varSamp(col)
표본 분산
VARP(col)
varPop(col)
모집단 분산

8.2 조건부 집계

MSSQL:

SELECT
    COUNT(CASE WHEN status = 'active' THEN 1 END) AS active_count,
    SUM(CASE WHEN region = 'KR' THEN amount ELSE 0 END) AS kr_amount
FROM users

ClickHouse:

SELECT
    countIf(status = 'active') AS active_count,
    sumIf(amount, region = 'KR') AS kr_amount
FROM users

ClickHouse는 대부분의 집계 함수에 If 접미사를 붙여 조건부 집계를 수행할 수 있습니다: countIf, sumIf, avgIf, minIf, maxIf, uniqIf 등

9. 윈도우 함수

윈도우 함수는 대부분 동일한 구문으로 사용할 수 있습니다.

SELECT
    user_id,
    order_date,
    amount,
    SUM(amount) OVER (PARTITION BY user_id ORDER BY order_date) AS running_total,
    ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY order_date DESC) AS rn
FROM orders

지원되는 윈도우 함수: ROW_NUMBER, RANK, DENSE_RANK, NTILE, LAG, LEAD, FIRST_VALUE, LAST_VALUE

미지원 함수: PERCENT_RANK, CUME_DIST (직접 계산 필요)

10. CTE (Common Table Expression)

기본 CTE는 동일한 구문으로 사용할 수 있습니다.

WITH monthly_sales AS (
    SELECT
        toStartOfMonth(order_date) AS month,
        sum(amount) AS total
    FROM orders
    GROUP BY month
)
SELECT * FROM monthly_sales WHERE total > 10000

주의: ClickHouse는 재귀 CTE(WITH RECURSIVE)를 지원하지 않습니다. 계층 데이터 처리가 필요한 경우 데이터를 미리 펼쳐서 저장하거나 배열 함수를 활용해야 합니다.

11. PIVOT 변환

MSSQL:

SELECT * FROM (
    SELECT year, quarter, revenue FROM sales
) src
PIVOT (
    SUM(revenue) FOR quarter IN ([Q1], [Q2], [Q3], [Q4])
) pvt

ClickHouse:

SELECT
    year,
    sumIf(revenue, quarter = 'Q1') AS Q1,
    sumIf(revenue, quarter = 'Q2') AS Q2,
    sumIf(revenue, quarter = 'Q3') AS Q3,
    sumIf(revenue, quarter = 'Q4') AS Q4
FROM sales
GROUP BY year

12. 타입 변환

12.1 CAST (동일)

SELECT CAST(column AS Int32) FROM table

12.2 TRY_CAST → OrNull/OrZero 함수

MSSQL:

SELECT TRY_CAST(value AS INT) FROM data

ClickHouse:

SELECT toInt32OrNull(value) FROM data    -- 실패 시 NULL
SELECT toInt32OrZero(value) FROM data    -- 실패 시 0

13. 기타 변환 사항

13.1 임시 테이블

MSSQL:

SELECT * INTO #temp_sales FROM sales WHERE year = 2024

ClickHouse:

CREATE TEMPORARY TABLE temp_sales AS
SELECT * FROM sales WHERE year = 2024

13.2 EXISTS / IN 서브쿼리

EXISTS와 IN 서브쿼리는 동일한 구문으로 사용할 수 있습니다.

SELECT * FROM customers c
WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.customer_id = c.id
)

14. 주의사항

14.1 지원하지 않는 기능

기능
설명
트랜잭션
ACID 트랜잭션 미지원 (eventual consistency)
Stored Procedure
미지원, 애플리케이션 레이어로 이전 필요
Trigger
미지원
재귀 CTE
WITH RECURSIVE 미지원
UPDATE/DELETE
MergeTree 엔진에서만 제한적 지원 (ALTER TABLE ... UPDATE/DELETE)

14.2 동작 차이

항목
MSSQL
ClickHouse
문자열 비교
Collation에 따름
대소문자 구분 (기본)
NULL 정렬
NULLS FIRST/LAST 지정
NULLS LAST 기본
+ 연산자
문자열 연결 가능
숫자 연산만 가능

15. 마이그레이션 체크리스트

마이그레이션 진행 시 다음 항목들을 순차적으로 점검하시기 바랍니다.

  1. ODBC/JDBC 드라이버 설치 및 연결 문자열 변경
  2. 테이블 스키마 생성 (데이터 타입 매핑 적용)
  3. 쿼리 구문 변환
    • SELECT TOP → LIMIT 변환
    • 문자열 함수 변환
    • 날짜/시간 함수 변환
    • NULL 처리 함수 변환
    • 조건부 집계 최적화 (If 접미사 함수 활용)
  4. Stored Procedure 로직 애플리케이션으로 이전
  5. 테스트 및 검증

16. 결론

ClickHouse는 ODBC/JDBC 표준 인터페이스를 지원하므로, 기존 MSSQL 기반 분석 애플리케이션의 연결 계층은 그대로 유지할 수 있습니다. 본 문서에서 정리한 쿼리 구문 변환 사항들만 적용하면 애플리케이션 아키텍처 변경 없이 ClickHouse로의 마이그레이션이 가능합니다.

ClickHouse의 컬럼 지향 스토리지와 벡터화된 쿼리 실행 엔진은 대용량 분석 워크로드에서 MSSQL 대비 월등한 성능을 제공하므로, 마이그레이션 후 분석 쿼리 성능의 획기적인 개선을 기대할 수 있습니다.