我有一个对称用户关系表:
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;
此表包含以下信息:
总结说:
如何进行有效查询以检查用户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);
结果:
1:0.14095306396484
2:0.063449859619141
3:0.18946194648743
答案 0 :(得分:1)
您必须为usersID创建索引,并检查您是否确实需要额外的ID。
我会使用选项2来简化,不确定它是否是最有效的方法,你可以测试一个更快的简单。
我必须做一些类似于此的事情,其中select选择查询比插入更常见,并且有很多记录,所以我所做的总是按特定顺序插入,在这种情况下可能是类似的user_a&lt; user_b,因此您只能检查查询中的一侧。
答案 1 :(得分:1)
正如您已经通过测试发现的那样,方法2会更快。
我对此的理解是,在50%的情况下,第一部分足以满足WHERE
部分,第二部分将不会被执行。
从@Luis添加想法,你总是拥有user_a&lt; user_b那些50%将升至100%。
此外,连接和子查询可能需要临时表,有时甚至必须在磁盘上。这真的很慢,所以应该避免。
测试查询是否使用临时表运行EXPLAIN
并在额外部分中使用临时查找。
我还会删除那个额外的id(无用的数据)并将user_a,user_b作为主键。那会给你一个快速的索引(只要你知道user_a&lt; user_b)。