MongoDB - 查询超过1000万条记录的性能

6

首先,我已经阅读了很多与MongoDB查询性能相关的文章,但是我没有找到任何好的解决方案。

在集合内部,文档结构如下:

{
    "_id" : ObjectId("535c4f1984af556ae798d629"),
    "point" : [
        -4.372925494081455,
        41.367710205649544
    ],
    "location" : [
        {
            "x" : -7.87297955453618,
            "y" : 73.3680160842939
        },
        {
            "x" : -5.87287143362673,
            "y" : 73.3674043270052
        }
    ],
    "timestamp" : NumberLong("1781389600000")
}

我的收藏已经有了一个索引:

db.collection.ensureIndex({timestamp:-1})

查询看起来像这样:

db.collection.find({ "timestamp" : { "$gte" : 1380520800000 , "$lte" : 1380546000000}})

尽管如此,响应时间太长,大约需要20-30秒(这取决于指定的查询参数)。
任何帮助都是有用的!
提前致谢。
编辑:我更改了查找参数,用真实数据替换了它们。
上述查询需要46秒,并且这是explain()函数给出的信息:
{
    "cursor" : "BtreeCursor timestamp_1",
    "isMultiKey" : false,
    "n" : 124494,
    "nscannedObjects" : 124494,
    "nscanned" : 124494,
    "nscannedObjectsAllPlans" : 124494,
    "nscannedAllPlans" : 124494,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 45,
    "nChunkSkips" : 0,
    "millis" : 46338,
    "indexBounds" : {
        "timestamp" : [
            [
                1380520800000,
                1380558200000
            ]
        ]
    },
    "server" : "ip-XXXXXXXX:27017"
}

1
如果你的意图是在以后进行地理位置查询,你可能需要考虑不同的文档结构。但除此之外,你的查询看起来更具有理论性而不是真实性(因为时间戳值显然不在你指定的范围内),而理论性问题很少能得到有意义的答案。在这里涉及到了许多变量,涉及到了一个“1000万记录”的查询,如果你不能更加具体,那么很难全面覆盖它们。请尽量呈现一个非常具体的案例。 - Neil Lunn
我同意你的搜索本身已经得到了124K条记录,这并没有太多改进的空间。 - Devesh
1个回答

14

这个解释输出非常理想。您通过索引(nscanned)找到了124,494个文档,它们都是有效的结果,所以它们都被返回(n)。但它仍然不是只使用索引查询,因为边界值不是在特定文档中找到的确切值。

这个查询较慢的原因可能是它返回了大量数据。您找到的所有文档必须从硬盘中读取(当集合是冷的时候),扫描,序列化,通过网络发送到客户端,并由客户端进行反序列化。

您真的需要那么多数据来满足您的用例吗?当答案是“是”时,响应速度真的很重要吗?我不知道您实际想创建什么样的应用程序,但我猜测您的用例之一可能是以下三种:

  1. 您想以某种报表形式显示所有这些数据。这意味着输出将是一个巨大的列表,用户必须滚动查看。在这种情况下,我建议使用分页。只加载适合一个屏幕的数据,并提供“下一页”和“上一页”按钮。MongoDB分页可以使用游标方法.limit(n).skip(n)来实现。
  2. 与上例类似,但它是用户可以下载的某种离线报告,然后使用各种数据挖掘工具进行检查。在这种情况下,初始加载时间将是可接受的,因为用户将花费一些时间处理他们收到的数据。
  3. 您不想向用户显示所有原始数据,而是对其进行处理并以某种聚合方式呈现,如统计图表或图表等。在这种情况下,您可能可以使用聚合框架在数据库中完成所有工作。

@user1503117,你是如何使用分页并加快查询速度的?能否请你解释一下? - Jaffer Wilson
我需要比较来自Mongo和MySQL的数据。两个数据集都有大约500,000行,我正在使用Python进行实际比较。现在Mongo集合中的数据已经增加了很多,即使使用索引按时间戳选择也需要大约10分钟。有什么方法可以减少这个时间吗? - xRahul
@Rahul,你可能需要提出一个新问题,详细描述你想要做什么以及如何做。 - Philipp
尝试使用分片来提高效率,这肯定会改善它。 - Yatender Singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接