R中注册Data Frame到DuckDB是否复制数据?虚拟表未同步问题
问题:R中DuckDB虚拟表未同步原data.table的修改
我正在学习在R中使用DuckDB。根据文档和网络资料,将Data Frame注册为虚拟表时不会复制数据,而是创建指向该Data Frame的指针。
我创建了data.table格式的Data Frame,注册为DuckDB虚拟表后,查询发现其行数与原Data Frame一致(50行)。但删除原data.table部分行(剩余38行)后,再次查询虚拟表,行数仍为50行,未同步变化。
复现代码
dt_cars <- as.data.table(cars) dt_cars[, .N] # 50. so far, so good # 获取数据库连接 conn <- dbConnect(duckdb::duckdb()) duckdb_register(conn, name = 'tbl_cars', df = dt_cars) query <- 'select count(*) as records from tbl_cars' results <- dbGetQuery(conn, statement = query) %>% data.table() results # 50. that makes sense dt_cars <- dt_cars[speed < 20, ] dt_cars[, .N] # 38. that worked query <- 'select count(*) as records from tbl_cars' results <- dbGetQuery(conn, statement = query) %>% data.table() results # still fifty!
解答
一、DuckDB虚拟表注册的实际机制
用duckdb_register()注册Data Frame为虚拟表时,DuckDB确实不会复制整个数据集,但它并非创建能实时追踪原对象变化的动态指针:
- DuckDB会获取当前Data Frame在内存中的快照引用,记录该对象的内存地址与数据结构信息。
- 对于data.table这类对象,DuckDB会读取其底层列存储的数据,但不会持续监听原对象的后续修改操作。
二、修改原data.table后虚拟表未同步的核心原因
你代码里的dt_cars <- dt_cars[speed < 20, ]并非对原data.table做原地修改,而是生成了一个全新的data.table对象,并让dt_cars变量重新指向这个新对象:
- 最初被DuckDB引用的50行data.table对象依然存在于内存中(未被修改或删除,除非触发垃圾回收)。
- DuckDB的虚拟表始终指向最初的旧对象,因此查询结果还是50行。
同步数据变化的两种方法
- 原地修改原data.table:使用data.table的原地修改语法(比如
dt_cars[speed >= 20, ] <- NULL),之后重新注册虚拟表或刷新连接。 - 重新注册虚拟表:修改数据后,调用
duckdb_register(conn, name = 'tbl_cars', df = dt_cars, overwrite = TRUE)覆盖原虚拟表,让DuckDB指向新的data.table对象。
内容的提问来源于stack exchange,提问作者mac_in_texas
相关产品推荐
相关产品推荐

