Php 从表中选择条件1或反转条件1的有效方法

Php 从表中选择条件1或反转条件1的有效方法,php,mysql,performance,Php,Mysql,Performance,我有一个对称的用户关系表: CREATE TABLE IF NOT EXISTS `friends` ( `id` int(11) NOT NULL AUTO_INCREMENT, `user_a` int(11) NOT NULL DEFAULT '0', `user_b` int(11) NOT NULL DEFAULT '0', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1; 此表包含以下信息: ID

我有一个对称的用户关系表:

CREATE TABLE IF NOT EXISTS `friends` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_a` int(11) NOT NULL DEFAULT '0',
  `user_b` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
此表包含以下信息:

  • ID为1的用户是ID为2的用户的朋友
  • ID为3的用户是ID为1的用户的朋友
结论是:

  • ID为1的用户有2个朋友(ID 3和ID 2)
  • 用户ID可以在两列中的任何一列中(请参见用户ID 1)
如何进行有效查询以检查用户1是否是用户3的朋友

为什么我要问一个有效的方法?嗯,因为我有3种不同的解决方案(可能会有更多),但我正在努力选择其中最有效的。有什么帮助吗

方法1:

SELECT user_b AS user_a
FROM    friends
WHERE   (user_a = :user_a AND user_b = :user_b)
UNION ALL
SELECT  user_a
FROM    friends
WHERE   (user_b = :user_b AND user_a = :user_a)
方法2:

SELECT * FROM friends WHERE (user_a = :user_a AND user_b = :user_b) OR
(user_b = :user_a AND user_a = :user_b)
方法3:

SELECT user_a FROM (
SELECT user_b AS user_a
FROM    friends
WHERE   user_a = :user_a
UNION ALL
SELECT  user_a
FROM    friends
WHERE   user_b = :user_a
) AS newtab WHERE newtab.user_a = :user_b;
PHP检查:

$my_id = 1;
$friend_id = 3;
$stmt = $dbh->prepare("SELECT ..."); // approach 1 or 2 or 3 or ...
$stmt->bindParam(':user_a', $my_id, PDO::PARAM_STR);
$stmt->bindParam(':user_b', $friend_id, PDO::PARAM_STR);
$stmt->execute();

if ($stmt->rowCount() > 0) {
echo "You are friends";}
else { echo "he is not your friend";}
性能方面-哪种方法更好

编辑:

测试

$start_2 = microtime(true);
for ($i = 1; $i <= 100; $i++) {
    $stmt->execute();
}
$end_2 = microtime(true);
$start_2=微时间(真);
对于($i=1;$i execute();
}
$end_2=微时间(真);
结果

$start_2 = microtime(true);
for ($i = 1; $i <= 100; $i++) {
    $stmt->execute();
}
$end_2 = microtime(true);
1:0.14095306396484

2:0.063449859619141

3:0.18946194648743


您必须为usersID创建一个索引,并检查是否确实需要额外的ID

为了简单起见,我会使用选项2,不确定这是否是最有效的方法,您可以测试witch one是否足够简单


我曾经做过类似的事情,其中select查询比插入更常见,并且有很多记录,所以我总是按照特定的顺序插入,在这种情况下可能类似于user_a正如您通过测试方法2已经发现的那样速度会更快

我对此的理解是,在50%的情况下,第一部分足以满足
部分,其中
部分和第二部分根本不会执行

加上@Luis的想法,你总是有用户a 此外,联接和子查询可能需要临时表,有时甚至必须在磁盘上。这非常慢,因此应该避免

要测试查询是否使用临时表,请运行
EXPLAIN
,并在extra部分中查找是否使用临时表


我还将去掉多余的id(无用数据),并将用户a、用户b作为主键。这将为您提供一个快速的索引(只要您知道该用户a<用户b)。

性能问题通常以“对其进行基准测试并亲自查看”结束。由于您的“用户a”/“用户b”列都没有索引,因此无论采用何种解决方案,您最终都会进行完整的表扫描。@MarcB i遵照您的建议,实现了benchark。赢家是方法2;)从朋友那里选择(用户a=:用户a或用户a=:用户b)怎么样(user_b=:user_a或user_b=:user_b)限制1;
刚刚测试过-没有区别;)(与方法2的结果相同)基本上我得到了两个表:第一个表用于成员(id、名称、姓氏),第二个表用于关系(id1、id2)。这样,我可以在两个用户之间建立友谊。有没有更好的办法?您刚才提到的“单边查询”方法很好,但这意味着表中的记录将增加一倍。这并不意味着,这只意味着如果1是3的朋友,它只能在这个中间表中,1个id将始终位于用户_a中,3个id将位于用户_b中,因为1<3哦,对了!我在想一些不同的事情,但现在我明白你的意思了!基本上,我必须比较ID,并根据“X