从Mysql切换到MongoDB 200百万行

时间:2011-07-26 15:53:15

标签: mysql mongodb bigdata

我们正试图从mysql迁移到mongodb。 mysql结构是 id_src int id_dest int 唯一键:id_src,id_dest

它们在mysql中大约有2亿行

数据示例: {id_src,id_dest} {1,2} {1,3} {1,10} {2,3} {2,10} {4,3}

我们需要检索数据: {id_dest,count} {3,3} {10,2} {2,1}

我开始在mongodb中重新生成mysql的结构。 插入性能非常好(非常好):大约1小时插入2亿行。

但是我需要使用map reduce来获取组。地图缩减大约需要1小时。

所以我尝试创建另一个mongodb结构: {id_dest,{id_src1,id_src2}}

每个文档都有十万个id_src。

这是我的insert.php代码

$res=mysql_unbuffered_query("select * from ids limit 10000100");  
while ($tab=mysql_fetch_array($res)) {  
$collection->update(array('_id'=>(int)$tab['id_dest']),array('$push' => array('src'=>(int)$tab['id_src'])),array("upsert" => true));  
}  

但在这种情况下,性能非常差,每秒只有少量更新。

我做错了吗?

1 个答案:

答案 0 :(得分:6)

首先,Map / Reduce不是为实时分析而设计的。此外,MongoDB目前仅限于M / R的一个核心,这将进一步降低速度。

因此,如果你要使用M / R来获取数据,那么它将不是“实时”的,它将每隔X分钟(或几小时)更新一次。

这里有两种有效的方法:

  1. 增量M / R
  2. 实时计数器
  3. 选项#1:增量M / R

    对于此选项,您可以为所有数据运行一次M / R.然后,继续,您只对修改后的数据运行M / R.如果您现在有200M文档,那么下一步可能有210M文档(这意味着M / R变得更慢)。但是如果你只需要运行新的/更改的文件,那么它应该花费不到1小时。

    查看文档here中的reduce输出选项。

    前提是,您只需M / R相关数据,系统就可以“重新减少”现有数据。通过这种方式,您可以获得“增量”M / R.

    选项#2:实时计数器

    在此方法中,您有两个集合:一个用于数据,另一个用于“摘要”的结果。插入数据时,还会对摘要执行增量。

    假设您有这些数据:

    Main Collection
    {src: 1, dest: 2}
    {src: 1, dest: 3}
    {src: 1, dest: 10}
    {src: 2, dest: 3}
    {src: 2, dest: 10}
    {src: 4, dest: 3}
    
    Summary Collection
    {dest: 3, count: 3}
    {dest: 10, count: 2}
    {dest: 2, count: 1}
    

    您收到一条新数据{src: 5, dest: 2}。你会做两个更新:

    db.main.insert({src: 5, dest: 2});
    db.summary.update({dest: 2}, { $inc : { count: 1 } }, true); // upsert true
    

    这是您的新数据:

    Main Collection
    {src: 1, dest: 2}
    ...
    {src: 4, dest: 3}
    {src: 5, dest: 2}
    
    Summary Collection
    {dest: 3, count: 3}
    {dest: 10, count: 2}
    {dest: 2, count: 2}
    

    您会注意到我们已更新了摘要:{dest: 2, count: 2}

    显然,这里存在权衡取舍。您需要更多更新/插入(2x),但您可以获得实时计数器。现在,MongoDB中没有任何事务,因此您必须决定确保两个更新都发生的策略。有很多方法可以做到这一点,我不能在这里讨论(请参阅一个方法的消息队列)。