<< ..

MongoDB count 数据量不一致问题

发布时间:

20170228 UPDATE

细读官方文档发现如下一段,链接

After an unclean shutdown of a mongod using the Wired Tiger storage engine, count statistics reported by count may be inaccurate.

先说结果: 我们认为mongodb count是不准确的。

在实际生产环境中,针对一个表直接count的结果,和使用aggregate计算得出的结果不一致。但因为聚合是通过扫描+计算得出,我们认为聚合更准确。此外,我们也尝试将mongo表直接映射到hive表上面,通过hive count的值和mongo聚合得出结果一致。

//mongo count
db.collection.count()  // 得出结果 4831488

// 自己改写count成聚合
db.collection.aggregate([
    {"$group": {
        "_id": null,
        "count": {"$sum": 1}
    }}
]) //得出结果 {“_id”: null, "count": 4831764.0}

让mongo count不准确的原因,可能是mongo异常shutdown,最好异常关闭后validate一下,参考链接:

  • https://docs.mongodb.com/manual/reference/command/validate/#dbcmd.validate
  • https://docs.mongodb.com/manual/reference/program/mongod/#cmdoption-syncdelay

20170220 UPDATE

Update: 发现mongoshell中也存在count同范围数据出不同结果的情况,但多次count后会趋向于一个值,这个值跟dump出的条目数吻合。


我们一直使用Robomongo作为mongo客户端工具,用得顺手,写聚合高亮,各种特性加一起基本是绝配。

然额,最近发现这样一件事情,当我试图对一组量级较大历史数据多次count后发现得出不同结果。

// 检索语句
db.getCollection('eventV4').count({
    // 时间范围以`ISODate()`过滤
    "serverTime" : {
        "$gte": ISODate("2017-02-03T16:00:00.000Z"),
        "$lt": ISODate("2017-02-04T16:00:00.000Z"),
    },
    // 筛选了一类型字段
    "platform": {"$ne": "backend"}
})

Robomongo多次检索出的结果居然发现不同:

id result
第1次 17182684
第2次 18143412
第3次 18143412
第4次 17182684

WHAT THE FUCK!!!???这是忽略物理世界客观规律的错误吗?于是我开始尝试mongodump/restore将相同条件的数据从数据源取下来在另一个mongo实例里做统计,最终得出结果:

id result
第1次 17182684
第2次 17182684
第3次 17182684
第4次 17182684

count() is equivalent to the db.collection.find(query).count() construct.

开始思考到底是count()条件导致,还是count()函数本身有问题,于是也尝试了find({}).count(),还是得出相同结果,但是一旦回到数据源去count,便会偶然得出不同结果。开始怀疑是否因为cursor + 数据量太大导致。但是这个时候我无意打开了MongoChef,于是用另一款mongo客户端工具测试了数据源count,发现几次测试结果竟然一致。于是我开始对比mongodump/mongoshell/robomongo/mongochef的结果:

mongodump/restore mongoshell robomongo mongochef
17182684 17182684 17182684 17182684
17182684 17182684 18143412 17182684
17182684 17182684 18143412 17182684
17182684 17182684 17182684 17182684

真相只有一个,robomongo不知道为什么撒了谎。

这让我回想起曾经遇到过这样的情况,在robomongo中两个count结果突然聚到一页上Ref: Double count give double result on second View #1146

还有如果集合太大,Scripts end prematurely and randomly when using loop #1106

反思这个事情,如果日后需要精确的数据量级统计,还是用mongoshell比较好,毕竟robomongo可能会因为软件自身带来一些影响统计结果的问题。