2014-02-09 188 views
5

我建立一个网站,我需要从数据库中选择随机加权记录 。大数据库快速mysql随机加权选择

还有就是代码SQL : select one row randomly, but taking into account a weight

SELECT t.*, RAND() * t.weight AS w 
FROM table t 
ORDER BY w DESC 
LIMIT 1 

它适用于记录小样本罚款文档片断。

尝试接近100万条记录时,它在本地机器上变慢(1.3 - 1.8秒) ,我想我会在更大的机器上花费更长的时间。

它如何优化? 有没有更好的方法随机选择加权记录?

我的尝试是定期计算权重,将它们存储在单独的表中,选择随机数programmaticaly并搜索最接近该记录的记录。

回答

1

您可以根据权重对数据进行分区,然后随机选择一个分区。

确定要使用的分区: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(日志(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)运行时间。

我与第一个查询中(6.089 s)运行测试表800万行和(0.001 s)

0

第一第二数据库中获取所有的权重的总和,这样就可以计算出每一行的概率选择上苍蝇。

SELECT SUM(weight) FROM t; 

我假设款额是通过名为mysql的变量访问@TOTAL_WEIGHT

SELECT t.* 
FROM t 
WHERE RAND() <= (weight/@TOTAL_WEIGHT) 
ORDER BY RAND() 
LIMIT 1; 

有一个机会,这个经历整个表,仍然没有找到一个匹配,在哪种情况下你可能只是运行另一个查询来获得一个随机行。