SQL:随机选择一行,但考虑到权重

前端之家收集整理的这篇文章主要介绍了SQL:随机选择一行,但考虑到权重前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用 MySQL.
我有一张看起来像这样的表:
  1. id: primary key
  2. content: varchar
  3. weight: int

我想要做的是从该表中随机选择一行,但考虑到重量.例如,如果我有3行:

  1. id,content,weight
  2. 1,"some content",60
  3. 2,"other content",40
  4. 3,"something",100

第一行有30%被选中的机会,第二行被选中的几率为20%,第三行被选中的几率为50%.

有没有办法做到这一点 ?如果我必须执行2或3个查询,这不是问题.

解决方法

我已经尝试过van的解决方案,虽然它有效,但它并不快.

我的解决方

解决这个问题的方法是为权重维护一个单独的链接表.基本表结构与此类似:

  1. CREATE TABLE `table1` (
  2. `id` int(11) UNSIGNED AUTO_INCREMENT PRIMARY KEY,`name` varchar(100),`weight` tinyint(4) NOT NULL DEFAULT '1',);
  3.  
  4. CREATE TABLE `table1_weight` (
  5. `id` bigint(20) UNSIGNED AUTO_INCREMENT PRIMARY KEY,`table1_id` int(11) NOT NULL
  6. );

如果我在table1中有一个权重为3的记录,那么我在table1_weight中创建3条记录,通过table1_id字段链接到table1.无论表1中的权重值是多少,这就是我在table1_weight中创建的链接记录数.

测试

在table1中有976条记录的数据集中,总权重为2031,因此table1_weight中有2031条记录,我运行了以下两个sql

1)van的解决方案版本

  1. SELECT t.*
  2. FROM table1 t
  3. INNER JOIN
  4. ( SELECT t.id,SUM(tt.weight) AS cum_weight
  5. FROM table1 t
  6. INNER JOIN table1 tt ON tt.id <= t.id
  7. GROUP BY t.id) tc ON tc.id = t.id,( SELECT SUM(weight) AS total_weight
  8. FROM table1) tt,( SELECT RAND() AS rnd) r
  9. WHERE r.rnd * tt.total_weight <= tc.cum_weight
  10. ORDER BY t.id ASC
  11. LIMIT 1

2)加入辅助表进行加权

  1. SELECT t.*
  2. FROM table1 t
  3. INNER JOIN table1_weight w
  4. ON w.table1_id = t.id
  5. ORDER BY RAND()
  6. LIMIT 1

sql 1持续0​​.4秒.

sql 2需要0.01到0.02秒.

结论

如果选择随机加权记录的速度不是问题,则van建议的单表sql很好,并且没有维护单独表的开销.

如果,在我的情况下,短的选择时间是关键,那么我会建议两个表方法.

附:这是我的第一个StackOverflow帖子,它花了我很多年,所以希望有人会觉得它很有帮助!

猜你在找的MsSQL相关文章