首先,慢的部分可能是
cast(...)
,因此不要在每个查询中两次执行此操作,而是将
start
和
realized
保留为时间戳,并更改查询以适应此情况。
其次,
data.table
选项仍然快了约100倍(但是请参阅末尾关于使用
sqldf
索引的部分)。
library(sqldf)
library(data.table)
N <- 1e6
set.seed(1)
df <- data.frame(start=as.character(as.POSIXct("2000-01-01")+sample(0:1e6,N,replace=T)),
realized=as.character(as.POSIXct("2000-01-01")+sample(0:1e6,N,replace=T)),
V1=rnorm(N), V2=rpois(N,4))
sometime <- "2000-01-05 00:00:00"
query <- "SELECT V1, V2 FROM df WHERE start <= datetime('%s') and realized > datetime('%s')"
query <- sprintf(query,sometime,sometime)
system.time(result.sqldf <- sqldf(query))
set.seed(1)
DT <- data.table(start=as.POSIXct("2000-01-01")+sample(0:1e6,N,replace=T),
realized=as.POSIXct("2000-01-01")+sample(0:1e6,N,replace=T),
V1=rnorm(N), V2=rpois(N,4))
setkey(DT,start,realized)
system.time(result.dt <- DT[start<=as.POSIXct(sometime) & realized > as.POSIXct(sometime),list(V1,V2)])
请注意,这两个结果集将以不同的方式排序。
根据@G.Grothendieck(
sqldf
包的作者)下面的评论进行编辑。
这正在成为包之间的一个非常好的比较...
sqldf()
sqldf("create index ix on df(start, realized)")
query <- fn$identity("SELECT V1, V2 FROM main.df WHERE start <= '$sometime' and realized > '$sometime'")
system.time(result.sqldf <- sqldf(query))
sqldf()
因此,在这种情况下,创建索引可以使sqldf
的速度提高约10倍。索引创建很慢,但您只需要执行一次。在data.table中创建“key”(物理排序表)非常快,但在这种情况下并没有显著提高性能(仅提高约2倍)。
使用system.time()
进行基准测试有一定风险(1个数据点),因此最好使用microbenchmark(...)
。请注意,为了使其正常工作,我们必须运行上面的代码,并保持连接打开(例如,删除对sqldf()
的最后一次调用)。
f.dt <- function() result.dt <- DT[start<=as.POSIXct(sometime) & realized > as.POSIXct(sometime),list(V1,V2)]
f.sqldf <- function() result.sqldf <- sqldf(query)
library(microbenchmark)
microbenchmark(f.dt(),f.sqldf())
我们可以看到,在这种情况下,使用关键字的 data.table
比使用索引的 sqldf
快了约 6 倍。实际时间将取决于结果集的大小,因此您可能希望比较这两个选项。
data.table
包,它可以让你为表格构建真正的索引,从而使搜索更快。 - MrFlickdata.table
不会 "建立真正的索引"。请参考这个问题/答案。但是,使用它会更快。 - jlhoward