本章内容:
- 哈希函数
- 创建哈希索引
- 注意事项
哈希索引使用索引字段值的哈希来维护索引条目。
哈希索引可以用作哈希分片键来对数据进行分片。基于哈希的分片将字段的哈希索引用作分片键,以跨分片群集对数据进行分区。
使用哈希分片键对集合进行分片使数据分布更随机。有关更多详细信息,请参见哈希分片。
一、哈希函数
哈希索引使用哈希函数来计算索引字段值的哈希。 [1]哈希函数折叠嵌入的文档并计算整个值的哈希,但不支持多键(即数组)索引。
提示
使用哈希索引解析查询时,MongoDB自动计算哈希值。应用程序不需要计算哈希。
[1]从版本4.0开始,mongo shell提供了convertShardKeyToHashed()方法。此方法使用与哈希索引相同的哈希函数,可用于查看一个键的哈希值。
二、创建哈希索引
要创建哈希索引,请指定hash作为索引键的值,如以下示例所示:
db.collection.createIndex( { _id: "hashed" } )
三、注意事项
MongoDB支持任何单个字段的哈希索引。哈希函数折叠嵌入的文档并为整个值计算哈希,但不支持多键(即数组)索引。
不能创建具有哈希索引字段的复合索引,也不能在哈希索引上指定唯一约束;但是,可以在同一字段上创建哈希索引和升序/降序(即非哈希)索引:MongoDB将标量索引用于范围查询。
1.上限值2^53
警告
MongoDB哈希索引在哈希之前将浮点数截断为64位整数。例如,哈希索引将为具有2.3、2.2和2.9的值的字段存储相同的值。为防止冲突,请勿对不能准确地转换为64位整数的浮点数使用哈希索引。
MongoDB哈希索引不支持大于2^53的浮点值。
若要查看一个键的哈希值是多少,请参见convertShardKeyToHashed()。
2.PowerPC和2^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 " + idx.ns);
printjson(idx);
};
});
});
});
要检查索引字段是否包含值2^63,请对集合和索引字段运行以下操作:
- 如果索引字段类型是标量而不是文档:
//将<collection>替换为实际的集合名称
//将<indexfield>替换为实际的索引字段名称
db.<collection>.find( { <indexfield>: Math.pow(2,63) } );
- 如果索引字段类型是文档(或标量),则可以运行:
//将<collection>替换为实际的集合名称
//将<indexfield>替换为实际的索引字段名称
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));
}
})