我们正在尝试从 mysql 迁移到 mongodb。 mysql结构是 id_src 整数 id_dest 整数 唯一键: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的结构。 插入性能非常好(非常好):插入 2 亿行大约需要 1 小时。
但我需要使用 map reduce 来获取分组依据。 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));
}
但在那种情况下性能很差,每秒只有很少的更新。
我做错了什么吗?
最佳答案
首先,Map/Reduce 不是为实时分析而设计的。此外,MongoDB 目前仅限于一个内核用于 M/R,这会进一步降低速度。
因此,如果您要使用 M/R 获取数据,它将不是“实时”的,它将每 X 分钟(或小时)更新一次。
这里有两种有效的方法:
- 增量 M/R
- 实时计数器
选项 #1:增量 M/R
对于此选项,您对所有数据运行一次 M/R。然后,继续前进,您只对修改后的数据运行 M/R。如果您现在有 200M 文档,接下来可能会有 210M 文档(这意味着 M/R 变得更慢)。但是,如果您只需要运行新的/更改的文档,那么它应该花费不到 1 小时。
查看文档中的 reduce
输出选项 here .
同样,前提是您只对相关数据进行 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 中没有事务,因此您必须决定一种策略来确保这两个更新都发生。有很多方法可以做到这一点,我不能在这里详细介绍(一种方法参见消息队列)。
关于mysql - 从 Mysql 切换到 MongoDB 2 亿行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6832893/