MongoDB索引大小是否取决于字段大小?

时间:2016-09-21 12:55:01

标签: mongodb indexing database-performance

在MongoDb中,有一个32位的int类型(4字节)和一个96位的ObjectId类型(12字节)。我注意到32位int字段上的索引比ObjectId字段上的索引大,而根据这个问题,我期待相反:Are there any tools to estimate index size in MongoDB?

这是否特定于ObjectId,它是如何实现的?

以下是一些显示差异的统计数据,使用MongoDB 3.2.9和mongodb-java-driver 3.2和默认配置(WiredTiger引擎+ snappy压缩级别)

“_ id”as ObjectId:

    > db.objectId.stats()
{
    "ns" : "test1.objectId",
    "count" : 500000,
    "size" : 20500000,
    "avgObjSize" : 41,
    "storageSize" : 6737920,
    [...]
    "nindexes" : 1,
    "totalIndexSize" : 4300800,
    "indexSizes" : {
        "_id_" : 4300800
    }
}

“_ id”为int32(线性插入):

     > db.int32linear.stats()
{
    "ns" : "test1.int32linear",
    "count" : 500000,
    "size" : 16500000,
    "avgObjSize" : 33,
    "storageSize" : 5586944,
    [...]
    "nindexes" : 1,
    "totalIndexSize" : 5255168,
    "indexSizes" : {
        "_id_" : 5255168
    }
}

“_ id”为int32(随机插入):

> db.int32random.stats()
{
    "ns" : "test1.int32random",
    "count" : 500000,
    "size" : 16500000,
    "avgObjSize" : 33,
    "storageSize" : 5595136,
    [...]
    "nindexes" : 1,
    "totalIndexSize" : 5378048,
    "indexSizes" : {
        "_id_" : 5378048
    }
}

以下是重现测试的代码:

import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.bson.Document;

public class Main {

    public static void main(String[] args) {

        List<Document> listDoc = new ArrayList<>(); 

        MongoClient mongoClient = new MongoClient(); 
        MongoDatabase db = mongoClient.getDatabase("test1");

        MongoCollection<Document> objectId = db.getCollection("objectId");
        MongoCollection<Document> int32linear = db.getCollection("int32linear");
        MongoCollection<Document> int32random = db.getCollection("int32random");

        for(int i = 0; i<500000; i++){
            listDoc.add(new Document("field", "content" ));
        }
        objectId.insertMany(listDoc);
        listDoc.clear();

        for (int i = 0; i<500000; i++){
            listDoc.add(new Document("_id", i).append("field", "content"));
        }
        int32linear.insertMany(listDoc);
        // unsort the array
        Collections.shuffle(listDoc); 

        int32random.insertMany(listDoc);

        mongoClient.close();

    }
}

1 个答案:

答案 0 :(得分:2)

我不确定但是:WildTiger正在有效地压缩对象ID键。如果您看一下它们是如何生成的,并且如果所有文档都超级快速地插入(在几秒钟内),则在一台机器上,对象ID将有一个非常长的公共前缀。 WildTiger的密钥前缀压缩将非常有效。

那么为什么这不能用于递增整数呢?因为小端格式。

如果上述假设是正确的,实际上在插入时间间隔较多且存在许多服务器(分片)的实际系统上,ObjectId索引可能会比int索引大一点 - 但仍然非常合理尺寸。如果要检查此项,请尝试关闭索引构建的压缩。

总的来说,我认为这是个好消息,因为问题不是int索引很大,而是ObjectId索引是有效的 - 大约10个字节/条目是合理的(虽然我可以想象做得更好)给出除了每个文档的密钥之外,还有一个记录ID。

https://docs.mongodb.com/manual/reference/method/ObjectId/

P.S。我相信递增的int索引略小于随机索引,因为mmap中的升序密钥有适度的优化。