假设你有一个随机数生成器吐出1到100 000 000之间的数字,你想将它们存储在一个数据库(MySQL)中,并带有它们被生成时的时间戳。如果以前看到的数字出现,则将其丢弃。
实现这一目标的最佳算法是什么? 根据需要选择然后插入?还有比这更有效的吗?
-
你可以去一个
SEQUENCE
:+
- 没有关系被锁定,因此性能最佳;
- 没有比赛条件;
- 便携式。
-
- 有可能在
- 数字序列中获得"间隙"。
-
您可以执行
SELECT ...
然后INSERT ...
:+
- 没有间隙,您还可以对数字进行一些复杂的数学运算。
-
- 有可能在
SELECT
和INSERT
之间的中间获得另一个并行会话,最终得到 2 个相等的数字; - 如果存在
UNIQUE
约束,则 Previos 情况将导致异常; - 为了避免这种情况,您可以使用显式表锁,但这会对性能造成直接影响。
-
您可以选择
INSERT ON DUPLICATE KEY UPDATE
,到目前为止,它似乎是最好的选择(看看"插入忽略"与"插入...关于重复键更新"),至少在我看来,唯一的例外 - 不能移植到其他RDBMS上。
附言本文与MySQL无关,但值得一读,以了解途中可能发生的所有捕获。
如果您不需要每次都插入新的随机值,则可以使用 INSERT IGNORE 或 REPLACE INTO。否则,您应该选择检查,然后选择插入。
这通常可以通过在表中的随机数列上创建唯一索引来解决。 你可以尝试看看b树与哈希是否具有更好的性能。
如果有大量内存,则可以预先填充包含 100,000,000 行的表——所有可能的值。 然后,当您查看是否已创建某些内容时,您只需查看时间戳是否为非 null。 但是,这将需要超过 GB 的 RAM 将表存储在内存中,并且只有在您尝试最大化每秒事务数时才是最佳解决方案。
如果在带有提取数字的列上放置UNIQUE
索引,则任何尝试复制UNIQUE
键INSERT
都将失败。
简单和最便携的版本将是(PHP代码,但你明白了):
function extraction() {
do {
$random = generate_random_number();
$result = @mysql_query("INSERT INTO extractions(number) VALUE ($random)");
} while (!$result);
return $random;
}