查询差异:Grouped JOIN vs inline JOIN

时间:2015-05-24 08:40:11

标签: mysql sql database performance difference

我有两个不同的查询返回相同的数据:

+---------+-------------------------------+----------+
| title   | body                          | username |
+---------+-------------------------------+----------+
| Welcome | You got a cool forum here     | john     |
| Welcome | Great topics.                 | boyd     |
| Welcome | Nice to have you as members   | cris     |
| Looking | I have the time and knowlegde | boyd     |
| Looking | I'm fully qualified for this  | joe      |
+---------+-------------------------------+----------+

查询I:

SELECT posts.title,comments.body,users.username
FROM posts
    LEFT JOIN (
        users INNER JOIN comments ON users.id = comments.user_id
    ) ON posts.id = comments.post_id

查询II:

SELECT posts.title,comments.body,users.username
FROM posts
    LEFT JOIN comments ON posts.id = comments.post_id
    INNER JOIN users  ON users.id = comments.user_id

这些是我的表格:

    USERS
+----+----------+
| id | username |
+----+----------+
|  1 | john     |
|  2 | boyd     |
|  3 | ella     |
|  4 | cris     |
|  5 | joe      |
|  6 | esses    |
| 18 | test2    |
+----+----------+
            POSTS
+----+-----------------------+
| id | title                 |
+----+-----------------------+
|  1 | Welcome               |
|  2 | Looking for moderator |
+----+-----------------------+

                        COMMENTS
+---------+---------+------------------------------------------+
| post_id | user_id | body                                     |
+---------+---------+------------------------------------------+
|       1 |       1 | You got a cool forum here                |
|       1 |       2 | Great topics.                            |
|       1 |       4 | Nice to have you as members              |
|       2 |       2 | I have the time and knowlegde to do this |
|       2 |       5 | I'm fully qualified for this job         |
+---------+---------+------------------------------------------+

我的问题是:这两个查询之间真正的区别是什么?

编辑:这是EXPLAIN EXTENDED结果:

查询I:

- EXPLAIN EXTENDED

+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+-------------+
| id | select_type | table    | type   | possible_keys | key     | key_len | ref                  | rows | filtered | Extra       |
+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+-------------+
|  1 | SIMPLE      | posts    | ALL    | NULL          | NULL    | NULL    | NULL                 |    2 |   100.00 | NULL        |
|  1 | SIMPLE      | comments | ALL    | NULL          | NULL    | NULL    | NULL                 |    5 |   100.00 | Using where |
|  1 | SIMPLE      | users    | eq_ref | PRIMARY       | PRIMARY | 4       | app.comments.user_id |    1 |   100.00 | NULL        |
+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+-------------+

- 显示警告

+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                                  |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `app`.`posts`.`title` AS `title`,`app`.`comments`.`body` AS `body`,`app`.`users`.`username` AS `username` from `app`.`posts` left join (`app`.`users` join `app`.`comments`) on(((`app`.`posts`.`id` = `app`.`comments`.`post_id`) and (`app`.`users`.`id` = `app`.`comments`.`user_id`))) where 1 |
+-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

查询II:

- EXPLAIN EXTENDED

+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+
| id | select_type | table    | type   | possible_keys | key     | key_len | ref                  | rows | filtered | Extra                                              |
+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+
|  1 | SIMPLE      | comments | ALL    | NULL          | NULL    | NULL    | NULL                 |    5 |   100.00 | Using where                                        |
|  1 | SIMPLE      | users    | eq_ref | PRIMARY       | PRIMARY | 4       | app.comments.user_id |    1 |   100.00 | NULL                                               |
|  1 | SIMPLE      | posts    | ALL    | PRIMARY       | NULL    | NULL    | NULL                 |    2 |   100.00 | Using where; Using join buffer (Block Nested Loop) |
+----+-------------+----------+--------+---------------+---------+---------+----------------------+------+----------+----------------------------------------------------+

- 显示警告

+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level | Code | Message                                                                                                                                                                                                                                                                                                     |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Note  | 1003 | /* select#1 */ select `app`.`posts`.`title` AS `title`,`app`.`comments`.`body` AS `body`,`app`.`users`.`username` AS `username` from `app`.`posts` join `app`.`comments` join `app`.`users` where ((`app`.`posts`.`id` = `app`.`comments`.`post_id`) and (`app`.`users`.`id` = `app`.`comments`.`user_id`)) |
+-------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

3 个答案:

答案 0 :(得分:1)

从左到右逻辑处理连接,除非您使用括号覆盖它。

Q1: posts LEFT (users INNER comments)

posts(users INNER comments)的结果保持联接,这导致posts的所有行都为NULL,其中连接条件未评估为TRUE

Q2: posts LEFT comments INNER users 

现在posts首先加入comments,而comments中无法加入的列为NULL。然后使用内部联接将此结果连接到users。但由于comments.user_id中的NULL,因外部连接而添加的行将再次被删除。实际上,这与连接所有三个表的内部相同。

答案 1 :(得分:0)

这两个查询之间没有概念上的区别,但为了提高性能,最好先通过加入更大的表来尽快缩小时态结果表,然后只选择所需的字段而不是全部。

答案 2 :(得分:0)

我认为我正确地说查询2在功能上与此相同:

select p.title
 , c.body
, u.username
 from posts p
 join comments c
 on p.id = c.post_id
 join users u
  on u.id = c.user_id

而查询1与此

相同
select p.title
 , c.body
 , u.username
 from posts p
join comments c
on p.id = c.post_id
 left 
 join users u 
on u.id = c.user_id
where 1