有没有办法强制执行MySQL执行顺序?

时间:2010-08-11 07:17:19

标签: mysql performance sql-execution-plan

我知道我可以使用FORCE INDEX (abc)关键字更改MySQL执行查询的方式。但有没有办法改变执行顺序?

我的查询如下:

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
  AND c.itemid = 123456

我有一个用于我使用的每个关系/约束的键。如果我在这个语句上运行解释,我看到mysql首先开始查询c。

id    select_type    table    type
1     SIMPLE         c        ref
2     SIMPLE         b        ref
3     SIMPLE         a        eq_ref

但是,我知道按a -> b -> c顺序查询会更快(我已经证明了这一点) 有没有办法告诉mysql使用特定的订单?

更新:我知道a -> b -> c更快。

上述查询需要1.9秒才能完成并返回7行。如果我将查询更改为

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
HAVING c.itemid = 123456

查询在0.01秒内完成(不使用我获得10.000行)。 然而,这不是一个优雅的解决方案,因为此查询是一个简化的示例。在现实世界中,我从c加入到其他表中。由于HAVING是一个在整个结果上执行的过滤器,因此我意味着我会从数据库中提取更多的记录而不是nescessary。

Edit2:只是一些信息:

  • 此查询中的变量部分是c.itemid。其他所有内容都是不变的固定值。
  • 索引设置正常,mysql为我选择正确的索引
    • 在a和b之间存在1:n关系(使用索引PRIMARY)
    • 在b和c之间存在多对多关系(使用索引IDX_ITEMID)

关键是mysql应该开始查询表a并将其工作到c而不是反过来。对此有任何改变。

解决方案:不完全是我想要的,但这似乎有效:

SELECT c.*
FROM table1 a
INNER JOIN table2 b ON a.id = b.table1_id
INNER JOIN table3 c ON b.itemid = c.itemid
WHERE a.itemtype = 1
  AND a.busy = 1
  AND b.something = 0
  AND b.acolumn = 2
  AND c.itemid = 123456
  AND f.id IN (
         SELECT DISTINCT table2.id FROM table1
         INNER JOIN table2 ON table1.id = table2.table1_id
         WHERE table1.itemtype = 1 AND table1.busy = 1)

3 个答案:

答案 0 :(得分:35)

也许你需要使用STRAIGHT_JOIN

http://dev.mysql.com/doc/refman/5.0/en/join.html

  

STRAIGHT_JOINJOIN类似,只是左表始终在右表之前读取。这可以用于连接优化器以错误顺序放置表的那些(少数)情况。

答案 1 :(得分:3)

您可以尝试以两种方式重写

  • 将一些WHERE条件带入JOIN
  • 引入子查询,即使它们不是必需的

这两件事都可能影响到规划师。

首先要检查的是,如果您的stats是最新的。

答案 2 :(得分:3)

您可以使用FORCE INDEX强制执行命令,我之前已经这样做了。

如果您考虑一下,通常只有一个订单可以查询您选择的任何索引的表格。

在这种情况下,如果您希望MySQL首先开始查询a,请确保您在b上强制使用的索引是包含b.table1_id的索引。如果已经首先查询a,MySQL将只能使用该索引。