데이터 가져오기
데이터 가져오기 (Import Data)
Go 클라이언트에는 데이터를 DuckDB에 벌크로 넣는 두 가지 방식이 있어요. Go에서 생성한 행을 삽입하는 고성능 Appender와, Parquet·CSV·JSON 같은 데이터 파일에서 직접 읽는 방식이에요. 둘 다 아래에서 살펴볼게요. 몇 개 안 되는 행을 삽입할 때는 일반 [INSERT 문]({% link docs/current/clients/go/querying.md %}#sending-statements)으로 충분해요. 여기의 옵션들은 대량 데이터를 위한 거예요.
출처: 문서
본문
Appender
[Appender]({% link docs/current/data/appender.md %})는 Go에서 생성한 행을 삽입하는 가장 빠른 방법이에요. INSERT 문을 내는 것보다 훨씬 빨라요. Appender는 raw DuckDB 커넥션에서 동작하므로 *sql.DB가 아니라 Connector에서 만들어요. 커넥터에서 커넥션을 얻은 뒤 대상 테이블에 대한 appender를 duckdb.NewAppenderFromConn()으로 만들고 스키마(기본이면 빈 문자열)와 테이블 이름을 넘겨요.
connector, err := duckdb.NewConnector("test.db", nil)
if err != nil {
log.Fatal(err)
}
defer connector.Close()
conn, err := connector.Connect(context.Background())
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// The table must already exist.
appender, err := duckdb.NewAppenderFromConn(conn, "", "users")
if err != nil {
log.Fatal(err)
}
defer appender.Close()
// Each argument is one column value, in table column order.
if err := appender.AppendRow("Fred", int32(34)); err != nil {
log.Fatal(err)
}
AppendRow()의 각 인자는 테이블 열 순서대로 된 열 값이고, 그 Go 타입은 열의 DuckDB 타입과 일치해야 해요. 예시는 INTEGER 열에 int32(34)를 넘겨요. 행마다 AppendRow()를 한 번 호출해요.
Warning appender는 행을 버퍼링해 청크 단위로 DuckDB에 플러시하므로,
NOT NULL이나 외래 키 위반 같은 제약 조건 위반이 그 행을 추가한AppendRow()호출이 아니라 버퍼가 플러시될 때 드러날 수 있어요. 대기 중인 행을 신뢰하기 전에Flush()를 호출하고 그 오류를 확인하고, 최종 플러시를 수행하는Close()의 오류도 항상 확인하세요.
다음은 클라이언트의 appender 예시를 따르는 코드로, 같은 커넥터에서 연 *sql.DB로 테이블을 만들고, 행을 추가한 뒤 다시 읽어요.
package main
import (
"context"
"database/sql"
"log"
"github.com/duckdb/duckdb-go/v2"
)
func main() {
c, err := duckdb.NewConnector("", nil)
if err != nil {
log.Fatal(err)
}
defer c.Close()
con, err := c.Connect(context.Background())
if err != nil {
log.Fatal(err)
}
defer con.Close()
db := sql.OpenDB(c)
defer db.Close()
if _, err := db.Exec(`CREATE TABLE users (name VARCHAR, age INTEGER)`); err != nil {
log.Fatal(err)
}
a, err := duckdb.NewAppenderFromConn(con, "", "users")
if err != nil {
log.Fatal(err)
}
if err := a.AppendRow("Fred", int32(34)); err != nil {
log.Fatal(err)
}
// Close flushes any buffered rows before closing the appender.
if err := a.Close(); err != nil {
log.Fatal(err)
}
var (
name string
age int
)
row := db.QueryRowContext(context.Background(), `SELECT name, age FROM users`)
if err := row.Scan(&name, &age); err != nil {
log.Fatal(err)
}
log.Printf("User: name=%s, age=%d", name, age)
}
다른 스키마와 열 부분집합 대상 지정
패키지는 다른 카탈로그·스키마 대상 지정, 열 부분집합 선택, 또는 배치를 추가하면서 변환하는 더 많은 생성자를 제공해요. 각각은 첫 인자로 driver.Conn을 받아요.
duckdb.NewAppender(driverConn, catalog, schema, table)— 지정된 테이블의 모든 열에 추가해요.duckdb.NewTableAppender(driverConn, query, catalog, schema, table, columnNames)— 버퍼링된 배치마다INSERT,DELETE,UPDATE,MERGE INTO쿼리를 실행해요. 대상 테이블의 이름 있는 열에서 입력 타입을 추론해요. 빈 열 이름 슬라이스를 넘기면 모든 열을 사용해요.duckdb.NewQueryAppender(driverConn, query, temporaryTable, columnTypes, columnNames)— 배치마다 쿼리도 실행하지만, 호출자가 임시 입력 테이블의 이름, 열 타입, 열 이름을 지정할 수 있어요.
duckdb.NewAppenderWithColumns(driverConn, catalog, schema, table, columnNames)도 열의 부분집합을 추가하면서 다른 열은 기본값이나 NULL로 남길 수 있어요. 주로 하위 호환성 때문에 유지돼요. 쿼리 기반 appender가 더 성능이 좋으므로 이 경우엔 NewTableAppender를 선호하세요.
데이터 파일 읽기
DuckDB는 많은 파일 포맷을 SQL에서 직접 읽을 수 있어서, 외부 데이터를 로드하는 가장 간단한 방법인 경우가 많아요. Go 클라이언트는 그저 쿼리를 보내면 돼요. [Parquet]({% link docs/current/data/parquet/overview.md %}), [CSV]({% link docs/current/data/csv/overview.md %}), [JSON]({% link docs/current/data/json/overview.md %}) 리더가 [bundle 확장]({% link docs/current/clients/go/overview.md %}#bundled-extensions)에 포함돼 있어서 추가 설치가 필요 없어요. 일치하는 테이블 함수로 파일을 그자리에서 쿼리해요.
rows, err := db.QueryContext(ctx, `SELECT * FROM read_parquet('data.parquet')`)
같은 패턴으로 read_csv()는 CSV, read_json()은 JSON을 읽어요. 파일을 그 자리에서 쿼리하는 대신 테이블로 로드하려면 리더를 Exec로 보낸 [CREATE TABLE ... AS SELECT]({% link docs/current/sql/statements/create_table.md %}#create-table--as-select-ctas)나 [COPY]({% link docs/current/sql/statements/copy.md %}) 문으로 감싸면 돼요.
_, err := db.ExecContext(ctx, `CREATE TABLE data AS SELECT * FROM read_parquet('data.parquet')`)
더 알아보기 (Learn more)
- [Appender]({% link docs/current/data/appender.md %}) — Go
Appender가 감싸는 엔진 레벨 Appender 인터페이스. - [Data Import]({% link docs/current/data/overview.md %}) — DuckDB의 벌크 로딩 옵션 전체.
- [Run Queries]({% link docs/current/clients/go/querying.md %}) — 파일 리더가 기반으로 하는
CREATE TABLE과COPY문 보내기. - [Connect]({% link docs/current/clients/go/connecting.md %}) — Appender가 동작하는
Connector와 커넥션 만들기.