MySQL:跨表优化连接

时间:2013-08-09 14:18:22

标签: mysql optimization join query-optimization

该查询很慢(约1.5秒)。它应该只返回一个帖子列表

SELECT SQL_NO_CACHE p.id 
    FROM 1_posts p 
    LEFT JOIN 1_topics t ON (p.cid = t.cid AND p.container = t.id) 
    WHERE t.cid = 1010699;

EXPLAIN给出:

+----+-------------+-------+------+-----------------------+-----------+---------+---------------+------+--------------------------+
| id | select_type | table | type | possible_keys         | key       | key_len | ref           | rows | Extra                    |
+----+-------------+-------+------+-----------------------+-----------+---------+---------------+------+--------------------------+
|  1 | SIMPLE      | t     | ref  | PRIMARY,cid           | cid       | 4       | const         |  216 | Using where; Using index |
|  1 | SIMPLE      | p     | ref  | PRIMARY,cid,container | container | 4       | forumdb.t.id |   49 | Using where              |
+----+-------------+-------+------+-----------------------+-----------+---------+---------------+------+--------------------------+

请注意,SQL_NO_CACHE仅用于测试目的。

表格的部分结构:

1_posts:

mysql> explain 1_posts;
+----------------+----------------------+------+-----+---------+----------------+
| Field          | Type                 | Null | Key | Default | Extra          |
+----------------+----------------------+------+-----+---------+----------------+
| cid            | int(20) unsigned     | NO   | PRI | 0       |                |
| id             | int(20) unsigned     | NO   | PRI | NULL    | auto_increment |
| container      | int(20) unsigned     | NO   | MUL | 0       |                |
mysql> explain 1_topics;
+-----------------+----------------------+------+-----+---------+----------------+
| Field           | Type                 | Null | Key | Default | Extra          |
+-----------------+----------------------+------+-----+---------+----------------+
| cid             | int(10) unsigned     | NO   | PRI | 0       |                |
| id              | int(10) unsigned     | NO   | PRI | NULL    | auto_increment |
| container       | int(20)              | NO   | MUL | 0       |                |

表帖子有数百万条目,主题大约为500k。

两个表上的cid和id都是主要的组合键。 cid表示社区ID。这些表主持许多不同的论坛。

感谢您提供任何帮助,以加快这一点。

2 个答案:

答案 0 :(得分:1)

在多个字段(使用AND)上加入时,有助于在这些字段上创建复合索引。

在您的情况下,您可以将帖子中的cid索引更改为(cid, container),这样mysql就可以直接查找行(您仍可以将其用于仅{{1}的查询条件)。

另外你应该把它变成一个INNER JOIN(正如@AndrewK所说),以提高可读性。

答案 1 :(得分:0)

只需查看您的查询,您就可以简化它。

由于您将设置减少到t.cid = 1010699,因此您声明它不能为空。所以你可以使用内连接。

SELECT SQL_NO_CACHE p.id 
FROM 1_posts p 
JOIN 1_topics t ON p.container = t.id 
WHERE t.cid = 1010699 AND p.cid = t.cid;

编辑:

正如Vatev所指出的,删除p.cid = t.cid确实会改变查询结果。为了便于阅读,我在WHERE子句中添加了它