【发布时间】:2011-03-28 05:38:11
【问题描述】:
我知道我可以通过使用 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 是对整个结果执行的过滤器,这意味着我会从数据库中提取比必要更多的记录。
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)
【问题讨论】:
-
您如何证明
a -> b -> c会更快?另外,你能显示你的索引吗? -
至于测试哪个更快,如果没有实际预加载大量数据并模拟正常负载,可能很难测试。让 MySQL 进行自己的优化通常是件好事,随着您拥有的数据越多(随着时间的推移,或者运行 ANALYZE TABLE 一次或两次),它会变得越来越准确,并且只有在遇到问题时才强制索引。但是确实存在这样的问题;我肯定遇到过 MySQL 的查询计划非常糟糕的情况,但是在强制使用某个索引并因此加入顺序之后,它运行良好且高效。
-
@thomasrutter:如果 MySQL 的优化导致 2-7 秒(取决于负载/数据量)查询,除了使用我自己的优化之外,我别无选择 :) AS Hammerite 建议:STRAIGHT_JOIN 做什么我想和 1 将查询固定一千次。
标签: mysql performance sql-execution-plan