0

我们的环境: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 在此查询上使用索引?

4

3 回答 3

3

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

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

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

顺便说一句,有一种方法可以告诉 MySQL 使用特定的 index,但我认为它不会像现在这样适用于这个查询中的用户表,因为没有WHERE子句。如果您最终使用STRAIGHT_JOIN,您可能需要它,但在这种情况下,如果用户表不是连接中的第一个表,MySQL 可能会选择主键。

您还应该查看EXPLAIN 语法页面以获取更多有用的详细信息。

这个查询看起来不应该那么慢。如果没有 where 子句,您可能会在某处进行全表扫描,而 MySQL 已将其检查的总行数减少到大约 1700 行。看起来这只有在它是一个高使用查询时才会成为问题,在这种情况下,您可能想要检查底层架构(没有WHERE子句)涉及运行一个查询,该查询将影响系统中的每个用户,并且将随着更多用户的添加,只会变得更重。

于 2009-05-18T21:55:15.490 回答
1

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

WHERE u.uid > 0

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

于 2009-05-18T21:58:26.980 回答
0

这有帮助吗?

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

于 2009-10-04T02:27:22.070 回答