如何以比这更快的方式将数据从 oracle 检索到 R?

How to retrieve data from oracle to R in a faster way than this?

这是我的数据框

trail_df= data.frame(d= seq.Date(as.Date("2020-01-01"), as.Date("2020-02-01"), by= 1),
                      AA= NA,
                      BB= NA,
                      CC= NA)

现在我将循环到 trail_df 的列并分别从 oracle 数据库中获取给定日期的列名数据,我正在这样做。

for ( i in 2:ncol(trail_df)){
      c_name = colnames(trail_df)[i]
      query = paste0("SELECT * FROM tablename WHERE ID= '",c_name,"' ")   # this query would return Date and price
      result= dbGetQuery(con, query)              # con is the connection variable from db
      
      for (k in nrow(trail_df)){
          trail_df [which(as.Date(result[k,1])==as.Date(trail_df[,1])),i]= result[k,2]
          # just matching the date in trail_df dataframe and pasting the value in front of respective column
  }
}
           

这是代码片段和日期过滤,所有内容都已在实际代码中处理。

问题是,我有超过 6000 列和 500 行,我必须匹配日期( 因为日期是随机的)并把价格放在前面,现在这就像永远一样。

我是 R 语言的新手,如果有任何帮助可以在 R 中固定此代码或多进程,我将不胜感激。

这个答案有两个步骤:

  1. 使用参数化查询获取原始数据;和
  2. 将此数据转换为您想要的“宽”格式。

参数化查询

我的(第一个)建议是使用parameterized queries,这样更安全。相对于@RonakShah 的回答(使用 sprintf),它可能不会提高速度,至少第一次不会。

但是,如果重复查询,a touch 可能会有所帮助:DBMS 倾向于 parse/optimize 查询并缓存此优化。当一个查询发生一点点变化时,这种缓存就不会发生,并且查询会被重新优化。在这种情况下,这种缓存失效是不必要的,如果我们使用绑定参数就可以避免。

query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s)",
                 paste(rep("?", ncol(trail_df[-1])), collapse = ","))
query
# [1] "SELECT * FROM tablename WHERE ID IN (?,?,?)"
res <- dbGetQuery(con, query, params = list(trail_df$ID))

一些想法:

  • 如果数据库的日期比您在这里的日期多很多,您可以通过减少日期范围查询来限制返回的数据。如果您的 trail_df 日期很近,这将很有效:

    query <- sprintf("SELECT * FROM tablename WHERE ID IN (%s) and Date between ? and ?",
                     paste(rep("?", ncol(mtcars)), collapse = ","))
    query
    res <- dbGetQuery(con, query, params = c(list(trail_df$ID), as.list(range(df$d))))
    
  • 如果你的日期变化很大,你最终查询的行比你实际需要的多,我建议你可以将你的 trail_df 日期上传到一个临时的 table 和类似于:

    "select tb.Date, tb.ID, tb.Price
       from mytemptable tmp
       left join tablename tb on tmp.d = tb.Date
     where ..."
    

重塑

看起来您的数据库 table 可能更“长”,而您希望它在框架中“宽”。有很多方法可以从长到宽 (examples) 进行重塑,但这些应该有效:

reshape2::dcast(res, Date ~ ID, value.var = "Price") # 'Price' is the 'value' column, unk here

tidyr::pivot_wider(res, id_cols = "Date", names_from = "ID", values.from = "Price")