sql-server - 并行计算环境中使用JDBC时服务器内存不足问题

标签 sql-server r memory garbage-collection rjdbc

我有一个具有 16 个核心和 8Gb RAM 的 R 服务器,它初始化一个由 10 个工作线程组成的本地 SNOW 集群。每个工作人员从 Microsoft SQL 服务器下载一系列数据集,将它们合并到某个键上,然后对数据集运行分析,然后将结果写入 SQL 服务器。 Worker 和 SQL Server 之间的连接通过 RJDBC 连接运行。当多个工作人员从 SQL 服务器获取数据时,内存使用量会激增,R 服务器会崩溃。

奇怪的是,与加载的数据集的大小相比,加载数据的工作人员使用的内存似乎不成比例地大。每个数据集大约有 8000 行和 6500 列。当在磁盘上保存为 R 对象时,这意味着大约 20MB;当保存为逗号分隔文件时,大约为 160MB。然而,R session 的 RAM 使用量约为 2.3 GB。

以下是代码概述(为了提高可读性而进行了一些排版更改):

使用 RJDBC 建立连接:

require("RJDBC")
drv <- JDBC("com.microsoft.sqlserver.jdbc.SQLServerDriver","sqljdbc4.jar")
con <<- dbConnect(drv, "jdbc:sqlserver://<some.ip>","<username>","<pass>")

在此之后,有一些代码对函数输入向量 requestedDataSets 进行排序,其中包含要按记录数查询的所有表的名称,以便我们从最大到最小加载数据集:

nrow.to.merge <- rep(0, length(requestedDataSets))
for(d in 1:length(requestedDataSets)){
nrow.to.merge[d] <- dbGetQuery(con, paste0("select count(*) from",requestedDataSets[d]))[1,1]
}
merge.order <- order(nrow.to.merge,decreasing = T)

然后我们遍历 requestDatasets 向量并加载和/或合并数据:

for(d in merge.order){
    # force reconnect to SQL server
    drv <- JDBC("com.microsoft.sqlserver.jdbc.SQLServerDriver","sqljdbc4.jar")
    try(dbDisconnect(con), silent = T)
    con <<- dbConnect(drv, "jdbc:sqlserver://<some.ip>","<user>","<pass>")
    # remove the to.merge object
    rm(complete.data.to.merge)
    # force garbage collection
    gc()
    jgc()
    # ask database for dataset d
    complete.data.to.merge <- dbGetQuery(con, paste0("select * from",requestedDataSets[d]))
    # first dataset
    if (d == merge.order[1]){
        complete.data <- complete.data.to.merge
        colnames(complete.data)[colnames(complete.data) == "key"] <- "key_1"
    } 
    # later dataset
    else {
        complete.data <- merge(
                         x = complete.data, 
                         y = complete.data.to.merge,
                         by.x = "key_1", by.y = "key", all.x=T)
    }
}
return(complete.data)

当我在一系列十二个数据集上运行此代码时,complete.data 对象的行/列数符合预期,因此合并调用不太可能以某种方式破坏使用情况。对于十二次迭代,memory.size() 返回 1178、1364、1500、1662、1656、1925、1835、1987、2106、2130、2217 和 2361。这又很奇怪,因为最后的数据集最多 162 MB...

正如您在上面的代码中看到的,我已经尝试了一些修复,例如调用 GC()、JGC()(这是一个强制 Java 垃圾回收的函数 jgc <- function(){ .jcall("java/lang/System", method = "gc")}).我还尝试过合并 SQL 服务器端的数据,但后来遇到了列数限制。

令我烦恼的是,RAM 使用量比最终创建的数据集大得多,让我相信存在某种缓冲区/堆溢出......但我似乎无法找到它。

任何有关如何解决此问题的建议将不胜感激。如果我的问题描述(部分)含糊不清或者您需要更多信息,请告诉我。

谢谢。

最佳答案

这个答案更像是一个美化的评论。仅仅因为一个节点上处理的数据只需要 160MB,并不意味着处理它所需的内存量就是 160MB。许多算法需要 O(n^2) 存储空间,对于您的数据 block 来说,该空间以 GB 为单位。所以我实际上没有看到任何不足为奇的东西。

I've already tried a couple of fixes like calling GC(), JGC() (which is a function to force a Java garbage collection...

你不能在 Java 中强制进行垃圾回收,只能礼貌地调用 System.gc() 要求 JVM 进行垃圾回收,但它可以自由地进行垃圾回收。如果需要,请忽略该请求。无论如何,JVM 通常会自行很好地优化垃圾收集,我怀疑这是您的瓶颈。更有可能的是,您只是利用了 R 处理数据所需的开销。

关于sql-server - 并行计算环境中使用JDBC时服务器内存不足问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40611525/

相关文章:

r - 使用 extrafont 将字体导入 R 时,如何解决 "No Font Name"问题?

r - R中的双聚类

r - 是否存在 table() 函数的一般逆函数?

C++ 内存分配 new[] 和 delete[]

Python:每个对象类型(或源代码行)的内存使用统计

c - 在应用程序中禁用 Linux 内存过度使用

sql-server - 相当于在 SQL Server 中拖尾 MongoDB 操作日志?

sql-server - 当 set_identity 关闭时,如何将 Spark 数据帧推送到 Sql Server 表?

c# - 当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'IncomeTable' 中为标识列插入显式值

sql - Sql Server 中的标识列