如何更好地编写这个Mysql Join查询

时间:2010-08-20 09:56:00

标签: php mysql join

我有下一张桌子

Users {id, name}
Messages {id, user_id, cache_user_name}

出于性能原因,我只想在 cache_user_name NULL 时才进行加入。

例如:

SELECT Messages.*, Users.name FROM Messages INNER JOIN Users ON (Messages.user_id = Users.id) 
// ON (ISNULL(Messages.cache_user_name) AND ...

最好的方法是做2个查询? 1表示没有缓存(加入)的行,另一行表示没有缓存的行?

[编辑]

我需要的结果是:

用户

ID: 1, NAME: Wiliam

消息

ID: 1, USER_ID: 1, CACHE_USER_NAME: Wiliam
ID: 2, USER_ID: 1, CACHE_USER_NAME: null

结果

ID: 1,  USER_ID: 1,  CACHE_USER_NAME: Wiliam,  USERS.NAME: null   // No join, faster
ID: 2,  USER_ID: 1,  CACHE_USER_NAME: null,    USERS.NAME: Wiliam // Join

3 个答案:

答案 0 :(得分:1)

您可以添加WHERE ... IS NULL子句。

优化器将(尝试)使用效果最佳的计划。

SELECT   Messages.*
         , Users.name 
FROM     Messages 
         INNER JOIN Users ON (Messages.user_id = User.id)
WHERE    Users.cache_user_name IS NULL

修改

根据以下数据,您期望输出什么?

DECLARE @Users TABLE (ID INTEGER, Name VARCHAR(32))
DECLARE @Messages TABLE (ID INTEGER, User_ID INTEGER, Cache_User_Name VARCHAR(32))

INSERT INTO @Users VALUES (1, 'Wiliam')
INSERT INTO @Users VALUES (2, 'Lieven')
INSERT INTO @Users VALUES (3, 'Alexander')

INSERT INTO @Messages VALUES (1, 1, NULL)
INSERT INTO @Messages VALUES (2, 1, 'Cached Wiliam')
INSERT INTO @Messages VALUES (3, 2, NULL)
INSERT INTO @Messages VALUES (4, 3, 'Cached Alexander')

SELECT  *
FROM    @Users u
        INNER JOIN @Messages m ON m.User_ID = u.ID
WHERE   m.Cache_User_name IS NULL        

答案 1 :(得分:0)

SELECT m.Id, m.user_id, CACHE_USER_NAME user_name
FROM messages m
WHERE CACHE_USER_NAME IS NOT NULL
UNION ALL
SELECT m.Id, m.user_id, u.user_name user_name
FROM (Select * from messages Where cache_user_name IS NULL) m
JOIN users ON (u.user_id = m.user_id)

无论如何,最好的方法是在创建消息期间在表消息中存储cache_user_name。那么你将需要加入。

答案 2 :(得分:0)

我认为那些在以前的答案中加入了一个Not Null where子句应该可以正常工作,但也许我们没有关注你的效率问题。只要users.id和messages.user_id被索引并且类型相同,除非您拥有庞大的用户数据库和大量消息,否则该连接不应该很慢。如果是的话,扔掉更多的硬件;可能你正在运行大量的流量并且可以负担得起。 :)

或者,您可以像这样处理它:对名称不为null的Messages执行查询,运行结果,查找每条消息的名称(并将它们放入数组中),然后查询用户表仅仅是那些名字。然后,当您遍历消息结果时,您可以从保存的阵列中显示正确的名称。你会有两个问题,但它们会很快。

$users = $messages = $users_ids = array ();

$r = mysql_query('select * from Messages where cache_user_name is not null');
while ( $rs = mysql_fetch_array($r, MYSQL_ASSOC) )
{
    $user_ids[]    = $rs['user_id'];
    $messages[] = $rs;
}

$user_ids = implode ( ',', $user_ids );
$u = mysql_query("select * from Users where id in ($users)");

while ( $rs = mysql_fetch_array($r, MYSQL_ASSOC) )
{
    $users[$rs['id']] = $rs['name'];
}


foreach ( $messages as $message )
{
    echo "message {$message['id']} authored by " . $users[$message['user_id']] . "<br />\n";
}