具有特定索引用法的不正确项目计数

时间:2014-01-13 14:32:48

标签: mongodb indexing document-database

我在Windows Server 2008 R2上使用MongoDB,版本2.4.8,我有奇怪的索引行为,我无法解释。这是我在我的集​​合中的结构示例:

{
    "_id" : NUUID("67070100-4627-4aa5-8ab9-45624e5b82ad"), 
    "PropertyType" : "Cooperative",
    "Address" : {
        "Street" : "aaaaaaaaa",
        "HouseNo" : "165",
        "PostalCode" : 2860,
        "City" : "bbbbb",
        "Floor" : "1",
        "DoorNumber" : ""
    },
    "Sales" : {
        "Price" : 425000,
        "Payout" : 0,
        "AreaPrice" : 9042,
        "GrossPrice" : 2340,
        "NetPrice" : 800,
    },
    "WithdrawnFromSale" : true,
    "UnitData" : {
        "UnitType" : "aaaaa",
        "Area" : 400,
        "LivingArea" : 50,
        "UnitArea" : 50,
        "Rooms" : 2,
        "BuildYear" : 1948,
        "GroundArea" : 203,
        "NoiseLevel" : 5
    }
}

另外,我为该集合创建了索引:

db["UnitModel"].ensureIndex({ "Sales": 1, "PropertyType": 1, "UnitData.Rooms": 1, "UnitData.NoiseLevel": 1 })

该索引存在的问题是,在使用此索引时,我的项目计数错误。

当我发出此请求时:

db.UnitModel.find({Sales: {$ne: null}, WithdrawnFromSale: false}).explain({verbose: true})

我得到以下结果:

{
    "cursor" : "BtreeCursor Sales_1_PropertyType_1_UnitData.Rooms_1_UnitData.NoiseLevel_1 multi",
    "isMultiKey" : false,
    "n" : 19368,
    "nscannedObjects" : 42875,
    "nscanned" : 42876,
    "nscannedObjectsAllPlans" : 43274,
    "nscannedAllPlans" : 43276,
    "scanAndOrder" : false,
    "indexOnly" : false,
    ....
}

在这里我们可以看到已经使用了索引,但返回的项目数是“n”:19368。这是错误的。 应该是具有该标准的集合中的70986 项目。

为什么我确定它应该是更多的记录?嗯,这里是代码:

var totalCount = 0;
db.UnitModel.find({WithdrawnFromSale: false}).forEach(
  function (e) {      
    if(e.hasOwnProperty('Sales') && e.Sales != null)
      totalCount++;
  }
)
totalCount;

totalCount = 70986

为了确保上面的查询不使用任何索引,让我们检查一下:

db.UnitModel.find({WithdrawnFromSale: false}).explain({verbose: true})

结果:

{
    "cursor" : "BasicCursor",
    "isMultiKey" : false,
    "n" : 70986,
    "nscannedObjects" : 3204212,
    "nscanned" : 3204212,
    "nscannedObjectsAllPlans" : 3204212,
    "nscannedAllPlans" : 3204212,
    "scanAndOrder" : false,
    "indexOnly" : false,
    ....
}

因此,对于我正在使用的UnitModel集合,标准:销售:{$ ne:null},WithdrawnFromSale:false 它应该是mongo返回的70986条记录。但是你可以看到我弄错了。

有人可以解释一下为什么吗?可能是什么原因?

顺便说一句。当我删除该索引并使用以下索引时:     db [“UnitModel”]。ensureIndex({“WithdrawnFromSale”:1}) 它按预期工作。但我不需要那个索引,这对我的情况并不乐观。

2 个答案:

答案 0 :(得分:1)

与MongoDB 2.4一样,maximum size of an indexed value为1024字节。对于索引太大而无法索引的当前行为是在服务器端记录警告 - 但这不会引发异常。在这种情况下,当密钥太长时,密钥过长的文档将不包含在索引中,但将包含在其他索引中。这可能导致结果不一致,例如错误的计数和一个索引无法找到的“缺少文档”,但可能在另一个索引中或$natural搜索中可用。

在MongoDB 2.5开发/不稳定分支(最终将在今年晚些时候发布MongoDB 2.6产品版本)中,这种行为发生了变化。与MongoDB 2.5.5一样,如果插入/更新包含密钥太大的索引更新,现在将引发异常。有关详细信息,请参阅MongoDB问题跟踪器中的SERVER-5290

答案 1 :(得分:0)

找出问题的原因。当我查看monogodb的日志文件时,我看到了大量以下消息:

HBReadModel.system.indexes Btree :: insert:key太大而不能索引,跳过HBReadModel.UnitModel。$ Sales_1_WithdrawnFromSale_1_PropertyType_1_UnitData.Rooms_1_UnitData.NoiseLevel_1

我试图在 sales 字段上创建索引,该字段实际上是文档而非字段。为了避免这种情况,我只需重新创建索引并在 Sales 文档中指定字段。日志清除,查询按预期返回记录。