1

我正在尝试生成 16 000 000 个唯一的随机数(10 位:范围 1 000 000 000 - 9 999 999 999)并将它们插入到一个空表中(或者如果不为空,则填写此表)。

桌子:

CREATE TABLE `codes` (
`code_id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`code` bigint(20) UNSIGNED NOT NULL,
`is_used` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`code_id`),
UNIQUE KEY `code` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

...和功能:

DELIMITER $$

CREATE DEFINER=`root`@`localhost` FUNCTION `codes`(`minRange` BIGINT UNSIGNED, `maxRange` BIGINT UNSIGNED, `_amount` BIGINT UNSIGNED) RETURNS tinyint(1)
MODIFIES SQL DATA
BEGIN
DECLARE pick BIGINT;


while (SELECT count(*) FROM codes) < _amount do
begin
SET pick = minRange + FLOOR(RAND() * (maxRange - minRange + 1));
INSERT IGNORE INTO codes (code) VALUES (pick);

end;
end while;

RETURN 1;
END$$

DELIMITER ;

-- call: SELECT codes(1000000000,9999999999,16000000);

该功能非常慢:生成 20k 行需要 2.5 分钟,所以 16M - 大约 33 小时......有没有办法优化它?

4

4 回答 4

2

你要的是一个矛盾的说法。如果这 16M 个数字是唯一的,那么它们就不是随机的。想一想:一个真正的 10 位随机数有 1/9E9 的概率是任何给定的数字。然而,您的第 16M 号数字有 0 概率是 15,999,999 个数字之一,有 1/983,000,001 概率是其余数字之一。你应该总是期待重复。1B 中的 16M 大约有 1%。

所以我的建议是生成(16M +一点)随机数,做一个唯一的排序;截断到 16M 然后随机排序。我的问答:

php -r 'for( $i=0;$i<16500000;$i++) echo mt_rand(100000000, 999999999),"\n";'\
  | sort -u | head -16000000 | sort -R > /tmp/loadfile.lst

在我 4 岁的笔记本电脑上花了 7 多分钟。在现代四核桌面上它会快很多。我使用 PHP-CLI 是因为我的笔记本电脑上有它,而且 mt_rand 例程是一个很好的例程。您可以将其作为 3 liner-C prog 或任何可用的语言来执行。正如 Zercms 所说,只要在加载之前禁用索引并在之后重新启用,加载就会很快。您也只需要加载列code

享受。

于 2012-06-13T18:01:43.233 回答
1

您正在SELECT count(*)每个插入的随机数运行一个。一个简单的优化是尝试在不检查的情况下填充 16000000 个随机数,然后查看实际插入了多少个,从头开始重复要添加的剩余数字的数量。

于 2012-06-13T11:49:14.343 回答
1

我能想到的最快方法是生成具有唯一编号的纯文本文件并使用LOAD DATA INFILE

您还需要ALTER TABLE在开始加载数据之前禁用密钥,然后再启用

于 2012-06-13T11:45:43.757 回答
0

如果您安装了 PHP,也许您应该尝试不通过 MySQL 而是通过 PHP 来生成您的号码。PHPmt_rand()确实会生成更好的随机值,您可以将值填充到数组中,并通过in_array().

此外,由于每次都必须更新表索引,因此您的 MySQL 速度变慢了很多,如果您需要在 MySQL 中执行此操作,也许您应该在生成数字时禁用它。

于 2012-06-13T11:48:26.050 回答