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. 마이그레이션 체크리스트
마이그레이션 진행 시 다음 항목들을 순차적으로 점검하시기 바랍니다.
- ODBC/JDBC 드라이버 설치 및 연결 문자열 변경
- 테이블 스키마 생성 (데이터 타입 매핑 적용)
- 쿼리 구문 변환
- SELECT TOP → LIMIT 변환
- 문자열 함수 변환
- 날짜/시간 함수 변환
- NULL 처리 함수 변환
- 조건부 집계 최적화 (If 접미사 함수 활용)
- Stored Procedure 로직 애플리케이션으로 이전
- 테스트 및 검증
16. 결론
ClickHouse는 ODBC/JDBC 표준 인터페이스를 지원하므로, 기존 MSSQL 기반 분석 애플리케이션의 연결 계층은 그대로 유지할 수 있습니다. 본 문서에서 정리한 쿼리 구문 변환 사항들만 적용하면 애플리케이션 아키텍처 변경 없이 ClickHouse로의 마이그레이션이 가능합니다.
ClickHouse의 컬럼 지향 스토리지와 벡터화된 쿼리 실행 엔진은 대용량 분석 워크로드에서 MSSQL 대비 월등한 성능을 제공하므로, 마이그레이션 후 분석 쿼리 성능의 획기적인 개선을 기대할 수 있습니다.