我通过hashed_id对mongoDB集群进行了分片。我检查了索引大小,有一个_id_hashed索引占用了很多空间:
"indexSizes" : { "_id_" : 14060169088, "_id_hashed" : 9549780576 },
mongoDB手册说,如果你对一个集合进行分片,就会在分片的键上创建一个索引。我想这就是_id_hashed索引存在的原因。
我的问题是:如果我只通过_id字段查询文档,那么_id_hashed索引是什么?我可以删除它吗?因为它占用了太多的空间。
ps:mongoDB在查询时似乎使用了_id索引,而不是_id_hashed索引。查询的执行计划:
"clusteredType" : "ParallelSort", "shards" : { "rs1/192.168.62.168:27017,192.168.62.181:27017" : [ { "cursor" : "BtreeCursor _id_", "isMultiKey" : false, "n" : 0, "nscannedObjects" : 0, "nscanned" : 1, "nscannedObjectsAllPlans" : 0, "nscannedAllPlans" : 1, "scanAndOrder" : false, "indexOnly" : false, "nYields" : 0, "nChunkSkips" : 0, "millis" : 0, "indexBounds" : { "start" : { "_id" : "spiderman_task_captainStatus_30491467_2387600" }, "end" : { "_id" : "spiderman_task_captainStatus_30491467_2387600" } }, "server" : "localhost:27017" } ] }, "cursor" : "BtreeCursor _id_", "n" : 0, "nChunkSkips" : 0, "nYields" : 0, "nscanned" : 1, "nscannedAllPlans" : 1, "nscannedObjects" : 0, "nscannedObjectsAllPlans" : 0, "millisShardTotal" : 0, "millisShardAvg" : 0, "numQueries" : 1, "numShards" : 1, "indexBounds" : { "start" : { "_id" : "spiderman_task_captainStatus_30491467_2387600" }, "end" : { "_id" : "spiderman_task_captainStatus_30491467_2387600" } }, "millis" : 574
MongoDB使用基于范围的分片方法。如果您选择使用基于哈希的分片,您必须在分片键上有一个哈希索引,并且不能删除它,因为它将用于确定用于任何后续查询的分片(请注意,一旦哈希索引被允许是唯一的SERVER-8031,就有一个开放的票证允许您删除_id索引)。
至于为什么查询似乎使用_id索引而不是_id_hashed索引,我运行了一些测试,我认为优化器选择_id索引是因为它是唯一的,可以产生更高效的计划。如果对另一个已有唯一索引的键进行分片,则可以看到类似的行为。
如果您对hashed_id进行了分片,那么这就是创建的索引类型。
当您执行sh.shardCollection( 'db.collection', { _id:"hashed" } )
时,您告诉它您想使用_id的哈希作为分片键,需要_id
上的哈希索引。
所以,不,你不能放弃它。
文档详细介绍了哈希索引是什么,这让我很困惑,你是如何阅读文档但不知道哈希索引的用途的。
索引主要是为了阻止碎片键中的热点,这些热点可能在读/写时分布不均匀。
所以想象一下_id
字段,它是一个不断增加的范围,所有新的_id
都将在之后,这意味着你总是在集群的末尾写作,创建一个热点。
至于读取,通常只读取最新的文档,这意味着_id
密钥的上限是唯一一个用于在集群的上限范围内同时进行读取和写入的热点,而集群的其余部分则处于空闲状态。
哈希索引采用这个坏的shard键并对其进行哈希处理,这意味着它永远不会增加,而是会创建一组均匀分布的数据用于读写,希望能将整个数据集用于操作。
我强烈建议您不要删除它。
哈希索引是由分片集合请求的,更确切地说,哈希索引是分片均衡器请求的,以便直接根据哈希值查找文档,正常的查询操作不需要索引为hasded索引,即使在共享集合上也是如此。