TL;DR

  • DuckDB 데이터베이스 파일은 데이터 자체를 저장하지 않고 원격 Parquet 파일을 가리키는 뷰 정의만 저장해, 데이터 레이크 전체를 조회하는 수백 킬로바이트 규모의 공유 카탈로그가 됨.
  • 뷰는 쿼리 텍스트만 저장하며, 원격 파일을 읽는 쿼리는 조회 시점의 데이터를 반환함.
  • 네덜란드 철도 운행 데이터 사례에서 httpfs 확장 프로그램을 설치하고, 원격 Parquet 파일을 가리키는 services 뷰를 영속 데이터베이스에 생성함.
  • 카탈로그 파일을 네트워크에서 접근 가능한 위치에 호스팅하고 읽기 전용으로 연결하면, 개별 파일 경로를 공유하지 않고도 명명된 관계를 조회할 수 있음.
  • 파일 분할·재배치·열 이름 변경은 카탈로그의 뷰 정의를 갱신해 처리할 수 있지만, 소비자는 카탈로그와 참조 데이터 모두에 접근할 수 있어야 함.

아이디어

  • DuckDB 테이블은 행을 데이터베이스 파일 안에 저장하지만, 뷰는 쿼리 텍스트만 저장하며 조회 시 쿼리를 실행해 현재 결과를 반환함.
  • 원격 Parquet 파일을 읽는 쿼리라면 데이터는 오브젝트 스토리지에 남고, 뷰에는 데이터를 읽는 방법만 저장됨.
  • 뷰만으로 구성된 데이터베이스 파일은 자체 행 데이터 없이, 원래 위치와 형식에 있는 데이터를 기반으로 명명된 관계를 제공하는 카탈로그임.
  • 이 카탈로그는 데이터 레이크 위의 선별된 의미 계층으로 게시할 수 있으며, 뷰 정의에 조인·필터·열 이름을 담아 소비자가 사용할 방식을 지정할 수 있음. 이 과정에서 원본 데이터를 복사하거나 이동하지 않음.
  • Nikolas Goebel의 DuckDB doesn't need data는 현대 데이터베이스에서 데이터 저장 위치와 읽는 방식이 분리돼, 대부분의 데이터베이스가 자체 데이터를 보유할 필요가 없어졌다는 관점을 제시함. 이 관점에서 DuckDB는 로컬 디스크에 복사본을 두는 대신 URL을 통해 데이터셋에 접근하는 데이터 클라우드 브라우저임.

뷰 카탈로그 만들기

  • 예시는 네덜란드 철도 열차가 정차하는 모든 역을 행 단위로 기록한 DuckDB 공개 열차 운행 데이터셋을 사용함. 데이터는 Rijden de Treinen(열차 운행 정보) 애플리케이션이 공개한 데이터셋에서 제공되며, URL로 직접 읽을 수 있음.
  • DuckDB가 네트워크에서 데이터를 읽도록 httpfs 확장 프로그램을 설치함. 이 설치는 한 번만 수행하면 됨.
  • rail_catalog.duckdb라는 영속 데이터베이스 파일을 연결하고, 별칭 rail을 지정한 뒤 services 뷰를 생성해 https://blobs.duckdb.org/train_services.parquet의 데이터를 가리키게 함.
  • 뷰가 클라이언트의 작업 디렉터리와 관계없이 파일을 찾도록 전체 경로를 사용해야 함. 전체 경로는 원격 URL 또는 절대 경로를 의미함.
  • rail.services에서 departure_time, station_name, type 열을 조회해 처음 세 행을 확인하는 예시의 결과는 다음과 같음.
  • 2023-05-15 00:00:00 / Rotterdam Centraal / Intercity
  • 2023-05-15 00:13:00 / Delft / Intercity
  • 2023-05-15 00:29:00 / Den Haag HS / Intercity
  • 파일에는 뷰 정의만 저장되므로 참조 데이터셋이 커져도 카탈로그 크기는 작게 유지됨. train_services.parquet에는 380,959개 행이 있지만, 이를 조회하는 카탈로그는 수백 킬로바이트 규모임.

카탈로그 호스팅

  • rail_catalog.duckdb를 DuckDB가 네트워크로 읽을 수 있는 위치에 업로드할 수 있으며, 예시는 s3:// 버킷 또는 https:// 엔드포인트임. Parquet 파일이 이미 있는 버킷을 함께 사용하는 방법도 있음.
  • 카탈로그를 공유하면 개별 파일 경로 목록 대신 URL 하나를 전달하면 됨. 수신자는 각 뷰가 몇 개 파일을 참조하는지, 파일이 어디에 저장됐는지 알 필요 없이 카탈로그 주소만 알면 됨.

카탈로그를 읽기 전용으로 연결

  • 소비자는 카탈로그를 읽기 전용으로 연결하고, 뷰를 로컬 테이블처럼 조회함. 각 쿼리는 참조 파일에서 최신 데이터를 읽으므로 결과는 해당 시점의 오브젝트 스토리지 내용에 따라 달라짐.
  • https://example.com/rail_catalog.duckdb를 별칭 rail로 읽기 전용 연결한 다음, 역별 호출 수를 집계하고 내림차순으로 정렬해 상위 세 역을 조회하는 예시의 결과는 다음과 같음.
  • Utrecht Centraal: 7,663회
  • Amsterdam Centraal: 7,591회
  • Zwolle: 5,013회
  • 소비자는 httpfs 확장 프로그램이 필요하며, s3:// 소스에는 원본 데이터 접근 권한을 부여하는 자격 증명이 필요함.
  • DuckDB는 쿼리에 필요한 열과 행 그룹만 읽으므로, 대규모 원격 데이터셋에 대한 필터링 또는 집계 쿼리에서도 전체 데이터를 내려받지 않음.

데이터 레이아웃 변경에도 유지되는 쿼리

  • 소비자가 파일을 직접 읽지 않고 뷰를 조회하므로, 게시자는 쿼리를 바꾸지 않고도 파일 구성을 변경할 수 있음.
  • 단일 Parquet 파일이 너무 커져 연도별 파일로 나뉘는 경우, 카탈로그에서 뷰가 파일 디렉터리를 읽도록 한 줄을 바꾸면 되며 소비자는 변경을 알아차리지 못함. 예시 경로는 s3://my-bucket/rail/services/year=*/*.parquet임.
  • 파일의 열 이름이 바뀌어도 뷰에서 스키마를 안정적으로 유지할 수 있음. 후속 파일에서 station_name이 station으로 바뀌면, 뷰가 새 열을 기존 이름인 station_name으로 매핑하도록 설정할 수 있음. 예시 경로는 s3://my-bucket/rail/services/*.parquet임.
  • 파일을 재분할하거나 새 버킷으로 옮기는 경우 카탈로그만 갱신하면 되며, 카탈로그를 조회하는 쪽은 기존 쿼리를 계속 실행함.

사용 시점

  • 수신자에게 개별 파일 경로를 길게 나열해 전달하지 않고 데이터셋을 공유하려는 경우, 그리고 데이터가 Parquet처럼 DuckDB가 잘 읽는 형식인 경우에 이 패턴을 사용할 수 있음.
  • 독자는 조회할 수 있는 명명된 관계를 제공받으며, 게시자는 쿼리를 깨뜨리지 않고 파일 레이아웃을 바꿀 수 있음.
  • 다음 제약이 있음.
  • 소비자는 카탈로그 파일과 뷰가 참조하는 모든 데이터 소스에 접근할 수 있어야 함.
  • HTTPS 연결과 S3 API는 읽기 전용이므로 카탈로그를 해당 위치에서 직접 수정할 수 없음. 뷰를 바꾸려면 로컬 복사본을 편집한 뒤 다시 업로드해야 함.
  • 쿼리 성능은 네트워크와 참조 파일의 레이아웃에 좌우됨. 원격 파일 조회 관련 팁을 적용할 수 있음.

결론

  • 뷰만 저장하는 DuckDB 파일은 URL 하나로 공유할 수 있는 작은 카탈로그임.
  • 데이터는 원래 위치에 남고, 게시자는 저장 방식을 바꿀 수 있으며, 독자는 안정적인 관계 집합을 조회할 수 있음.
  • 전체 안내는 Share a DuckDB Database That Only Stores Views에서 확인할 수 있음.