MySQL + Drupal:在INNER JOIN中忽略索引

时间:2009-05-18 20:14:46

标签: mysql indexing inner-join ignore

我们的环境: 的Drupal + MySQL的

检查查询日志表明源自Drupal核心的node_load函数的以下查询占用了相当多的时间。

在node_load查询上的EXPLAIN显示在USER表上没有使用索引。

mysql> explain SELECT n.nid, n.vid, n.type, n.status, n.created, n.changed, 
    n.comment, n.promote, n.sticky, r.timestamp AS revision_timestamp, r.title, 
    r.body, r.teaser, r.log, r.format, u.uid, u.name, u.picture, u.data 
FROM xyz_node n 
INNER JOIN xyz_users u ON n.uid = u.uid 
INNER JOIN xyz_node_revisions r ON r.vid = n.vid;

+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+
| id | select_type | table | type   | possible_keys | key     | key_len | ref          | rows | Extra       |
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+
|  1 | SIMPLE      | u     | ALL    | PRIMARY       | NULL    | NULL    | NULL         |  181 |             | 
|  1 | SIMPLE      | n     | ref    | vid,uid       | uid     | 4       | xyz.u.uid |    9 | Using where | 
|  1 | SIMPLE      | r     | eq_ref | PRIMARY       | PRIMARY | 4       | xyz.n.vid |    1 |             | 
+----+-------------+-------+--------+---------------+---------+---------+--------------+------+-------------+

知道可能会发生什么,以及我如何强迫MYSQL在此查询中使用Index?

3 个答案:

答案 0 :(得分:3)

表不一定按照FROM子句中指定的顺序连接。在这种情况下,看起来MySQL已经确定在查询中没有WHERE子句的情况下,首先扫描users表可能最快,然后将其与其他表连接起来。

我要做的第一件事就是在查询中涉及的所有三个表上运行ANALYZE TABLE。这会更新表统计信息和存储的密钥分发,并允许联接优化器做出更好的决策。之后运行EXPLAIN语句,看看它是否已更改。

如果没有更改,您可能需要使用STRAIGHT_JOIN关键字。这会强制连接优化器按照查询中指定的确切顺序连接表。为了帮助确定是否应该执行此操作,您应该从rows结果中获取所有EXPLAIN值的乘积,并将其与查询返回的实际行数进行比较。因此,在这种情况下,将1629(181x9x1)与实际行数进行比较。如果它们有显着差异,则可能会调用STRAIGHT_JOIN(用作SELECT的关键字,即SELECT STRAIGHT_JOIN n.nid ...等等。

顺便说一句,有一种tell MySQL to use a specific index的方法,但我不认为它会适用于此查询中的用户表,因为它现在没有,因为没有WHERE子句。如果您最终使用STRAIGHT_JOIN,则可能需要它,但在这种情况下,如果用户表不是连接中的第一个表,MySQL可能会接收主键。

您应该查看EXPLAIN syntax page以获取更多有用的详细信息。

此查询看起来不应该 它的速度慢。如果没有where子句,您可以期待在某处进行全表扫描,并且MySQL已将其保持在大约1700行检查。看起来这只是一个问题,如果它是一个高使用率的查询,在这种情况下你可能想要检查基础架构(没有WHERE子句)涉及运行一个将影响每个用户的查询系统,只会在添加更多用户时变得更重。

答案 1 :(得分:1)

由于MySQL每个查询每个表只能使用一个索引,因此有时可以通过抛出这个看似无用的条件来获得“自由”范围索引扫描。

WHERE u.uid > 0

尝试添加该子句,可能ALL表扫描将更改为“范围”,这比全表扫描更好。

答案 2 :(得分:0)

这有用吗?

在表节点中,在(uid,vid)上创建索引 ALTER TABLE'xyz_node'ADD INDEX user_ver('uid,'vid') (注意解释输出中的第二行..在标题可能的键下..你看vid,uid)