DuckDB R 客户端的最新稳定版本为 1.4.4。
安装
duckdb: R 客户端
可以使用以下命令安装 DuckDB R 客户端
install.packages("duckdb")
详情请参阅安装页面。
duckplyr: dplyr 客户端
DuckDB 通过 duckplyr 软件包提供与 dplyr 兼容的 API。可以通过 install.packages("duckplyr") 进行安装。详情请参阅 duckplyr 文档。
参考手册
DuckDB R 客户端的参考手册可在 r.duckdb.org 查看。
客户端基础用法
标准的 DuckDB R 客户端实现了 R 的 DBI 接口。如果您还不熟悉 DBI,请参阅使用 DBI 页面获取入门指南。
启动与关闭
要使用 DuckDB,必须首先创建一个代表数据库的连接对象。连接对象以读写操作的数据库文件作为参数。如果数据库文件不存在,将会被创建(文件扩展名可以是 .db、.duckdb 或其他任何名称)。特殊值 :memory:(默认值)可用于创建内存数据库。请注意,内存数据库的数据不会持久化到磁盘(即当您退出 R 进程时,所有数据都会丢失)。如果您希望以只读模式连接到现有的数据库,请将 read_only 标志设置为 TRUE。如果多个 R 进程需要同时访问同一个数据库文件,则必须使用只读模式。
library("duckdb")
# to start an in-memory database
con <- dbConnect(duckdb())
# or
con <- dbConnect(duckdb(), dbdir = ":memory:")
# to use a database file (not shared between processes)
con <- dbConnect(duckdb(), dbdir = "my-db.duckdb", read_only = FALSE)
# to use a database file (shared between processes)
con <- dbConnect(duckdb(), dbdir = "my-db.duckdb", read_only = TRUE)
连接在超出作用域时会自动关闭,也可以使用 dbDisconnect() 显式关闭。若要关闭与连接关联的数据库实例,请使用 dbDisconnect(con, shutdown = TRUE)
查询
DuckDB 支持发送查询和获取结果集的标准 DBI 方法。dbExecute() 适用于不需要返回结果的查询,如 CREATE TABLE 或 UPDATE 等;而 dbGetQuery() 适用于产生结果的查询(例如 SELECT)。以下是一个示例。
# create a table
dbExecute(con, "CREATE TABLE items (item VARCHAR, value DECIMAL(10, 2), count INTEGER)")
# insert two items into the table
dbExecute(con, "INSERT INTO items VALUES ('jeans', 20.0, 1), ('hammer', 42.2, 2)")
# retrieve the items again
res <- dbGetQuery(con, "SELECT * FROM items")
print(res)
# item value count
# 1 jeans 20.0 1
# 2 hammer 42.2 2
DuckDB 的 R 客户端还通过 dbExecute 和 dbGetQuery 方法支持预处理语句。以下是一个示例
# prepared statement parameters are given as a list
dbExecute(con, "INSERT INTO items VALUES (?, ?, ?)", list('laptop', 2000, 1))
# if you want to reuse a prepared statement multiple times, use dbSendStatement() and dbBind()
stmt <- dbSendStatement(con, "INSERT INTO items VALUES (?, ?, ?)")
dbBind(stmt, list('iphone', 300, 2))
dbBind(stmt, list('android', 3.5, 1))
dbClearResult(stmt)
# query the database using a prepared statement
res <- dbGetQuery(con, "SELECT item FROM items WHERE value > ?", list(400))
print(res)
# item
# 1 laptop
警告:请不要使用预处理语句向 DuckDB 插入大量数据。请参考下文了解更好的方案。
高效传输
若要将 R 数据框(data frame)写入 DuckDB,请使用标准的 DBI 函数 dbWriteTable()。这会在 DuckDB 中创建一个表并用数据框的内容进行填充。例如
dbWriteTable(con, "iris_table", iris)
res <- dbGetQuery(con, "SELECT * FROM iris_table LIMIT 1")
print(res)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa
还可以将 R 数据框“注册”为虚拟表,这类似于 SQL 中的 VIEW。这不会立即将数据传输到 DuckDB 中。以下是一个示例
duckdb_register(con, "iris_view", iris)
res <- dbGetQuery(con, "SELECT * FROM iris_view LIMIT 1")
print(res)
# Sepal.Length Sepal.Width Petal.Length Petal.Width Species
# 1 5.1 3.5 1.4 0.2 setosa
注册后,DuckDB 会保留对 R 数据框的引用,以防止该数据框被垃圾回收。该引用在连接关闭时会自动清除,也可以使用
duckdb_unregister()方法手动清除。
另请参阅数据导入文档,了解更多高效导入数据的选项。
dbplyr
DuckDB 也与 dbplyr / dplyr 软件包配合良好,可用于在 R 中进行程序化查询构建。以下是一个示例
library("duckdb")
library("dplyr")
con <- dbConnect(duckdb())
duckdb_register(con, "flights", nycflights13::flights)
tbl(con, "flights") |>
group_by(dest) |>
summarise(delay = mean(dep_time, na.rm = TRUE)) |>
collect()
使用 dbplyr 时,可以使用 dplyr::tbl 函数读取 CSV 和 Parquet 文件。
# Establish a CSV for the sake of this example
write.csv(mtcars, "mtcars.csv")
# Summarize the dataset in DuckDB to avoid reading the entire CSV into R's memory
tbl(con, "mtcars.csv") |>
group_by(cyl) |>
summarise(across(disp:wt, .fns = mean)) |>
collect()
# Establish a set of Parquet files
dbExecute(con, "COPY flights TO 'dataset' (FORMAT parquet, PARTITION_BY (year, month))")
# Summarize the dataset in DuckDB to avoid reading 12 Parquet files into R's memory
tbl(con, "read_parquet('dataset/**/*.parquet', hive_partitioning = true)") |>
filter(month == "3") |>
summarise(delay = mean(dep_time, na.rm = TRUE)) |>
collect()
内存限制
您可以使用 memory_limit 配置选项来限制 DuckDB 的内存使用,例如
SET memory_limit = '2GB';
请注意,此限制仅应用于 DuckDB 使用的内存,不会影响其他 R 库的内存使用。因此,R 进程使用的总内存可能高于配置的 memory_limit。
故障排除
macOS 安装警告
在 macOS 上,安装 DuckDB 可能会导致警告 unable to load shared object '.../R_X11.so'
Warning message:
In doTryCatch(return(expr), name, parentenv, handler) :
unable to load shared object '/Library/Frameworks/R.framework/Resources/modules//R_X11.so':
dlopen(/Library/Frameworks/R.framework/Resources/modules//R_X11.so, 0x0006): Library not loaded: /opt/X11/lib/libSM.6.dylib
Referenced from: <31EADEB5-0A17-3546-9944-9B3747071FE8> /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/modules/R_X11.so
Reason: tried: '/opt/X11/lib/libSM.6.dylib' (no such file) ...
> ')
请注意,这只是一个警告,最简单的解决方法是忽略它。或者,您可以从 R-universe 安装 DuckDB
install.packages("duckdb", repos = c("https://duckdb.r-universe.dev", "https://cloud.r-project.org"))
您也可以通过 Homebrew 安装可选的 xquartz 依赖项。