同一桌上的多个LEFT JOINS是否有效?

时间:2016-05-27 02:34:02

标签: mysql sql

我必须处理以下架构(简化):

LinkedList<LinkedList<Object>> superList = new LinkedList<LinkedList<Object>>();

我希望以最有效的方式获得以下数据:

CREATE TABLE user
    (`id` int,
     `name` varchar(255),
     PRIMARY KEY (id));

CREATE TABLE user_extra
    (`user_id` int,
     `user_extra_name` varchar(64),
     `value` varchar(255),
     UNIQUE INDEX user_id_extra_name (user_id, user_extra_name));

INSERT INTO user
    (`id`, `name`)
VALUES
    (1, 'John Doe'),
    (2, 'Don Joe');

INSERT INTO user_extra
  (`user_id`, `user_extra_name`, `value`)
VALUES
    (1, 'phone', '1234444'),
    (1, 'email', 'doe@example.com'),
    (2, 'email', 'joe@example.com'),
    (1, 'nickname', 'johnny'),
    (2, 'nickname', 'donny');

除了电话,电子邮件和昵称外,还会有很多用户和可能更多的额外条目。

我到目前为止所做的是user_extra上的多个左连接:

id  name        phone   email               nickname
1   John Doe    1234444 doe@example.com     johnny
2   Don Joe     (null)  joe@example.com     donny

有没有更好的方法来解决这个问题?这可能会导致性能问题,因为用户数量增长,或者是否会有十几个这样的左连接?

SQLFiddle

2 个答案:

答案 0 :(得分:1)

由于您发布了简化表架构(没有索引),我无法确定您的查询是否存在任何性能问题。可能如果user.id是主键并且user_extra.user_id被编入索引,那么您的查询就相当不错了。

如果您要将user_extra的复杂索引添加到(user_id,user_extra_name),那可能会更好。

但对于小型表而言,只是为了简化阅读此查询,这是另一种方法:

http://sqlfiddle.com/#!9/0ab56b/20

SELECT
  u.id, u.name,
  ue.phone,
  ue.email,
  ue.nickname
FROM
  user u
LEFT JOIN (
  SELECT 
    user_id,
    MAX(IF(user_extra_name = 'phone',`value`,null)) AS phone,
    MAX(IF(user_extra_name = 'email',`value`,null)) AS email,
    MAX(IF(user_extra_name = 'nickname',`value`,null)) AS nickname
  FROM user_extra
  GROUP BY user_id
  ) ue
ON
    ue.user_id = u.id 

但实际上,如果您的桌子上有索引,我相信您的查询很好。

答案 1 :(得分:1)

问题归结为你 - 你是否注意到你的应用程序因为这段SQL而出现瓶颈?

Alex的答案是一个很好的方法,但如果您想使用CASE,那么这样的解决方案可能很适合您!它只需要一个LEFT JOIN

SELECT
  u.id, u.name,
  (CASE WHEN uextra.user_extra_name = 'phone' THEN uextra.value ELSE null END) AS phone, 
  (CASE WHEN uextra.user_extra_name = 'email' THEN uextra.value ELSE null END) AS email, 
  (CASE WHEN uextra.user_extra_name = 'nickname' THEN uextra.value ELSE null END) AS nickname
FROM
  user u
LEFT JOIN
  user_extra AS uextra
ON
  uextra.user_id = u.id
GROUP BY
  u.name
ORDER BY
  u.id
ASC

http://sqlfiddle.com/#!9/0ab56b/28

对索引的了解不多。