您可以根据权重对数据进行分区,然后随机选择一个分区。
确定要使用的分区:O(n)
SELECT Weight, FLOOR(RAND()*COUNT(*)) as Target
FROM test
GROUP BY Weight
ORDER BY RAND()*(Weight)*count(Weight)/100 DESC
LIMIT 1;
使用之前查询的权重和目标得到结果:O(Log(n))
SELECT test.*
FROM test
WHERE Weight = $Weight
LIMIT $Target, 1
测试一下:
CREATE TABLE `test` (
`Id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`Weight` int(11) NOT NULL,
PRIMARY KEY (`Id`),
KEY `Weight` (`Weight`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
insert into test (Weight) ( select FLOOR(RAND()*1000) );
运行 20 次以创建 100 万个测试行:
insert into test (Weight) select FLOOR(rand()*1000) as Weight from test;
由于 GROUP BY,第一个查询在 O(n) 中运行。如果您维护另一个表来跟踪每个重量的计数,则可以将其降低到 log(n) 运行时间。
在测试表中有 800 万行的我的数据库中,第一个查询在 (6.089 s) 中运行,第二个在 (0.001 s) 中运行