我可以提高MongoDB聚合性能吗?

时间:2014-05-30 12:59:47

标签: mongodb indexing

我正在尝试将当前存在于MS SQL 2005中的解决方案移植到MongoDB - 当前架构是结构化的,但是我们希望添加一个新级别的数据,而不是无模式的更多结构变体所以noSQL似乎还有很长的路要走。

数据的主要用途是分析性的,我们对数据进行了大量聚合。但是我在MongoDB中遇到聚合查询的困难而且我不确定问题出在哪里 - 这可能是我的期望,我对MongDB的知识有限(我只是在学习)或者可能是MongoDB不正确这项工作的工具。

我已阅读有关集合,索引和聚合的MongoDb手册。有一些简单的aggregation examples,作为我学习的一部分,我决定使用这些。

但是,在第一次尝试时(使用第一个示例),我发现性能比我预期的要慢,并且肯定比我用MS SQL实现的要慢。我的猜测是我做错了什么,但我真的不知道什么,我的直觉让我失望了 - 这就是我问这个问题。

测试 我想计算在一个字段上有多少实体匹配简单的'起始'查询。

这与SQL中的基本select count() from where模式匹配,并使用MongoDB站点中的比较示例。

数据

原始数据有21 ^ 6行。在MongoDB中我有一个没有空白的单个集合,所以21 ^ 6个文档大约有17到40个字段(平均28)。

它有单一索引 - 我之所以选择它,因为它是我们分析中的常见字段。我让Mongo给它命名。

{
    "n4" : 1
}

索引的大小约为2Gb,所以 - 如果我理解正确的话 - 应该有足够的空间来存储它。

在MSSQL中,这是一个包含40列的单个表。在MS SQL中,表具有以下索引

USE [v3_newDev]
GO
/****** Object:  Index [n4]    Script Date: 05/30/2014 13:34:19 ******/
CREATE NONCLUSTERED INDEX [n4] ON [dbo].[beta_3_dev_POST_coded] 
(
    [n4] ASC,
    [pn4] ASC,
    [ypCat Code] ASC
)
INCLUDE ( [SIC div],
[SIC 2]) WITH (PAD_INDEX  = OFF,
STATISTICS_NORECOMPUTE  = OFF, 
SORT_IN_TEMPDB = OFF,
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
ONLINE = OFF, ALLOW_ROW_LOCKS  = ON,
ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

稍微复杂一点,但它是为一些查询设计的覆盖索引,最终我想在MongoDB上重现。

机器 双Xeon 5050四核,24Gb内存,慢速磁盘,但很多并且分区很好。在MS-SQL和Mongo中,各个部分都有自己的主轴。我是这个开发环境的唯一用户。

我做了什么

mongoDB中的第一个测试是简单计数/查询的复制。

db.main.find({n4:/^UKN/}).count()

在25.714秒内返回n = 2306913。

使用PerfMon进行检查表明没有发生任何磁盘活动,因此我猜测这一切都发生在内存中,但后来看起来很慢。

所以,我看一下解释只是为了确保......

db.main.find({n4:/^UKN/}).explain()

结果:

{
    "cursor" : "BtreeCursor n4_1",
    "isMultiKey" : false,
    "n" : 2306913,
    "nscannedObjects" : 2306913,
    "nscanned" : 2306914,
    "nscannedObjectsAllPlans" : 2306913,
    "nscannedAllPlans" : 2306914,
    "scanAndOrder" : false,
    "indexOnly" : false,
    "nYields" : 18022,
    "nChunkSkips" : 0,
    "millis" : 22255,
    "indexBounds" : {
        "n4" : [ 
            [ 
                "UKN", 
                "UKO"
            ], 
            [ 
                /^UKN/, 
                /^UKN/
            ]
        ]
    },
    "server" : "rack01:27017",
    "filterSet" : false,
    "stats" : {
        "type" : "FETCH",
        "works" : 2306914,
        "yields" : 18022,
        "unyields" : 18022,
        "invalidates" : 0,
        "advanced" : 2306913,
        "needTime" : 0,
        "needFetch" : 0,
        "isEOF" : 1,
        "alreadyHasObj" : 0,
        "forcedFetches" : 0,
        "matchTested" : 0,
        "children" : [ 
            {
                "type" : "IXSCAN",
                "works" : 2306913,
                "yields" : 18022,
                "unyields" : 18022,
                "invalidates" : 0,
                "advanced" : 2306913,
                "needTime" : 0,
                "needFetch" : 0,
                "isEOF" : 1,
                "keyPattern" : "{ n4: 1.0 }",
                "boundsVerbose" : "field #0['n4']: [\"UKN\", \"UKO\"), [/^UKN/, /^UKN/]",
                "isMultiKey" : 0,
                "yieldMovedCursor" : 0,
                "dupsTested" : 0,
                "dupsDropped" : 0,
                "seenInvalidated" : 0,
                "matchTested" : 0,
                "keysExamined" : 2306914,
                "children" : []
            }
        ]
    }
}

在那里一切似乎都没关系,它正在使用BTreeCursor进行索引扫描。但我正试图让它更快。

根据手册检查我注意到indexOnly(设置为false)在此方案中是不必要的,因此请尝试使用方法

._addSpecial( "$returnKey", true ) 

通过阅读手册和网络上的其他内容,此方法告诉查询计划程序仅使用索引中可用的n4字段

这确实更快......

db.main.find({n4:/^UKN/})._addSpecial( "$returnKey", true ).explain().n

在9.896sec中返回n = 2306913。

一项改进,但仍然比我想要的慢一个数量级,以及我能用MS SQL实现的目标。

我的下一步是使用.count()方法返回_addSpecial()方法,虽然这是徒劳的,因为这会产生所有

的最长时间

在129.575sec中返回n = 2306913。 (虽然在随后的测试中大约是23/25秒。)

如何改善MongoDB的查询时间?我可以通过索引或更好的查询模式做些什么吗?

在MS SQL 2005中,使用以下简单查询

SELECT COUNT(*)as n     FROM v3_newDev..beta_3_dev_POST_coded     在哪里n4喜欢'UKN%'`

查询在<中返回n = 2306913 1秒。

根据我在这里写的内容,我可以用MongoDB做些什么来提高这个基本查询的性能?

0 个答案:

没有答案