Php 大表中的SQL随机行(带where子句)

Php 大表中的SQL随机行(带where子句),php,mysql,sql,database,Php,Mysql,Sql,Database,我有一个网站,人们可以在那里对汽车进行投票。向用户展示4辆车,用户可以投票选择他们最喜欢的车 表cars中有重要的列: car_id int(10) (not auto_increment, so has gaps) views int(7) points int(7) car_type int(1) (value = 1, 2 or 3) 目前,我对所有车型使用一个映射表,它有一个没有间隙的PK。我选择映射表的max ID并创建4个随机数(PHP),从映射中选择这些行并获得相应

我有一个网站,人们可以在那里对汽车进行投票。向用户展示4辆车,用户可以投票选择他们最喜欢的车

cars
中有重要的列:

car_id   int(10) (not auto_increment, so has gaps)
views    int(7)
points   int(7)
car_type int(1) (value = 1, 2 or 3)
目前,我对所有车型使用一个映射表,它有一个没有间隙的PK。我选择映射表的max ID并创建4个随机数(PHP),从映射中选择这些行并获得相应的car_ID。我使用这些数字从
cars
表中选择汽车

问题是,后来添加到数据库中的汽车与以前添加的汽车相比,获得相同积分的机会较少

我的问题是如何显示按最少视图数(视图asc)排序的相同点数(随机)的4辆车。还应注意:

  • select应仅查询至少有1个点的车辆
  • 该数据库将包含3000多万辆汽车,与汽车无关,但对于这个问题,我认为更容易:)
  • 当70%的车有1分,20%的车有2分,10%的车有3分时,随机点应选择70%的车有1分,20%的车有2分,10%的车有3分
  • 查询将用于向访问者显示4辆车,我们都知道用户不耐烦,因此查询越快越好:)
  • 我可以(如果需要的话)使用一个映射表,它在PK中没有任何间隙(就像我现在所做的那样)
  • 仅显示特定车型内的车辆。例如,汽车类型2的4个随机数(即家用汽车),因为我不想同时显示跑车和家用汽车
如果您知道解决上述问题的另一种解决方案,我愿意接受各种解决方案(PHP/SQL)

赏金,因为这是一个比一般问题更大的问题(/答案)。奖金将奖励描述解决方案或(首选)解决方案代码的人员。无论如何,这是我感谢帮助我的人的方式,并确保我非常感谢你的帮助

更新:


谢谢你迄今为止的所有答案!你的答案是对的。在过去的几个小时里,我确实想了很多,我开始意识到数据库实际上从来都不是为这样的事情而建立的(显示随机数据),它是为了通过快速访问显示精确和准确的数据而创建的。这就是为什么在3000万行或更多行的PK上选择仍然非常快。这就是为什么我在考虑用PHP做所有随机的事情。因此,我在PHP中生成了40个随机数,并从正确车型的映射表中选择这40行。在中选择
非常快(比如0.0006秒)。在这次选择之后,我得到了40个car_id,我还从cars表中选择了
。我将汽车循环放置在一个数组中,并进行一些自定义排序(基于点和视图)。在此之后,我从40辆车内的所有点中选择一个随机数,并从最接近该数量点且视图最少的阵列中抓取这些车。通过这种方式,PHP可以处理随机性、视图部分和查询,因为您请求精确数据的速度非常快(每个0.0006秒)。

Yo可以编写一个存储过程,执行以下操作:

(不要像大多数伪代码那样认为语法正确)

首先选择点:

SELECT @varpoints = points FROM cars ORDER BY RAND() LIMIT 1
这样我们可以获得点列的随机值

将该值存储在var中,并执行如下操作(伪代码):

现在,仅检索包含所需结果的SQL:

SELECT car_id FROM cars WHERE points = @varpoints ORDER BY views ASC
这应该可以解决问题


这将获取一个随机点值,并使用该值查询汽车。如果它没有得到至少4,它将减去1并重试。如果每个积分点的车数少于4辆,那么进行某种尝试性接球会很好。

因此,看来你的主要问题是速度。在这种情况下,您可以进行一些预处理,比如说,让一个表像队列一样使用,包含4辆车的组,随时可以显示。当然,这将区分最后一刻查看/投票的车辆,但您可以定期刷新此队列


  • 当70%的车有1分,20%的车有2分,10%的车有3分时,随机点应选择70%的车有1分,20%的车有2分,10%的车有3分

如果你真的随机选择它们,那就不需要额外的代码了。

我很想给出一个具体的答案,但我需要帮助来理解你的思维过程

您可以从以下内容开始:

我有一个网站,人们可以在那里投票选出他们最喜欢的汽车

问题是,后来添加到数据库中的汽车与先前添加的汽车相比,获得相同积分的机会较少

然后你继续写:

当70%的车有1分,20%的车有2分,10%的车有3分时,随机点应选择70%的车有1分,20%的车有2分,10%的车有3分

对我来说,根据第一句话,后一个规范没有什么意义

Imho,你真正想要的是让用户在每辆车上都有相同数量的投票机会。或者更准确地说,将每辆车与每辆车进行比较

如果你假设(car)变量是独立的,那么你需要记录一个选择出现的次数,而不是它被投票的次数,并相应地调整你的决策过程。这是一个数学问题,它并没有那么难看,然后它可以被翻译成SQL,不管是好是坏——我敢说它可能会更糟

如果你像我一样假设它们不是独立的,你还需要考虑它们之间的相互关系——并存储它们相互联系的次数。因为,嗯,有一个无限小的机会
SELECT car_id FROM cars WHERE points = @varpoints ORDER BY views ASC
select * from cars where points=?, car_type=? order by views desc, lastViewed limit 4
$condition = "car_type=? AND points > 0";
$q_count = "SELECT count(*) FROM cars WHERE {$condition}";
$r_count = mysql_query($q_count);
$car_count = mysql_result($r_count, 0, 0);
$q_cars = "SELECT car_id FROM cars WHERE {$condition}";
$r_cars = mysql_query($q_cars);
$car_ids = array();
for($i = 0; $i < 4; ++$i)
{
    $random_row = rand(0, $car_count);
    $car_ids[] = mysql_result($r_cars, $random_row, 0);
}
SELECT * FROM cars
WHERE points >= 1
    AND car_type = ROUND((RAND() * 2) + 1)
ORDER BY -LOG(1.0 - RAND()) / 70
LIMIT 4;
Select rownum, c.* from Cars where points > 1
SELECT @rownum:=@rownum+1 rownum, c.* 
  FROM (SELECT @rownum:=0) r, Cars c where points > 1;
select * from 
 (the above select)
where rownum in (Random[0], Random[1], Random[2], Random[3])