Php 从子查询性能中选择

Php 从子查询性能中选择,php,mysql,sql,Php,Mysql,Sql,我正在为我的项目PHP+MySQL寻找更高的性能,有一个看起来太慢的查询从一个表中选择2个随机用户 id | name | total | img ------------------------ -- 1 user1 500 1 2 user2 600 2 3 user3 650 3 __ 有什么改进方法吗?确保为where子句中的所有列创建了索引: CREATE TABLE `users` ( `id` INT UNSIGNE

我正在为我的项目PHP+MySQL寻找更高的性能,有一个看起来太慢的查询从一个表中选择2个随机用户

id  | name |  total | img
------------------------ --
1    user1   500      1
2    user2   600      2
3    user3   650      3
__


有什么改进方法吗?

确保为where子句中的所有列创建了索引:

CREATE TABLE `users` (
`id` INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`name` VARCHAR( 255 ) NOT NULL ,
`total` INT NOT NULL ,
`img` INT NOT NULL ,
INDEX ( `total`)
);
还请注意,以下不带子查询的查询将给出相同的结果

SELECT
  C1.id AS id1, C1.img AS img1, C1.name AS name1,
  C2.id AS id2, C2.img AS img2, C2.name AS name2,
  C1.total AS total1, C2.total AS total2
FROM users C1, users C2
WHERE C1.id <> C2.id 
  AND ABS(C1.total - C2.total) < 200
ORDER BY RAND()
LIMIT 1

您可以检查,在

中,您可能能够优化内部选择,但使用ORDER BY RAND将始终将性能转换为。。。我想不出比SHT更好的词了。基本上,你告诉你的数据库管理系统去调用所有的索引并对整个数据集进行重新排序,一旦数据集变得比“微小”的多,它将是一个非常明显的性能损失

我今天刚刚写了一篇关于这个的文章,只要你不介意每次的结果都不一定是不同的,它就会起作用

编辑 我刚刚注意到您只选择了一行。试试这个:

$rs = $dbh->query(
"SELECT COUNT(*) AS 'count'
 FROM users C1, users C2
 WHERE C1.id <> C2.id
   AND ABS(C1.total - C2.total) < 200");
$target = rand(0,$rs[0]['count']);
$rs = $dbh->query(
  "SELECT 
   C1.id AS id1, C1.img AS img1, C1.name AS name1,
   C2.id AS id2, C2.img AS img2, C2.name AS name2,
   C1.total AS total1, C2.total AS total2
  FROM users C1, users C2
  WHERE C1.id <> C2.id
   AND ABS(C1.total - C2.total) < 200
  LIMIT ?,1",
array($target));
它将利用您的索引,并且不需要对潜在的大型数据集进行重新排序

在主键不等于自身的条件下自联接表也不是一个好主意,实际上是在平方数据集的大小。一个有1000行的表将产生一个有999000行的集合。我认为将“total”条件滚动到显式联接中会减少性能损失,但我不确定

更改:

  FROM users C1, users C2
  WHERE C1.id <> C2.id
   AND ABS(C1.total - C2.total) < 200
致:


如前所述,您可以使用索引对其进行优化。但是,我建议以编程方式执行随机逻辑。虽然对较小的表使用ORDER BY RAND很好,但对较大的表来说效率很低。例如,如果一个表有10000条记录,它将不得不生成10000个随机数,并且可以选择最小的一个

我建议使用两个查询。选择计数,从中生成一个随机数,然后在LIMIT子句中使用该值

例如:

//get the total number of rows
$result= mysql_query(" SELECT  COUNT(*) AS total FROM `table` ");
$row = mysql_fetch_array($result);
$total=$row['total'];

//create random value from 1 to the total of rows 
$randomvalue =rand(1,$total);

//get the random row
$result= mysql_query(" SELECT  * FROM `table` limit $randomvalue,1");
在您的特定情况下,您可以生成两个随机数并选择两个用户,只要确保随机数不相等即可


编辑:找到了类似的例子。

只是一个问题:为什么需要外部查询?我想这是因为C1.total-C2.total,我不明白为什么要这样做。添加索引,删除外部查询,因为其无用且仅供参考,rand的顺序也会减慢查询速度。我需要获得2个随机用户img,条件是总计之间的差异小于200。最佳解决方案如果已经创建了表,但缺少索引,请使用alter table users添加索引idx_totaltotalforeach$rs作为$row{print$row['name1'];}我得到的结果是空的,我错过的连接还可以:$dbh=new-PDO-mysql:host=$hostname;dbname=$dbname,$username,$pw--
  FROM users C1, users C2
  WHERE C1.id <> C2.id
   AND ABS(C1.total - C2.total) < 200
  FROM users C1 INNER JOIN users C2
   ON C1.id <> C2.id
     AND ABS(C1.total - C2.total) < 200
//get the total number of rows
$result= mysql_query(" SELECT  COUNT(*) AS total FROM `table` ");
$row = mysql_fetch_array($result);
$total=$row['total'];

//create random value from 1 to the total of rows 
$randomvalue =rand(1,$total);

//get the random row
$result= mysql_query(" SELECT  * FROM `table` limit $randomvalue,1");