如何避免超时错误将大文件并行加载到mysql

时间:2018-01-02 09:53:49

标签: mysql r database parallel-processing rmysql

我必须循环浏览单独存储在各个csv文件中的几组数据 - 大约1500个文件。每个文件代表给定日期的活动量,每个文件中的数据量基本上从无到有。

我的过程是我将数据加载到R,预处理和清理,然后我插入到本地mysql表中。这可以作为单个循环正常运行。

为了提高加载速度,我尝试将循环移动到一个并行进程中,我有几个工作程序预处理单独的文件,然后将每个文件加载到数据库中。

当某些文件很大时我遇到错误,dbwritetable调用需要一些时间来处理。这似乎会锁定表,不允许其他进程完成写入,从而导致超时错误。

我对mysql相当新,我隐约知道我可以在数据库级别更改mysql超时时间(我相信使用conf文件)。这是最好/唯一的解决方案吗?我希望将所有控件保持在R级别,这样我就可以更轻松地在不同的机器上运行此代码。我想知道是否有另一种方法可以保持队列中的进程并在表可用时按顺序写入负载。

更新

我认为这是一个关于如何处理超时的简单问题,但听起来似乎需要更多信息。这是一个例子 - 它并不复杂。

  Bluetooth.loadloop <- foreach(i=jump:LoopLength, .inorder=TRUE) %dopar% {


    Start.Time <- Sys.time()
    x <- filenames[i]  

    if(!length(readLines(x))) {
      Stats <- data.frame(
        i=i, 
        time=difftime(Sys.time(),Start.Time,units='secs'),
        DataList= 0 )

      source("/Shared_Functions/MYSQL_LOGIN.r" )
      invisible(dbWriteTable(con, name="RawData_Loadloop_Stats_Bluetooth",value=Stats, append=TRUE, row.names=FALSE))
      dbDisconnect(con)
      print( "Zero length");

      return("Zero length")
    } else {


      ### Loads Data from CSV
      print(paste(i,"Start"))
      datalist <-readLines(x,encoding="UTF-8")
      filelocation <- (paste(i,x))
      datalist.length <- length(datalist)
      print(datalist.length)


      ### Proceses the individual fields 
      deviceID <- v1 <- gsub("([0-9]+),.*", "\\1", datalist)
      Time <- v2 <- gsub("[0-9]+,([0-9]+),.*", "\\1", datalist)
      Label <- v3 <- gsub("^[0-9]+,[0-9]+,(.*),([a-zA-Z0-9:]+),([^,]+)$", "\\1", datalist)
      MacAddress <- v4 <- gsub("^[0-9]+,[0-9]+,(.*),([a-zA-Z0-9:]+),([^,]+)$", "\\2", datalist)
      Strength <- v5 <- gsub("^[0-9]+,[0-9]+,(.*),([a-zA-Z0-9:]+),([^,]+)$", "\\3", datalist)

      Label <- BlueToothFilterRules(Label)
      Encoding(Label) <- 'UTF-8'
      BlueToothTable <- data.frame(i=i, DeviceID = deviceID, Time= Time, Label= Label, Mac = MacAddress, Strength= Strength, stringsAsFactors = FALSE)

      Stats <- data.frame(
        i=i, 
        time=difftime(Sys.time(),Start.Time,units='secs'),
        DataList= datalist.length
      )

      ### Writes to the Database
      source("/Shared_Functions/MYSQL_LOGIN.r" )
      dbSendQuery(con, 'set character set "utf8"')
      invisible(dbWriteTable(con, name="RawData_Events_Bluetooth",value=BlueToothTable, append=TRUE, row.names=FALSE))
      invisible(dbWriteTable(con, name="RawData_Loadloop_Stats_Bluetooth",value=Stats, append=TRUE, row.names=FALSE))
      dbDisconnect(con)
      print(paste(i,"END"));

      return("Finished")
    }
  }

所以当这个并行运行时,就像我说的那样,它在写入时会出现瓶颈,导致超时。

我不知道如何处理user3666197所说的内容,除此之外还有为这些故障做好准备并且在处理它们时设计得很好。

将readin与write分离不是一个现实的选择,因为生成的对象太大而无法很好地处理。

据我所知,并行运行会因为瓶颈而提供有限的改进,但是通过允许其他工作人员在加载所有内容时加载和处理原始数据,它将减少总处理时间。

所以我的原始问题仍然是 - 如何最好地处理mysql写入队列,以便在并行运行时不会产生超时错误?

谢谢

1 个答案:

答案 0 :(得分:0)

在MCVE制定的问题中没有代码,让我们在答案中没有任何代码。

While all the due mathematical formulations are in the tail section of this,人类可读的故事可能是更好地掌握主体TimeOut 问题根本原因的方法:

使用并行语法构造函数?
在许多地方和许多时尚的语法上可行,但......

这里(总是)的意思是,是否它是否有意义。要回答这个问题,必须知道使用它的所有费用的总和

成本是,我们的核心动力是处理加速,我们需要支付的时间开销,然后才能享受使用&#34;加速&#34;结果

让我们举一个例子 - 科德角机场故事:

一个城市的市长决定建造一条新的高速公路,以便让受欢迎的市民乘坐更快到达科德角一角的机场。

这听起来很合乎逻辑。因此,他们开始投资,已经为所有新收购的地块支付了数百名业主(购买物业以提升新路),石矿工挖掘所有需要的岩石,用适当大小的石头砂子水泥沥青进行研磨的铣刀,所有这些都需要高速公路,推土机和#39;运营商将公路岩石基地,混凝土供应商用于及时混合和交付水泥,公路建设正在进行中等等。

经过几个月或几年(取决于当地经济,承包商的表现,城市预算及其与机场的距离......确定),高速公路已经完工,并举行了开幕式。

目前有两件事情确定 - 成本 - 用金钱建造这样的高速公路需要多少钱,加上 - 潜伏期 - 如何很长一段时间,第一辆车可以从城市一直到机场。

最后一件事是 - 净加速达到 - 所以这个新的,100平行的车道宽高速公路终于有多快,如果与旧的和多年的使用相比,可爱的乡村道路

结果?

首先是已知的效果基线:

汽车A,B,C,D,...... X,Y,Z 大约几个月(几年)前都开往机场,开得很舒服大约40英里每小时,所有人都在一个小时内到达机场,一个又一个,以纯[SERIAL] 的方式。没有什么性感,但是坚实,可重复的结果,下次,这些将再次享受几乎相同的结果。

和新的并行车手相比:

汽车 A1,A2,A3,... A100,B101,... B200,... Z2600 都有相同的目标,到达机场尽可能快,但不得不等待几个月(几年)的新高速公路建成(明显的处理设置延迟),接下来需要几分钟才能享受超级在这条新高速公路上快速骑行,德国没有速度限制,所以每小时200英里? 300英里每小时?没问题。

在100平行车道宽新高速公路之前,以<3>分钟超快速驾驶汽车 300英里/小时的超快体验已经到达海岸线,接下来,每辆车都必须排队等候下一艘渡船到达(可容纳约30辆汽车,也可以服务所有传统的本地交通工具)。 / p>

鉴于渡轮线路有一个服务RTT(往返时间 - 装载前30辆车,前往科德角,卸载汽车并装载那些返回,从科德角返回大陆港口)约40分钟,游戏快结束了。

<强>结果:
- 整组 A:Z has made the task in T0 +01:00:00 时间
- &lt; = 30-parallel-riders has made the same in T0 +8760:23:00 的第一个子集 - &lt; = 30-parallel-riders的下一个子集 has made the same in T0 +8760:43:00
- &lt; = 30-parallel-riders的下一个子集 has made the same in T0 +8761:03:00
- &lt; = 30-parallel-riders的下一个子集 has made the same in T0 +8761:23:00
- &lt; = 30-parallel-riders的下一个子集 has made the same in T0 +8761:43:00
- &lt; = 30-parallel-riders的下一个子集 has made the same in T0 +8762:03:00
...
- &lt; = 30-parallel-riders的最后一个子集 has made the same in T0 +8788:43:00

所有这些条件给予
- 大约29小时内,没有本地流量出现了 - 第一艘渡轮准备好开始在他们到达时开始装载第一套约30辆汽车 - 没有渡船服务中断或时间表服务违规行为曾出现

故事的结局:

不,#34;更好&#34;结果在现实世界中是可能的,在真实硬件上的资源受限的并行计算图执行中不可能有更好的结果。

尾声:

在其他真实的 [CONCURRENT] 设置中使用单个&#34;只是&#34; - [PARALLEL] 元素可能会很昂贵 - 幸运的是, ~x.000.000.000 USD ~8760+小时的所有成本神奇地只是&#34; 免费 &#34;,

真正的计算永远不会那么宽容 并且代码将始终支付所有费用,总是(设计方面,代码执行方面),因此应该始终采用适当的工程设计和适当的设计保护不要让任何<< 1加速。