MongoDB——哈希索引

655 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

不同于传统的B-Tree索引,哈希索引使用hash函数来创建索引。在索引字段上进行精确匹配,但不支持范围查询,不支持多键哈希。

哈希索引的支持使用哈希分片键来进行过分片。基于哈希分片使用的字段作为分片键对分片集群的数据进行分区。

哈希分片键对集合进行的分片会使数据分布更均匀。

哈希函数

哈希索引使用哈希函数来计算索引字段的哈希值。哈希函数计算的整个哈希值折叠到嵌入文档中,但不支持多键索引。

MongoDB在使用哈希索引查询时会自动计算哈希值,程序时不需要计算哈希的。

创建哈希索引

db.<collection>.createIndex({<field>: "hashed"})

MongoDB 4.0开始,支持创建包含单个哈希字段的复合索引。

db.<collection>.createIndex({<field>: "hashed", <field>: 1})

注意事项

  • 不支持多键(即数组)哈希索引

  • 不支持哈希索引指定唯一约束。可以再多加一个索引,增加唯一约束。

  • 上限值2^63,哈希索引哈希之前会讲浮点数截断为64位整数。例如:2.3,2.2和2.9的值会存储相同的值。为了防止冲突,请勿对不能准确转化为64位整数的浮点数使用哈希索引。

  • PowerPC2^63

    PowerPC(英语:Performance Optimization With Enhanced RISC – Performance Computing,有时简称PPC)是一种精简指令集(RISC)架构的中央处理器(CPU),其基本的设计源自IBM的POWER(Performance Optimized With Enhanced RISC;《IBM Connect电子报》2007年8月号译为“增强RISC性能优化”)架构。POWER是1991年,Apple、IBM、Motorola组成的AIM联盟所发展出的微处理器架构。PowerPC是整个AIM联盟平台的一部分,并且是到目前为止唯一的一部分。但苹果电脑自2005年起,将旗下电脑产品转用Intel CPU。

    对于哈希索引,MongoDB 4.2确保PowerPC上浮点值2^63的哈希值与其他平台一致。

    尽管可能包含大于2^53的浮点值的字段上的哈希索引是不受支持的配置,但是客户端仍可以在索引字段具有值2^63的位置插入文档。

    要列出部署中所有集合的所有哈希索引,可以在mongo shell中使用以下操作:

db.adminCommand("listDatabases").databases.forEach(function(d){
   let mdb = db.getSiblingDB(d.name);
   mdb.getCollectionInfos({ type: "collection" }).forEach(function(c){
      let currentCollection = mdb.getCollection(c.name);
      currentCollection.getIndexes().forEach(function(idx){
        let idxValues = Object.values(Object.assign({}, idx.key));

        if (idxValues.includes("hashed")) {
          print("Hashed index: " + idx.name + " on " + d.name + "." + c.name);
          printjson(idx);
        };
      });
   });
});
要检查索引字段是否包含值`2^63`,请对集合和索引字段运行以下操作:

如果索引字段类型是标量而不是文档:
db.<collection>.find( { <indexfield>: Math.pow(2,63) } );
如果索引字段类型是文档(或标量),则可以运行:
db.<collection>.find({
    $where: function() {
        function findVal(obj, val) {
            if (obj === val)
                return true;
            for (const child in obj) {
                if (findVal(obj[child], val)) {
                    return true;
                }
            }
            return false;
        }
        return findVal(this.<indexfield>, Math.pow(2, 63));
    }
})