问题所在目前有一个系统会将唯一标识符(id
)及其附加数据集从SQL表中读取到无序Map中。这些数据集通常以id
1开始,但数据集的添加和删除只需约10ms。请注意,并非所有数据集都始终加载到RAM中。
当程序启动时,它从数据库中读取SELECT MAX(id)
,并继续将+1添加到计数器变量,它将其用作任何添加的数据集的id
。删除的数据集的id
s不再在任何地方使用。这不可避免地会导致id
序列中出现间隙,并在某一天导致溢出。
我正在寻找一种高性能的方法来填补id
值的最低差距。同时保持与仅部分加载的SQL表和程序内存的一致性。内存中的数据可能在几分钟内或立即不会保存到SQL表中。
我想到的一个解决方案是在运行时对每个创建的数据集进行昂贵的查询,以找到SQL表中的最低间隙,检查这个id
是否作为无序Map中的值存在,然后再次使用计数器变量的值作为备份,以避免无休止地查询空闲的id
。这正好适用于1 id
的数量。然后,它在SQL中仍然是空闲的,但在无序Map中被占用,直到再次节省内存。
我还集思广益,将空闲ID列表查询到一个向量中,并将它们用作新数据集的id
,直到向量为空,然后(或经常)对更多ID进行新的查询。但是我想不出一个查询来查找表中的X数量的间隙,该表可能有也可能没有以1开头的id
列。
我遇到过How do I find a "gap" in running counter with SQL?,但我对最重要的答案有两个问题:显然,它只找到一个缺口,而我需要很多,我不能理解它使用的mo
和mi
。
假设我有一个名为userdata
的表,其中列id
和dataset
都是32位有符号INT。如何在id
列中找到一个间隔数组?例如,当表中的id
s为1,6,7,9时,我希望查询返回2,3,4,5,8。
任何指向可能的解决方案的方法的指针也是值得赞赏的。
2条答案
按热度按时间snvhrwxg1#
如果每10 ms有一个数据库更改,则每秒有100个更改。一个有符号的
int
可以保存大约2,147,483,648个值,或者21,474,846秒,大约是8个月。在此之后,没有可用的新ID是可能的。第一种解决方案是使用
64bit
类型而不是int
。这给了你大约13,600年(对于有符号的64 b),这似乎足够了:)其他解决方案是拥有一个包含所有可能ID的向量。向量存储
bool
(ID已使用/未使用)。通过将向量向上行进到标记为未使用的第一位置来完成请求新ID。这个vector使用了大量的RAM,尽管std::vector有一个专门用于需要较少RAM的bools的版本。
第三种解决方案是处理一个链表(可能是双向链接的),它存储被删除的(读:可重用)ID。
当请求一个新的ID时,列表提供它的头,或者如果列表为空,则提供表的大小。
当数据集被删除时,它的ID会正确地插入列表中,因此列表总是排序的。
当一个ID被重复使用时,它将从列表中删除。
删除表中的最后一条记录也可能删除列表中的最后一个节点,因为它们是无用的(案例ID >表大小)。这就是为什么我建议使用双向链表,以便快速删除最后一个节点。
因此,这个列表在其节点上快速使用“new”和“delete”,并且还频繁地上下运行(用于双向链接)以插入新节点。
这有点慢,但我希望名单不要太大,所需的时间也不是那么糟糕。
还请注意,此列表为您提供了所需的间隙数组。
dtcbnfnu2#
SELECT MAX(id)
--如果多个并发进程正在使用此技术,则此技术将 * 不 * 可靠。让AUTO_INCREMENT
来为您完成这项工作--更快、更高效、* 且 * 安全的并发性。"本我的漏洞",所以呢?
方案A:使用
BIGINT
--它的极限如此之大,即使使用当今最快的机器也需要几个世纪才能达到。计划B:让我们讨论数据流。可能有其他技术来避免间隙或处理它们。例如,下面的代码可以避免batch Normalization 的“burning ids”
计划C:正如你所说,填补空白的成本太高,甚至无法考虑。