删除 mongodb collection 中的 _id
Getting rid of _id in mongodb collection
我知道无法删除 mongodb collection 中的 _id
字段。但是,我的 collections 的大小很大,_id
字段上的索引阻止我在 RAM 中加载其他索引。我的机器有 125GB 内存,我的 collection 统计数据如下:
db.call_records.stats()
{
"ns" : "stc_cdrs.call_records",
"count" : 1825338618,
"size" : 438081268320,
"avgObjSize" : 240,
"storageSize" : 468641284752,
"numExtents" : 239,
"nindexes" : 3,
"lastExtentSize" : 2146426864,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 1,
"totalIndexSize" : 165290709024,
"indexSizes" : {
"_id_" : 73450862016,
"caller_id_1" : 45919923504,
"receiver_id_1" : 45919923504
},
"ok" : 1
}
当我执行如下查询时:
db.call_records.find({ "$or" : [ { "caller_id": 125091840205 }, { "receiver_id" : 125091840205 } ] }).explain()
{
"clauses" : [
{
"cursor" : "BtreeCursor caller_id_1",
"isMultiKey" : false,
"n" : 401,
"nscannedObjects" : 401,
"nscanned" : 401,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"caller_id" : [
[
125091840205,
125091840205
]
]
}
},
{
"cursor" : "BtreeCursor receiver_id_1",
"isMultiKey" : false,
"n" : 383,
"nscannedObjects" : 383,
"nscanned" : 383,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"receiver_id" : [
[
125091840205,
125091840205
]
]
平均需要 15 秒以上才能 return 结果。 caller_id
和 receiver_id
的索引应该在 90GB 左右,这没问题。但是,_id
上的 73GB 索引使此查询非常慢。
您正确地告知您不能从文档中删除 _id
字段。您也无法从此字段中删除索引,因此这是您必须忍受的事情。
出于某种原因,您一开始就假设 _id
索引会使您的查询变慢,这是完全没有道理的,而且很可能是错误的。该索引未被使用,只是保持原样。
在你的情况下我会尝试做的几件事:
您的 collection 中有 4000 亿个文档,您是否认为现在是开始分片数据库的合适时机?在我看来你应该。
使用 explain with your query 实际找出是什么减慢了速度。
查看您的查询,我也会尝试执行以下操作:
更改您的文档
{
... something else ...
receiver_id: 234,
caller_id: 342
}
到
{
... something else ...
participants: [342, 234]
}
如果您的参与者按此顺序 [caller_id, receiver_id]
,那么您只能在此字段上放置一个索引。我知道它不会使您的索引变小,但我希望因为您不会使用 $or
子句,所以您会更快地获得结果。 P.S.如果你会这样做,请不要在生产中这样做,测试它是否会给你带来显着的改进,然后再改变产品。
这里有很多潜在的问题。
首先是您的索引不包含 returned 的所有数据。这意味着 Mongo 从索引中获取 _id,然后使用 _id 检索和 return 相关文档。因此,即使可以删除 _id 索引也无济于事。
其次,查询包含一个 OR。这会强制 Mongo 加载两个索引,以便它可以读取它们,然后检索有问题的文档。
要提高性能,我认为您只有几个选择:
- 将附加元素添加到索引并将数据 returned 限制为索引中可用的数据(这会在解释结果中更改 indexOnly = true)
- 按 Skooppa.com 所述探索分片。
- 重新查询 and/or 文档以消除 OR 条件。
我知道无法删除 mongodb collection 中的 _id
字段。但是,我的 collections 的大小很大,_id
字段上的索引阻止我在 RAM 中加载其他索引。我的机器有 125GB 内存,我的 collection 统计数据如下:
db.call_records.stats()
{
"ns" : "stc_cdrs.call_records",
"count" : 1825338618,
"size" : 438081268320,
"avgObjSize" : 240,
"storageSize" : 468641284752,
"numExtents" : 239,
"nindexes" : 3,
"lastExtentSize" : 2146426864,
"paddingFactor" : 1,
"systemFlags" : 0,
"userFlags" : 1,
"totalIndexSize" : 165290709024,
"indexSizes" : {
"_id_" : 73450862016,
"caller_id_1" : 45919923504,
"receiver_id_1" : 45919923504
},
"ok" : 1
}
当我执行如下查询时:
db.call_records.find({ "$or" : [ { "caller_id": 125091840205 }, { "receiver_id" : 125091840205 } ] }).explain()
{
"clauses" : [
{
"cursor" : "BtreeCursor caller_id_1",
"isMultiKey" : false,
"n" : 401,
"nscannedObjects" : 401,
"nscanned" : 401,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"caller_id" : [
[
125091840205,
125091840205
]
]
}
},
{
"cursor" : "BtreeCursor receiver_id_1",
"isMultiKey" : false,
"n" : 383,
"nscannedObjects" : 383,
"nscanned" : 383,
"scanAndOrder" : false,
"indexOnly" : false,
"nChunkSkips" : 0,
"indexBounds" : {
"receiver_id" : [
[
125091840205,
125091840205
]
]
平均需要 15 秒以上才能 return 结果。 caller_id
和 receiver_id
的索引应该在 90GB 左右,这没问题。但是,_id
上的 73GB 索引使此查询非常慢。
您正确地告知您不能从文档中删除 _id
字段。您也无法从此字段中删除索引,因此这是您必须忍受的事情。
出于某种原因,您一开始就假设 _id
索引会使您的查询变慢,这是完全没有道理的,而且很可能是错误的。该索引未被使用,只是保持原样。
在你的情况下我会尝试做的几件事:
您的 collection 中有 4000 亿个文档,您是否认为现在是开始分片数据库的合适时机?在我看来你应该。
使用 explain with your query 实际找出是什么减慢了速度。
查看您的查询,我也会尝试执行以下操作: 更改您的文档
{
... something else ...
receiver_id: 234,
caller_id: 342
}
到
{
... something else ...
participants: [342, 234]
}
如果您的参与者按此顺序 [caller_id, receiver_id]
,那么您只能在此字段上放置一个索引。我知道它不会使您的索引变小,但我希望因为您不会使用 $or
子句,所以您会更快地获得结果。 P.S.如果你会这样做,请不要在生产中这样做,测试它是否会给你带来显着的改进,然后再改变产品。
这里有很多潜在的问题。
首先是您的索引不包含 returned 的所有数据。这意味着 Mongo 从索引中获取 _id,然后使用 _id 检索和 return 相关文档。因此,即使可以删除 _id 索引也无济于事。
其次,查询包含一个 OR。这会强制 Mongo 加载两个索引,以便它可以读取它们,然后检索有问题的文档。
要提高性能,我认为您只有几个选择:
- 将附加元素添加到索引并将数据 returned 限制为索引中可用的数据(这会在解释结果中更改 indexOnly = true)
- 按 Skooppa.com 所述探索分片。
- 重新查询 and/or 文档以消除 OR 条件。