我们的环境: 的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?
答案 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)