我正在使用
DBI
/ROracle
.
conn <- dbConnect(ROracle::Oracle(), ...)
我需要从另一个表中的选择查询创建一个表(即像
create table <tabX> as select * from <tabY>
这样的语句)。
似乎有几个函数可以执行此任务,例如:
dbSendQuery(conn, "create table tab1 as select * from bigtable")
# Statement: create table tab1 as select * from bigtable
# Rows affected: 28196
# Row count: 0
# Select statement: FALSE
# Statement completed: TRUE
# OCI prefetch: FALSE
# Bulk read: 1000
# Bulk write: 1000
或:
dbExecute(conn, "create table tab2 as select * from bigtable")
# [1] 28196
甚至:
tab3 <- dbGetQuery(conn, "select * from bigtable")
dbWriteTable(conn = conn, "TAB3", tab3)
# [1] TRUE
每种方法似乎都有效,但我想在性能/最佳实践方面存在差异。运行像
create table <tabX> as select * from <tabY>
这样的语句的最佳/最有效方法是什么?
我没有在 DBI 和 ROracle 帮助页面中找到任何提示。
预先:为此使用
dbExecute
;不要使用dbSendQuery
,该函数建议返回数据的期望(尽管仍然有效)。
dbSendQuery
只应在您期望返回数据时使用;即使您使用不当,大多数连接也能正常工作,但这就是它的设计。相反,使用 dbSendStatement
/dbClearResult
或更好但只是 dbExecute
.
以下是一对完全等价的路径:
dat <- dbGetQuery(con, qry)
res <- dbSendQuery(con, qry); dat <- dbFetch(res); dbClearResult(res)
UPDATE
或INSERT
):
dbExecute(con, stmt)
res <- dbSendStatement(con, stmt); dbClearResult(res)
res <- dbSendQuery(con, stmt); dbClearResult(res)
(我认为有些数据库抱怨这种方法)如果您选择
dbSend*
,那么在完成语句/获取后,应该always调用dbClearResult
。 (R 通常会在你之后清理,但如果这里出现问题——我在过去几年中遇到过几次——连接会锁定,你必须重新创建它。这可能会在数据库中留下孤立连接也一样。)
我认为大多数用例都是单次查询和输出,这意味着
dbGetQuery
和dbExecute
是最容易使用的。但是,有时您可能想要重复查询。来自?dbSendQuery
的例子:
# Pass multiple sets of values with dbBind():
rs <- dbSendQuery(con, "SELECT * FROM mtcars WHERE cyl = ?")
dbBind(rs, list(6L))
dbFetch(rs)
dbBind(rs, list(8L))
dbFetch(rs)
dbClearResult(rs)
(我认为在没有捕获数据的情况下对
dbFetch
的文档有点草率......我希望dat <- dbFetch(..)
,在这里丢弃返回值似乎适得其反。)
执行此多步骤(需要
dbClearResult
)的一个优点是可以处理更复杂的查询:数据库服务器通常倾向于根据其执行引擎“编译”或优化查询。对于服务器来说,这并不总是一个非常昂贵的步骤来执行,而且它可以为数据检索带来巨大的好处。服务器经常缓存这个优化的查询,当它看到相同的查询时,它使用查询的已经优化的版本。这是使用参数绑定真正有用的一种情况,因为查询在重复使用中是相同的,因此永远不需要重新优化。
仅供参考,参数绑定可以如上所示使用
dbBind
重复完成,也可以使用 dbGetQuery
使用 params=
参数来完成。例如,这组等效的表达式将返回与上面相同的结果:
qry <- "SELECT * FROM mtcars WHERE cyl = ?"
dat6 <- dbGetQuery(con, qry, params = list(6L))
dat8 <- dbGetQuery(con, qry, params = list(8L))
至于
dbWriteTable
,对我来说主要是方便快捷的工作。有时 DBI/ODBC 连接在服务器上使用错误的数据类型(例如,SQL Server 的 DATETIME
而不是 DATETIMEOFFSET
;或者 NVARCHAR(32)
与 varchar(max)
),所以如果我需要快速的东西,我会使用dbWriteTable
,否则我将使用我知道我想要的服务器数据类型正式定义表,如dbExecute(con, "create table quux (...)")
。到目前为止,这 not 是“最佳实践”,它很大程度上植根于偏好和便利性。对于简单的数据(浮点数/整数/字符串)并且服务器默认数据类型是可以接受的,dbWriteTable
非常好。也可以使用 dbCreateTable
(创建它而不上传数据),它允许您指定具有更多控制权的字段。