공유, 관리, 서비스, 모니터링. 안전한 신원 확인, 인가, 관리, 모니터링, 과금 같은 능력을 제공한다.
이 장은 앞의 여섯 장과 성격이 다르다. 지금까지는 오픈소스 데이터베이스 하나를 다뤘는데, 여기서는 그것을 감싼 상업 서비스를 다룬다. 그래서 서술에 값과 요금제가 등장하고, 화면 갈무리가 여섯 도판 가운데 다섯을 차지한다. 저자들은 MotherDuck이 DuckDB Labs 팀과 긴밀히 협력해 클라우드 플랫폼에서 모든 기능의 상호운용성과 가용성을 확보한다고 밝혀두었다.
그럼에도 기술적으로 읽을 대목이 분명하다. MotherDuck은 오픈소스 DuckDB에 선택적으로 붙는(opt-in) 기능으로 확장을 통해 제시된다. 이 확장은 md: 또는 motherduck: 프로토콜로 데이터베이스를 열 때 자동으로 적재되며, 질의 파서와 엔진 양쪽에 통합된다. 파서는 데이터베이스와 공유 관리 기능으로 확장되고, 질의 엔진에서는 확장이 테이블의 소재를 분석해 알맞은 실행 엔진을 고른다.
이 장의 작업 순서 — 번호 붙은 목록이 하나도 없고, 본문 자체가 세션 기록과 서비스 안내다
- 7.1서버리스가 무슨 뜻이고 아키텍처가 어떻게 생겼는지 본다
- 7.2가입하고 토큰으로 CLI를 인증한다
- 7.3.1로컬 데이터베이스를 클라우드로 올린다
- 7.3.2클라우드에서 데이터베이스를 처음부터 만든다
- 7.3.3읽기 전용 스냅숏을 공유하고 붙인다
- 7.3.4·5S3 비밀을 두고, 실행 위치와 비용을 제어한다
- 7.3.6·7자연어로 질의하고, 파이프라인 가운데에 앉힌다
MotherDuck 소개Introduction to MotherDuck
MotherDuck은 협업형 서버리스 분석 플랫폼이다. 브라우저나 DuckDB의 어떤 API로든 클라우드 데이터베이스와 클라우드 저장소의 데이터를 질의하고 분석하게 해준다. 여기서 서버리스가 뜻하는 바를 저자들이 분명히 정의한다. 사용자가 서버나 클러스터를 띄우거나 데이터베이스 인스턴스를 설정하는 일을 다룰 필요가 없다는 뜻이다. 대신 데이터베이스만 만들면 나머지는 서비스가 알아서 한다.
어떻게 작동하는가 7.1.1
쓰는 길이 여럿이다. 서비스에 가입하면 브라우저에서 돌아가는 MotherDuck 웹 UI에 이르게 된다. 이 UI는 MotherDuck과 통신하는 법을 아는 특별한 DuckDB 판본을 브라우저에서 돌리고 있다. UI는 데이터베이스를 관리하는 도구이면서, 질의를 입력하고 실행하고 결과를 보는 노트북 기반 접근이기도 하다.
다른 입구는 물론 CLI와 파이썬 같은 언어 통합이다. 여기서 md: 확장의 두 갈래 역할이 갈린다.
- 파서 — 데이터베이스와 공유 관리를 둘러싼 기능으로 확장된다.
- 질의 엔진 — 확장이 테이블이 로컬에 있는지 원격에 있는지 분석하고 알맞은 실행 엔진을 써서 데이터를 그에 맞게 조인한다. 필요하면 로컬 데이터의 일부를 조인이나 필터를 위해 서버로 보내거나, 원격 쪽 데이터를 가져와 로컬에서 조인한다.
아키텍처의 핵심 구성 요소는 넷이다.
서버리스 DuckDB 연산 인스턴스다. 질의의 "원격" 부분을 실행한다. 이름 하나에 이 서비스의 성격이 다 담겼다.
데이터베이스와 테이블. 저장 계층에서 관리되는 데이터베이스, 테이블, 뷰를 노출한다.
내부 저장과 유지 관리. 지속적이고 안전하며 최선의 성능을 위해 자동으로 최적화된다.
그리고 이 절에서 뒤의 비용 논의로 이어지는 복선이 하나 놓인다. MotherDuck은—다른 현대적 클라우드 데이터 플랫폼과 마찬가지로—저장과 연산 설비를 분리한다. 이것이 결국 MotherDuck을 쓸 때 발생하는 비용에 중요해진다. 7.3.5절에서 그 분리가 요금표로 어떻게 나타나는지 보게 된다.
왜 MotherDuck을 쓰는가 7.1.2
첫째이자 무엇보다, DuckDB에 기반한 단순하고 성능 좋고 효율적인 데이터 웨어하우스를 제공한다. 저자들의 진단이 이 책 전체의 문제의식과 이어진다. 대부분의 사람은 클라우드 데이터 웨어하우스 사용자의 긴 꼬리에 속하고, 수십 수백 테라바이트의 뜨거운 데이터를 위한 분석 처리 능력을 필요로 하지 않는다. 그런 쓰임새는 분산 시스템에 기반하지 않고 클라우드를 주된 데이터 저장소로, DuckDB를 질의 엔진으로 쓰는 더 단순하고 효율적인 아키텍처에서 이득을 볼 수 있다.
제3·4장의 가상 시스템—에너지 생산 감시—을 다시 떠올려보라는 것이 저자들의 방식이다. 수백 곳이나 수천 곳의 사이트를 15분 간격으로 감시한다 해도, 연간 10억 레코드에 가까운 것은 나오지 않으며 크기도 대개 몇 기가바이트에 머문다.
이것을 빅데이터라 부르기는 어렵고, MotherDuck이 손쉽게 다룰 수 있는 규모다. 규모를 재보지 않고 분산 시스템을 세우는 습관에 대한 조용한 반문이다.
나머지 세 쓰임새도 정리해둘 만하다.
- 다종 원천으로 이루어진 데이터 레이크의 질의 엔진 — Parquet으로 저장된 차가운 데이터, S3의 CSV 파일, 또는 Apache Iceberg에 저장된 데이터 같은 것이다. 그 데이터를 MotherDuck에 직접 저장된 뜨거운 데이터와 손쉽게 조인할 수 있다.
- 데이터 애플리케이션·대시보드·API의 서버리스 백엔드 — 주 트랜잭션 데이터베이스에서 분석 질의를 돌리는 대신, 전용 분석 데이터베이스에서 그 질의를 돌린다.
- 읽기 전용 스냅숏의 공유 — 다른 MotherDuck 사용자에게 데이터베이스의 스냅숏을 공유할 수 있다. 그들은 공유된 대로 원천을 쓸 수도 있고, 자기 인스턴스의 데이터를 그 데이터셋과 조인할 수도 있다.
MotherDuck 시작하기Getting started with MotherDuck
책 전체에서 CLI나 파이썬 통합을 썼는데, MotherDuck을 시작하려면 먼저 브라우저를 띄워야 한다. 가입 버튼을 눌러 GitHub 계정이나 구글 계정으로, 또는 이메일 주소를 주고 무료 계정을 만들 수 있다.
원서의 이 도판은 MotherDuck UI의 화면 갈무리다. 왼쪽에 데이터베이스와 그 스키마가 탐색 가능한 트리로 표시되고, 주 화면에 질의와 그 결과가—인라인 막대 차트를 포함해—표시되는 구성이다. 화면 갈무리는 이 문서에서 재현하지 않고 서술로 대신한다.
UI로 MotherDuck 쓰기 7.2.1
웹 기반 UI는 세 가지를 한자리에 모아준다. 모든 원격 데이터베이스에 접근하고 질의하기, 계정 설정 관리하기, 그리고 S3의 원격 데이터 원천을 질의하는 데 필요한 비밀을 저장하기다. UI 밖에서 MotherDuck에 접근하는 데 필요한 API 토큰도 여기서 얻는다.
웹 UI에서 돌아가는 데이터베이스도 실은 로컬 임베디드 데이터베이스다! WebAssembly(WASM)로 컴파일된 판본을 쓰고 있어 브라우저 안에서 로컬로 돌아간다. 물론 질의는 앞서 설명한 대로 MotherDuck 클라우드에서 실행된다.
대안으로, MotherDuck 계정이 없거나 원하지 않는다면 shell.duckdb.org를 방문할 수 있다. 본질적으로 CLI처럼 동작하지만 데이터를 영속화하거나 MotherDuck에 접속할 수는 없다.
이 구조에서 따라오는 이득이 있다. SQL 질의의 결과가 브라우저에 로컬한 DuckDB 인스턴스에 캐시되어, 질의 결과를 즉시 정렬하고 피벗하고 필터링할 수 있다. 서버를 다시 부르지 않고 손에서 결과를 만지작거릴 수 있다는 뜻이다.
UI 왼쪽은 데이터베이스와 그 테이블·컬럼, 업로드된 파일을 나열한다. 트리 구조를 탐색할 때 맥락 메뉴가 나타나 데이터베이스를 사용(use)·공유(share)·삭제(drop)·분리(detach)하거나 이름을 복사할 수 있다. 원서의 이 도판은 그 맥락 메뉴의 화면 갈무리다.
질의를 실행하는 경험은 주피터 노트북과 비슷하게 마련되어 있다. 자동 완성과 함께 SQL 문을 쓰고, 실행하고, 셀 아래의 데이터 격자에 렌더링된 질의 결과를 본다. 출력 격자는 로컬 정렬, 출력 컬럼 선택, 컬럼 머리글에 히스토그램과 집계 표시, 데이터의 피벗과 필터링을 지원한다. 그리고 질의를 담은 UI의 상태가 세션을 넘어 유지되므로, 브라우저를 닫고 나중에 이어서 할 수 있다.
CSV와 Parquet 파일을 UI에서 직접 업로드하는 것도 지원된다. 업로드한 파일은 어떤 질의에서든 접근할 수 있게 되고, CREATE TABLE AS SELECT 문을 활용하거나 필요에 맞게 변환하게 된다.
토큰 기반 인증으로 DuckDB를 MotherDuck에 연결하기 7.2.2
DuckDB는 공유 데이터베이스 인스턴스를 열려고 하는 순간에 MotherDuck과의 인증 과정을 촉발한다. 이름 붙은 데이터베이스일 수도 있고 기본 데이터베이스일 수도 있다.
데이터베이스를 지정하지 않고 MotherDuck에 접속하면 my_db라는 기본 데이터베이스에 접속한다. 그것이 현재 데이터베이스가 된다. 그러면 테이블 이름만 지정해 이 데이터베이스의 어떤 테이블이든 질의할 수 있다. USE 명령이 현재 데이터베이스를 바꾸게 해준다.
D .open md: Attempting to automatically open the SSO authorization page in your default browser. 1. Please open this link to login into your account: https://auth.motherduck.com/activate 2. Enter the following code: XXXX-XXXX # 인증 흐름을 끝까지 따라가면 터미널에 다음이 나온다. Token successfully retrieved [√] You can store it as an environment variable to avoid having to log in again: $ export motherduck_token='eyJhbGciOiJI..._Jfo'
# 또는 토큰을 md: 프로토콜의 매개변수로 쓴다. D .open 'md:?motherduck_token=eyJhbGciOiJI..._Jfo' # 이 URL 형식은 개별 언어 바인딩에도 그대로 적용된다. # 제6장에서 논한 파이썬 연결 관리를 떠올려보라. import duckdb con = duckdb.connect('md:?motherduck_token=eyJhbGciOiJI..._Jfo')
duckdb.connect에 ':memory:'나 파일 이름을 넘겼던 그 자리에
URL 하나를 넣으면 클라우드가 된다. API가 바뀌지 않는다는 것이 이 설계의 요령이다.
웹 UI를 쓸지 CLI를 쓸지는 결국 각자의 선택이다.
데이터베이스를 MotherDuck에 올리기Uploading databases to MotherDuck
7.3절의 도입에서 저자들은 이 절의 목표를 정리해둔다. 데이터를 클라우드에 넣고, 동료와 협력자에게 데이터베이스를 공유하도록 도와주는 모든 기능이다. 그리고 첫 예제의 동기가 현실적이다. 제6장에서 파이썬 통합으로 나라 데이터를 담은 데이터베이스를 만들고 데이터셋의 문제를 정리했다. 이제 그 작업을 동료와 공유하고 싶다.
한 방법은 저자들이 "스프레드시트식 삶의 방식"이라 부르는 것이다. countries.duckdb 저장 파일을 이메일에 첨부하거나 네트워크 폴더에 복사하고 넘어가는 것. 더 낫고 덜 부서지기 쉬운 공유 방법이 MotherDuck이다.
D .open countries.duckdb # 그 저장 파일이 없어도 걱정할 것 없다. 이 명령이 만들어준다. -- 갓 만든 데이터베이스라면 특히, cities 테이블을 더해둔다. D CREATE TABLE cities AS SELECT * FROM (VALUES ('Amsterdam', 1), ('London', 2)) cities(Name, Id); # 공유하기 전에 분리해서 모든 잠금을 풀어야 한다. # 인수 없는 .open으로 인메모리 DB로 돌아간 뒤 LOAD motherduck; 를 하거나, # 한 번에 .open md: 를 부른다. 후자는 CLI를 MotherDuck 기본 DB에 붙인다. D .open md: D CREATE DATABASE "countries" FROM 'countries.duckdb';
COPY … TO … (FORMAT PARQUET)가 여기서 쓸모를 찾는다.
-- 세션은 아직 MotherDuck 기본 DB에 붙어 있다. 접두사를 쓰거나 데이터베이스를 바꾼다. D FROM countries.cities; -- 접두사를 쓰는 방식 D USE countries; -- USE는 원격 MotherDuck 카탈로그에서 이름을 찾는다 D FROM cities; -- 그러면 접두사를 생략할 수 있다 # 이미 CLI를 나왔다면 새 데이터베이스에 직접 접속해도 된다. $ duckdb D .open md:countries
| Name | Id |
|---|---|
| varchar | int32 |
| Amsterdam | 1 |
| London | 2 |
로컬 데이터베이스를 MotherDuck에 올릴 때 로컬 이름과 원격 이름은 언제나 달라야 한다. 이 규칙을 잊고 같은 이름을 주면 오류를 만날 위험이 있다.
D create database "countries" from 'countries' ; Error: Catalog Error: Database 'countries' has already been created and attached # 그리고 현재 데이터베이스를 올리려 하면 이 오류가 난다. Error: Binder Error: Database "countries.duckdb" is already attached with alias "countries"
MotherDuck에서 데이터베이스 만들기Creating databases in MotherDuck
앞 절에서는 기존 데이터베이스를 올렸다. 대안으로 클라우드에서 직접 스키마를 처음부터 지을 수 있다. 그리고 그 편이 나은 경우를 저자들이 분명히 짚는다. 스키마의 내용이 대체로 다른 공용 클라우드에 저장된 파일에 의존한다면, 그것을 먼저 로컬 DuckDB 인스턴스로 내려받고 그 데이터베이스를 다시 MotherDuck에 올리는 것은 시간과 자원의 낭비다. 대부분의 경우 MotherDuck이 내 로컬 시스템보다 S3 버킷에 더 가까이서 돌아가므로, 클라우드에서 MotherDuck으로 직접 들이는 편이 시간과 돈을 아껴줄 수 있다.
D CREATE DATABASE "my-test"; D SHOW DATABASES; -- .databases CLI 명령으로도 된다
| database_name |
|---|
| varchar |
| my-test |
"my-test"를 만든다. 규칙과 예제가 어긋난다.
그리고 하이픈이 들어갔기 때문에 이름을 인용부호로 감싸야 하는데,
CREATE·DROP에서는 겹인용부호 "my-test"를 쓰고
USE에서는 홑인용부호 'my-test'를 쓴다.
식별자를 감싸는 표준 표기는 겹인용부호이니, 따라 할 때는 한쪽으로 맞추는 편이 안전하다.
-- CREATE DATABASE는 데이터베이스만 만들고 세션을 그리로 바꾸지는 않는다. D USE 'my-test'; D SELECT current_database();
| current_database() |
|---|
| varchar |
| my-test |
-- 테이블을 만들고 행을 넣어본다. D CREATE TABLE people (name varchar, born date); D INSERT INTO people VALUES ('Mark', '1989-01-01'), ('Hannes', '1990-01-01'); D SELECT count(*) FROM people; -- → 2 D SELECT count(*) FROM "my-test".people; -- 데이터베이스 이름을 접두사로 붙여도 같다 -- 감을 잡았으면 시험용 데이터베이스를 지운다. -- 쓰고 있는 데이터베이스는 지울 수 없으므로 먼저 기본 DB로 옮겨 앉는다. D USE my_db; D DROP DATABASE "my-test";
데이터베이스 공유하기Sharing databases
MotherDuck은 데이터베이스의 읽기 전용 스냅숏을 공유하는 능력을 제공한다. 데이터를 공유하는 데만 좋은 것이 아니라 협업 분석과 기능의 공유에도 좋다. 그 까닭이 이 절의 핵심이다. 스냅숏은 데이터만이 아니라 모든 뷰를 담으며, 그와 함께 그 뷰를 만드는 동안 들인 모든 노력을 담는다. 저자들의 표현으로는 "스테로이드를 맞은 스프레드시트"다.
제3·5장에서 뷰가 논리를 감싸두는 수단이라고 배웠다. 그 뷰가 그대로 건너간다는 것은, 정제 규칙과 단위 환산과 조인 논리까지 함께 건너간다는 뜻이다. 파일 하나를 이메일로 보내는 것과는 다른 종류의 공유다.
D CREATE SHARE shared_countries -- 공유될 데이터베이스의 이름 FROM countries; -- 공유할 데이터베이스의 이름
| share_url |
|---|
| varchar |
| md:_share/countries/1acb80cf-d872-4fab-8077-64975cce0452 |
-- 붙이려면 상대도 MotherDuck 계정이 있어야 한다. D ATTACH 'md:_share/countries/1acb80cf-d872-4fab-8077-64975cce0452' AS shared_countries; D .mode line D DESCRIBE SHARE shared_countries; share_name = shared_countries share_link = md:_share/countries/1acb80cf-d872-4fab-8077-64975cce0452 database_name = countries database_id = 9d7586ac-add9-46dc-a4fb-def6b42f0f7c snapshot_id = 041a5ba9-8cf4-471b-af13-1bec75a0b3ce D LIST SHARES; -- 내가 만든 공유 목록
-- 출간 시점에 공유는 원본이 바뀌어도 자동으로 갱신되지 않는다. -- 스키마와 데이터의 변경은 공유하는 쪽에서 명시적으로 전파해야 한다. D UPDATE SHARE shared_countries; -- 더 이상 필요 없는 공유는 DETACH로 없앤다. -- 그 공유에 접속해 있다면 먼저 다른 데이터베이스로 옮겨 앉아야 한다. D USE my_db; D DETACH shared_countries;
저자들이 준비해둔 공유들
저자들은 독자를 위해 흥미로운 공유 몇 개를 준비해두었다. 제3·4장의 완전한 데이터베이스—그 장들에서 만든 모든 테이블과 뷰를 담은—와 스택 오버플로의 완전한 덤프, 그리고 표본 데이터 모음이다.
-- ① 제3·4장의 데이터베이스 D ATTACH 'md:_share/duckdb_in_action_ch3_4/d0c08584-1d33-491c-8db7-cf9c6910eceb' AS duckdb_book_ch3_and_4; D USE duckdb_book_ch3_and_4; D SHOW tables; -- ② 스택 오버플로 덤프 D ATTACH 'md:_share/stackoverflow/6c318917-6888-425a-bea1-5860c29947e5' AS stackoverflow_analysis; D USE stackoverflow_analysis; D SELECT count(*) FROM posts; 58,329,356 -- ③ 표본 데이터 모음. 테이블에 접두사가 붙어 있어 완전한 이름으로 접근한다. D ATTACH 'md:_share/share_sample_data/23b0d623-1361-421d-ae77-62d701d471e6' AS sample_data;
| 이름 | 테이블 이름 | 행 수 | 설명 |
|---|---|---|---|
| Hacker News | hn.hacker_news | 3.9M | 해커 뉴스 댓글의 표본 |
| NYC 311 민원 데이터 | nyc.service_requests | 32.5M | 전화와 웹을 통한 뉴욕시 311 민원 상담 전화 요청 |
| 대기질 | who.ambient_air_quality | 41k | 세계보건기구의 과거 대기질 데이터 |
| 택시 운행 | nyc.taxi | 3.3M | 2020년 11월 뉴욕 옐로캡 운행 데이터 |
| 승차 공유 | nyc.rideshare | 18.1M | 뉴욕의 승차 공유(Lyft, Uber 등) 운행 |
본문이 완전한 이름의 예로 든 것은 sample_data.nyc.yellow_cab_nyc_2022_11이다. 그런데 표 7.1에는 그 이름이 없다. 택시 데이터의 테이블 이름은 nyc.taxi로 적혀 있고, 설명은 2020년 11월이라고 되어 있다. 예시 이름에 박힌 2022_11과도 어긋난다.
예시가 옛 이름이었을 가능성이 있으니, 실제로 붙여본 뒤 SHOW tables로 확인하는 편이 확실하다. 이 문서의 표에는 표 7.1에 인쇄된 이름을 그대로 실었다.
저자들의 맺음말이 이 공유들의 목적을 말한다. 이 데이터셋들은 여러 다른 주제를 제공하니, SQL 실력을 단련하거나 DuckDB와 MotherDuck의 가능성을 탐색하는 데 쓸 수 있다.
S3 비밀 관리와 S3 버킷에서 데이터 적재하기Managing S3 secrets and loading Data from S3 buckets
앞 장들에서는 http://나 https:// 프로토콜로 직접 접근할 수 있는 파일에서 데이터를 들였다. 그러나 파일 저장에 아마존 S3를 쓰는 일이 잦고, 그것은 s3:// 프로토콜로 접근한다. MotherDuck과 DuckDB는 그 프로토콜도 말하지만, 여러분을 대신해 아마존 S3에 인증하려면 비밀이 필요하다.
여기에 MotherDuck을 쓸 때의 이점이 하나 붙는다. 비밀을 그들의 시스템에 저장해두면 MotherDuck에 접속된 모든 세션에서 쓸 수 있다. 웹 UI로 하거나 전용 문장으로 한다.
D CREATE OR REPLACE SECRET ( TYPE S3, KEY_ID 'access-key', SECRET 'secret-key', REGION 'us-east-1' ); -- 그러면 보안 S3 버킷의 데이터를, 앞서 http나 파일시스템으로 질의했던 -- 여느 CSV나 Parquet 파일과 똑같이 질의할 수 있다. D CREATE OR REPLACE TABLE mytable AS FROM 's3://...'; -- 버킷 작업이 끝나면 비밀을 치운다. D DROP SECRET (TYPE s3);
DROP SECRET으로 손수 치우는 절차를 습관으로 삼아야 한다.
데이터 수집과 MotherDuck 사용 최적화Optimizing data ingestion and MotherDuck usage
클라우드 기반 해법을 돌리는 데는 여러 종류의 비용이 든다. 연산, 저장, 데이터 인그레스, 데이터 이그레스가 그중에 있다. 그리고 이 절의 핵심 능력이 여기서 나온다. MotherDuck 확장은 함수가 클라우드에서 실행될지 내 로컬 기계에서 실행될지에 대한 촘촘한 제어를 준다.
저자들이 든 반례가 명료하다. 이미 로컬에 있는 큰 Parquet 파일을 처리하고 싶다면, 그것을 S3에 먼저 올린 다음 MotherDuck에서 처리를 돌리는 것은 무의미하다. MotherDuck의 연산 비용과 S3의 이그레스 비용을 둘 다 물게 되기 때문이다. 인터넷이 빠르다면 로컬에서 처리하고 내 기계에서 MotherDuck으로 그냥 올리는 편이 아마 낫다.
확장은 read_ 접두사로 시작하는 모든 함수—read_json, read_csv_auto 같은 것—를 확장해 MD_RUN 매개변수를 지원하게 만든다. 아래에서 원천과 MD_RUN 값을 갈아 끼워, 함수가 어디서 실행되고 그것이 무엇을 뜻하는지 확인할 수 있다.
- 그렇게 되는 이유
- —
- 새겨둘 것
- —
차가운 저장과 뜨거운 저장
무료 등급을 넘어서면 MotherDuck은 표준 등급을 제공한다. 저자들이 적어둔 집필 시점의 값은 다음과 같다.
100GB 저장과 100 연산 시간이 포함된다.
표준 사용 할당량을 넘는 자원이 필요하면 추가로 구매할 수 있다.
다만 이것은 클라우드 사용에만 해당하며 로컬 실행에는 해당하지 않는다.
두 저장의 뜻이 다르다. 차가운 저장(cold storage)은 데이터베이스와 파일을 위한 영속 저장을 가리킨다. 뜨거운 저장(hot storage)은 질의를 실행하는 데 쓰이며 메모리 사용에 해당하고, 필요에 맞게 미세 조정한 최대치로 제한할 수 있다. DuckDB에서 뜨거운 저장은 상한까지 자동으로 확장되고 초와 기가바이트 단위로 계량된다.
저자들이 근거로 든 관찰이 인상적이다. 연구에 따르면 처리되는 데이터의 대단히 큰 비율이 24시간이 안 된 것이다. 데이터가 일주일 묵을 무렵이면 가장 최근 날의 데이터보다 질의될 가능성이 약 20배 낮아진다.
여기에 하나가 더 붙는다. 워크로드의 크기가 전체 데이터 크기보다 작은 일이 잦다. 예컨대 대시보드는 통상 집계된 데이터로 만들어진다. 지난 한 시간의 데이터는 새로 집계하면 최신 변경을 놓치지 않고, 일주일보다 더 거슬러 올라가는 것은 미리 집계해 별도 테이블로 저장할 수 있다. 집계는 통상 행이 훨씬 적고 저장을 훨씬 덜 잡아먹는다.
그래서 비용을 통제하려면 불필요한 데이터를 MotherDuck에 직접 저장하지 말고 필요할 때 적재하거나 처리하며, 한 번에 유지할 뜨거운 저장의 최대량을 합리적으로 설정해야 한다. 다만 쓸 수 있는 뜨거운 저장의 양이 질의 성능에 영향을 준다는 저울을 잊지 말아야 한다.
AI로 데이터 질의하기Querying your data with AI
SQL이 영어와 어느 정도 닮았다고는 하나 익히기가 늘 쉽지는 않고, 처음 접하는 사람에게는 어떤 구성물은 노골적으로 겁을 준다.
SQL의 이전 이름은 SEQUEL(Structured English QUEry Language)이었다. 관계형 모델에 기반한 또 다른 질의 언어 QUEL을 두고 만든 말장난이었다. 그 이름은 결국 상표권 문제로 폐기되었다.
그런데 구조화된 언어로 된 질의는 곧잘 생성될 수 있다. MotherDuck은 자연어로 데이터를 질의하게 해주는 생성 AI 기능을 제공한다. 데이터를 서술할 수 있고, SQL 문을 생성해주거나 기존 문장을 고쳐준다. 작동 원리를 저자들이 분명히 밝혀둔다. 데이터베이스 스키마를 상세한 프롬프트와 여러분의 질문과 함께 대규모 언어 모델(LLM)로 보내면, 그것이 요청된 SQL 문을 생성하고 선택적으로 실행한다.
D .mode line D CALL prompt_schema(); summary = The database contains tables for storing data related to votes, tags, posts, post links, badges, users, and comments. Run Time (s): real 3.672 user 0.007355 sys 0.002674 -- 한 번 더 부르면 대개 다른 응답을 얻는다. D CALL prompt_schema(); summary = The data in the database is about votes, tags, posts, post links, badges, users, and comments. Run Time (s): real 3.054 user 0.007354 sys 0.003175
-- "가장 인기 있는 태그는 무엇인가?"는 유효한 SQL이 아니므로 -- prompt_query라는 특별한 pragma로 그 사실을 알려야 한다. -- pragma는 컴파일러나 질의 파서에게 입력을 어떻게 처리해야 하는지 알려주는 특별한 지시다. D .mode duckbox D pragma prompt_query('What are the most popular tags?');
| TagName | Count |
|---|---|
| varchar | int64 |
| javascript | 2479947 |
| python | 2113196 |
| java | 1889767 |
| c# | 1583879 |
| php | 1456271 |
| android | 1400026 |
| html | 1167742 |
| jquery | 1033113 |
| c++ | 789699 |
| css | 787138 |
| 10 rows 2 columns · real 3.763 | |
prompt_sql 프로시저로 알아낼 수 있다.
다만 확률적으로 조금 달랐을 수도 있다는 점은 염두에 두어야 한다.
D .mode line D call prompt_sql('What are the most popular tags?'); query = SELECT TagName, Count FROM tags ORDER BY Count DESC; Run Time (s): real 5.425 user 0.010331 sys 0.005074
prompt_query는 정확히 열 행을 돌려주었다.
생성된 SQL과 실제 실행된 SQL이 달랐거나, 평이 과했거나, 인쇄에서 한 줄이 빠진 것이다.
LLM이 만든 질의를 그대로 믿지 말고 눈으로 확인하라는 이 절의 교훈이, 뜻하지 않게 이 자리에서 증명된다.
-- 더 복잡한 질문을 던져본다. D pragma prompt_query("Which 5 questions have the most comments, what is the post title and comment count"); -- → 5행. real 19.695 D call prompt_sql("Which 5 questions have the most comments, ..."); query = SELECT p.Title, COUNT(c.Id) AS comment_count FROM posts p JOIN comments c ON p.Id = c.PostId AND p.PostTypeId = 1 GROUP BY p.Title ORDER BY comment_count DESC LIMIT 5; Run Time (s): real 4.795
-- 댓글 수는 posts 테이블의 컬럼이므로 comments와의 조인이 필요하지 않다. -- 프롬프트를 손질해 posts 테이블만 쓰는 질의를 만들게 해본다. D call prompt_sql("System: No joins! User: Which 5 questions have the most comments, what is the post title and comment count"); query = SELECT Title, CommentCount FROM posts WHERE PostTypeId = 1 ORDER BY CommentCount DESC LIMIT 5; Run Time (s): real 3.587
-- prompt_fixup으로 SQL을 고칠 수도 있다. 악명 높은 "GROUP BY를 잊었다" 같은 것. D call prompt_fixup("select postTypeId, count(*) from posts"); query = SELECT postTypeId, COUNT(*) FROM posts GROUP BY postTypeId Run Time (s): real 12.006 -- 또는 잘못된 조인 컬럼 이름을 고치는 데 쓴다. D call prompt_fixup("select count(*) from posts join users on posts.userId = users.userId"); query = SELECT COUNT(*) FROM posts JOIN users ON posts.OwnerUserId = users.Id Run Time (s): real 2.378
| 기능 | 형태 | 하는 일 | 기재된 시간 |
|---|---|---|---|
| prompt_schema() | CALL | 데이터베이스 스키마를 요약해 서술한다 | 3.672 · 3.054 |
| prompt_query(…) | pragma | 자연어 질문을 SQL로 바꿔 실행하고 결과를 돌려준다 | 3.763 · 19.695 |
| prompt_sql(…) | CALL | 자연어 질문에 대해 생성된 SQL 문만 돌려준다 | 5.425 · 4.795 · 3.587 |
| prompt_fixup(…) | CALL | 잘못된 SQL 문을 고쳐 돌려준다 | 12.006 · 2.378 |
본문은 "이 AI 프롬프트의 실행 시간은 2초에서 10초 사이이며, 그 시간의 대부분이 LLM 안에서 소비된다"고 적었다. 그런데 같은 절에 인쇄된 아홉 개 측정값 가운데 둘이 그 범위를 벗어난다. prompt_query의 댓글 질문이 19.695초, prompt_fixup의 GROUP BY 예제가 12.006초다.
범위를 넘긴 둘이 우연히 가장 복잡한 질문과 가장 짧은 입력이라는 점도 눈에 걸린다. LLM 호출의 지연은 입력 길이만으로 예측되지 않으니, 대화형 대시보드의 응답 시간을 이 기능에 걸어두는 설계는 피하는 편이 좋다.
저자들의 총평은 균형이 잡혀 있다. 데이터베이스에 대한 질의를 생성하는 데 LLM을 쓰는 것에는 잠재력이 많고, 특히 모델이 데이터베이스 스키마로 증강될 수 있을 때 그렇다. 다만 보고서와 애플리케이션을 위해 전문가가 쓰고 조율한 질의를 대체하지는 못할 가능성이 크다. 그럼에도 데이터베이스 시스템을 훨씬 넓은 청중에게 접근할 수 있게 만들어줄 것이다. 무엇을 대체하고 무엇을 넓히는지를 나누어 적는 이 절제가 미덥다.
덧붙여, 2024년 초에 MotherDuck은 FixIt을 도입했다. 같은 기술에 기반한 UI용 빠른 SQL 오류 수정기이며, 구문이 잘못된 SQL 문이나 UI에 직접 인라인으로 있는 문장을 고쳐준다.
통합Integrations
MotherDuck은 다양한 데이터 전송, 비즈니스 인텔리전스, 데이터 시각화 도구를 지원한다. 저자들이 그린 그림의 구도는 이렇다. 왼쪽에서 오른쪽으로 가면서 중간에 선택적인 변환을 두면, MotherDuck이 파이프라인의 가운데에 앉을 수 있다.
원천은 직접 수집되거나 추가 서비스를 거쳐 수집되어 MotherDuck의 저장소에 놓이고, 그다음 비즈니스 인텔리전스 쓰임새나 특정 데이터 과학 도구가 그것을 질의한다. 그리고 한 가지가 더 붙는다. LLM 모델을 위한 검색 증강 생성(RAG)의 정보 검색 구성 요소로도 쓸 수 있다.
원서의 이 도판은 지원 도구들의 로고를 왼쪽(원천)에서 오른쪽(소비)으로 배치한 그림이다. 상표가 걸린 로고 모음이므로 이 문서에서 재현하지 않고 구도만 서술로 대신한다. 요지는 MotherDuck이 파이프라인의 어느 한쪽 끝이 아니라 가운데에 앉는다는 것이다.
그리고 그것에 필요한 것이 무엇인지를 저자들이 한 문장으로 적어둔다. 데이터베이스 접속 문자열에 md: 접두사를 끼워 넣고 ?motherduck_token=<token> 매개변수를 덧붙이는 것뿐이다. 제6장에서 duckdb.connect(':memory:')였던 자리가 duckdb.connect('md:?motherduck_token=…')으로 바뀌는 것 하나로 로컬이 클라우드가 된다. API를 바꾸지 않고 URL만 바꾸는 이 설계가 이 장 전체를 관통하는 요령이다.
제7장이 남긴 일곱 문장Summary
- MotherDuck은 브라우저에서 클라우드 저장소의 데이터를 질의하고 분석하기 쉽게 만들어주는 서버리스 데이터 분석 플랫폼이다.
md:프로토콜을 써서 DuckDB CLI와 파이썬 및 다른 언어 통합에 매끄럽게 통합되며, 그 프로토콜이 MotherDuck 확장을 자동으로 적재한다.- MotherDuck은 구조화된 데이터를 저장하고, SQL로 질의하고, 다른 사람과 공유하게 해준다.
- 이 서비스의 핵심 원칙 하나는 사용의 편의다. 인스턴스나 클러스터, 웨어하우스를 설정하거나 띄울 필요가 없다. 로컬에서 작업할 때와 같은 도구, 같은 생태계 안에서 SQL을 쓰고 제출하면 된다.
- 많은 경우 데이터 원천에 더 가까이 있기 때문에 로컬보다 MotherDuck에서 데이터를 훨씬 빠르게 수집할 수 있다.
- 로컬·원격·공유 데이터셋을 스키마와 관계의 완전한 이름을 써서 손쉽게 조인할 수 있다.
- 이 플랫폼은 자연어로 데이터셋을 질의하는 지원도 제공해, SQL을 배우지 않은 사람도 분석 데이터베이스의 이득을 볼 수 있게 한다.