对超大数据最有效的 MongoDB find() 查询 策略 A策略 B策略 C

我试图在 2D 天文坐标系中实施一个科学研究系统。我有一个过程可以生成大量地理空间数据,我们可以将这些数据组织在两个坐标和一个字符串值的文档中。另一方面,我有一小部分数据,其中只有一个坐标必须至少与生成的两个日期中的一个匹配。

简单来说,我将数据组织成两个集合:

  • collA 平均。大小:~2GB(时间恒定)
  • collB 超过 50GB(持续增加)

地点:

collA 中文档的架构是:

{
    terrainType: 'myType00001',lat: '000000123',lon: '987000000'
},{
    terrainType: 'myType00002',lat: '000000124',{
    terrainType: 'myType00003',lon: '997000000'
}

请注意,首先我们放置索引是为了避免 COLLSCAN。 collA 中有两个索引:__lat_idx(唯一)和 __long_idx(唯一)。我可以保证生成过程不会在批次列中的后期生成重复项(如上所示:lat 和 lon 有九位数字,但这只是为了简单......在实际情况下,这些值非常大)。

collB 中文档的架构是:

{
    latOrLon: '0045600'
},{
    latOrLon: '0045622'
},{
    latOrLon: '1145600'
}

我尝试了一些不同的查询策略。

策略 A

let cursor = collB.find() // Should load entire 2GB into memory?

curosor.forEach(c => {
    collA.find({lat: c.latOrLon})
    collA.find({lon: c.latOrLon})
})

这需要对 collB 中的每个文档进行两次 mongo 调用:非常慢。


策略 B

let cursor = collB.find() // Should load entire 2GB into memory?

curosor.forEach(c => {
    collA.find({$expr: {$or: [{$eq: [lat,c.latOrLon]},{$eq: [lon,c.latOrLon]} })
})

这需要对 collB 中的每个文档进行 mongo 调用,比 A 快但仍然很慢。


策略 C


for chunk in chunks:
    docs = []
    for doc in chunk:
    CHUNK_SIZE = 5000
    batch_cursor = collB.find({},{'_id': 0},batch_size=CHUNK_SIZE)
    chunks = yield_rows(batch_cursor,CHUNK_SIZE) # yield_rows defined below
    res = collA.find({
                    '$or': [
                        {
                            'lon': {
                                '$in': docs
                            }
                        },{
                            'lat': {
                                '$in': docs
                            }
                        }
                    ]
                })

这首先从 collA 获取 5000 个文档,然后将它们放入一个数组中并发送 find() 查询。效率高:collA 中每 5000 个文档调用一次 mongo。

此解决方案非常快,但我注意到随着 collA 大小的增加,速度会变慢,为什么?由于我使用的是索引,因此在计算时间方面搜索索引值应该花费 O(1)...例如,当 collA 的大小约为 25GB 时,执行一次大约需要 30 分钟完整查找()。现在这个集合是 50GB 大小,需要 2 个多小时。

我们计划下个月数据库至少达到 5TB,这将是一个问题。


我向大学要求使用 MongoDB 分片并行化这项工作的可能性,但这不会立即实现。我正在寻找一个临时解决方案,直到我们可以并行化这项工作。

请注意,我们尝试了不止这三种策略,我们混合了 Python3 和 NodeJS。

yield_rows 的定义:

        def yield_rows(batch_cursor,chunk_size):
            """
            Generator to yield chunks from cursor
            :param cursor:
            :param chunk_size:
            :return:
            """
            chunk = []
            for i,row in enumerate(batch_cursor):
                if i % chunk_size == 0 and i > 0:
                    yield chunk
                    del chunk[:]
                chunk.append(row)
            yield chunk
abc123xyzzxm2000 回答:对超大数据最有效的 MongoDB find() 查询 策略 A策略 B策略 C

你可以只索引你查询的字段(它不必是唯一的),这样只会返回匹配的数据,它不会遍历整个集合数据。

本文链接:https://www.f2er.com/9514.html

大家都在问