我有一些数据库项目,除了它们的主键外,还需要一个对于项目所属的组唯一的索引。我们将其称为属性nbr
,并将该属性分组在一起并定义唯一的nbr
:s的范围的属性称为group
。 nbr
必须在[1-N]范围内,并且从外部来源导入项目时可以设置 。由于所有项目都必须具有nbr
,因此任务将变成如何跟踪使用哪些值的功能,以便为手动添加的新项目选择免费的nbr
。
我正在使用DynamoDB和Redis。我在nbr
上没有DynamoDB索引。到目前为止,我的想法是使用Redis跟踪用于特定组的数字,以便对于Redis键(例如<MYGROUP>-item-nbrs
),我可以存储所有使用的nbr
:s并实现查找下一个空闲nbr
的逻辑。可接受的nbr
范围内的孔是可接受的,但是在考虑用完的数字之前,应先填充孔。
基本上,我想查找最大大小为N的稀疏数组的未使用索引。
在Redis中存储此信息以快速找到免费的nbr
的良好结构是什么?到目前为止,我的想法包括:
所有用过的nbr的单个逗号分隔字符串(按排序顺序)?为了找到一个免费的nbr,发出GET
命令并解析该字符串,直到找到一个空洞或列表的末尾,然后将选择的数字插入该字符串中,然后替换整个字符串。当N大时,这似乎效率很低。
哈希,其中每个使用的nbr
都存储为自己的字段,并使用例如HSCAN
遍历散列的字段以找到空闲的nbr
。当N很大时,HSCAN必须扫描很多字段。
将我的nbr
:s划分为称为p1-20,p21-40,p41-60等的字段,每个字段都包含一组已使用的nbr
:s仅在该分区内,并且当分区用尽时(不再有空闲的nbr
:s),请将其完全移除以加快进一步的迭代速度。使用HSCAN进行迭代,然后使用HSET启动新分区。
存储所有可用的nbr
而不是所有的空闲nbr
,并使用已排序的集合和ZPOPMIN或常规列表和LPOP,并可能划分为子集。不过,使用所有免费的function getFreeNbr() {
while (true) {
send "WATCH numbers"
nbr = send "BITPOS numbers 0"
if nbr < N
send "MULTI"
send "SETBIT numbers $nbr 1"
if send "EXEC" != NULL
return nbr
end if
else
send "UNWATCH numbers"
return -1
end if
}
}
1-N预先填充Redis似乎很丑。
假设N的大小为65536。
出于性能或其他原因,上述任何解决方案是否更好/更糟?有没有更好/更聪明的方法,也许是利用了我不知道的Redis的一些巧妙方面?
编辑:
凯文的答案导致了以下解决方案(伪代码):
{{1}}
答案 0 :(得分:1)
如何使用Bitmaps记录每个可能的nbr
是否使用该值?
要记录使用的值,请使用SETBIT
:
SETBIT key [nbr] 1
要找到免费的nbr
,请使用BITPOS
:
BITPOS key 0
为避免出现竞争状况,您需要确保获取和设置是原子的。 [OP在follow-up question中解决了这个问题。]
这将需要很少的内存(用于65536个可能值的8K字节)。 BITPOS
是O(n),但这不太可能是一个真正的问题。