我需要加入3个表,这些表使用索引很好地连接在一起。但是,我们正在从使用一个旧字段作为标识符转换到另一个表中的另一个字段。 LEGACYID是遗留领域,而NEWID是新领域。两个字段都是varchars。 这两个字段都只使用btree索引编制索引,两个表都是MyISAM。
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
JOIN TBLQ Q ON Q.SHPID = S.SHPID
WHERE C.LEGACYID = '692041'
OR Q.NEWID = '692041'
此查询需要5.147秒,比我预期的时间长5秒。
在执行EXPLAIN EXTENDED查询时,NEWID的索引类型为ALL,即全表扫描,可能的键是(primary,NEWID)和key(null)。如果我从Or语句中删除LEGACYID,则说明现在将使用密钥(NEWID)。如果我从OR语句中删除NEWID,则更改发生如下:
表Q有183k记录; C:115000; S:169K。 最后一点。如果我移动查询位置:
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
LEFT JOIN TBLQ Q ON Q.SHPID = S.SHPID
AND Q.NEWID = '692041'
WHERE C.LEGACYID = '692041'
虽然它的查询不一样,但对于数据的工作方式,它会提供我需要的结果,并且速度再次下降到0.1秒以内。
我确实想澄清一点,我真的不需要一个有效解决方案的查询。感谢下面的小马已经提供了一个。我需要知道的是,是否有其他人遇到过这个问题并且可以解释为什么会发生这种情况以及我可以为这个简单或声明使用这两个索引做些什么。
答案 0 :(得分:1)
如果您知道不会有重复项,请将UNION
更改为UNION ALL
(UNION ALL
更快,因为它不会删除重复项)。否则,请使用:
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
JOIN TBLQ Q ON Q.SHPID = S.SHPID
WHERE C.LEGACYID = '692041'
UNION
SELECT Username
FROM CUST C use index(primary,NEWID)
JOIN TBLSHP S ON S.CUSID = C.CUSID
JOIN TBLQ Q ON Q.SHPID = S.SHPID
WHERE Q.NEWID = '692041'
OR
是众所周知的糟糕表现者,因为它会破坏执行路径。 UNION
缓解了分裂,并结合了两个结果集。也就是说,IN
优于OR
,因为虽然逻辑上相同,但IN
的执行通常会更加优化。
UNION
并不总是答案调查许多选项,在确定解决方案之前比较EXPLAIN PLAN
输出。我最近遇到过一对使用游标比使用深奥功能的单个查询更好的表现。
此外,确保索引外键列(在JOINing时在ON
子句中使用的内容)。 MySQL已启动(v5.5 +?)以在进行外键约束时自动执行此操作,但这仅适用于InnoDB表。