DuckDB — 파일 위에서 바로 분석하는 열 지향 엔진 · 분석 SQL 패턴 · 퀴즈
퀴즈: 분석 SQL 패턴
문항 8개. 정답과 해설은 풀어 본 뒤에 보여 드립니다.
`row_number() over (...) as rnk` 를 붙인 질의에 `where rnk <= 3` 을 썼더니 열을 찾을 수 없다고 한다. 왜인가?
- 윈도 함수의 별칭은 ORDER BY 에서만 쓸 수 있고 조건절에는 원식을 다시 적어야 한다
- WHERE 는 윈도 함수보다 먼저 평가되므로 그 결과를 볼 수 없다 — QUALIFY 가 그 자리다
- row_number 는 결과를 실체화하지 않는 지연 함수라 같은 질의 안에서 참조할 수 없다
- PARTITION BY 가 있는 윈도는 GROUP BY 처럼 취급되어 HAVING 으로만 거를 수 있다
`sum(qty) over (partition by store_id order by month)` 가 '매장별 월 누적 합' 이 되는 이유는?
- partition by 가 매장별 합을 먼저 구하고 order by 가 그 합을 월 순으로 정렬해 표시하기 때문이다
- over 절이 있으면 sum 은 항상 전체 합이 되고, order by 는 출력 순서만 바꾸기 때문이다
- order by 가 있으면 sum 은 월별 합으로 바뀌고, partition by 가 그것을 매장별로 다시 더하기 때문이다
- 창이 매장마다 따로 열리고, order by 가 있으면 기본 프레임이 첫 행부터 현재 행까지가 되기 때문이다
`PIVOT t ON month USING sum(qty) GROUP BY country` 를 쓰면 `sum(case when month = …)` 을 여섯 번 적는 것과 무엇이 다른가?
- 어떤 월이 있는지 데이터에서 찾아 열을 만들므로 새 월이 생겨도 SQL 을 고칠 필요가 없다
- 결과가 열 저장 형식으로 나와 이후 집계가 case 식보다 빨라진다
- 월 값이 문자열이어도 자동으로 날짜로 바꿔 열 순서를 시간순으로 맞춘다
- case 식과 달리 NULL 인 월을 0 으로 채워 주므로 합계가 어긋나지 않는다
`sales s asof join fx_rates f on s.currency = f.currency and s.sold_at >= f.valid_from` 은 판매 행 하나에 환율을 몇 행 붙이나?
- 조건을 만족하는 모든 과거 환율 행을 붙이므로 판매 행이 그만큼 늘어난다
- 판매 시각과 valid_from 이 정확히 같은 행만 붙이고 없으면 판매 행을 버린다
- 통화가 같고 valid_from 이 판매 시각 이전인 것 중 가장 늦은 한 행만 붙인다
- 판매 시각 이후의 첫 환율 행을 붙여 다음 변경까지의 값을 미리 반영한다
ASOF 대신 보통 `join ... on s.currency = f.currency and s.sold_at >= f.valid_from` 을 쓰면 무엇이 잘못되나?
- 환율 표가 시각순으로 정렬돼 있지 않으면 조인 자체가 실패한다
- 환율이 없는 날의 판매 행이 빠져 합계가 실제보다 작아진다
- 판매 시각 이후의 환율까지 붙어 미래 값으로 계산된다
- 과거의 모든 환율 행이 다 붙어 행이 몇 배로 불어나고 합계가 커진다
`select unnest(tags) as tag from products` 에서 태그가 3개인 상품 한 행은 결과에 어떻게 나오나?
- 세 행으로 펼쳐지고 나머지 열은 세 행에 같은 값으로 복제된다
- 한 행으로 남고 tag 열에 세 값이 쉼표로 이어진 문자열이 들어간다
- 첫 번째 태그만 남고 나머지는 버려지므로 별도 함수로 꺼내야 한다
- 세 개의 열(tag_1, tag_2, tag_3)로 옆으로 펼쳐진다
`EXPLAIN` 과 `EXPLAIN ANALYZE` 의 차이는?
- EXPLAIN 은 논리 계획, EXPLAIN ANALYZE 는 물리 계획을 보여 주며 둘 다 실행하지 않는다
- EXPLAIN 은 계획만 만들고, EXPLAIN ANALYZE 는 실제로 실행해 연산자마다 행 수와 시간을 찍는다
- EXPLAIN ANALYZE 는 통계를 갱신한 뒤 계획을 다시 세우므로 두 계획이 달라질 수 있다
- EXPLAIN 은 CLI 전용이고 EXPLAIN ANALYZE 는 파이썬 API 에서만 쓸 수 있다
`SET memory_limit = '64MB'` 로 낮춘 뒤 큰 정렬을 돌렸다. 영속 DB 파일과 메모리 DB 에서 결과가 어떻게 갈리나?
- 둘 다 상한을 넘는 순간 오류로 멈춘다 — memory_limit 은 안전장치이지 동작을 바꾸지 않는다
- 둘 다 상한을 무시하고 완주하며, 설정은 통계 수집 시 참고값으로만 쓰인다
- 영속 DB 는 임시 파일로 흘려 느리게 완주하고, 메모리 DB 는 temp_directory 가 없으면 실패한다
- 메모리 DB 는 RAM 만 쓰므로 오히려 빠르게 완주하고, 영속 DB 는 디스크 잠금 때문에 실패한다