MySQL在“或”语句中编制索引

时间:2011-07-01 18:12:42

标签: mysql sql indexing

我需要加入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,则更改发生如下:

  • (S,C)的表连接类型从类型ref更改为eq_ref
  • key_len从4变为5(两者都有)
  • 从空到“使用位置”的额外更改。 如果从OR语句中删除了其中一个语句,则查询将以预期的速度运行。

表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秒以内。

我确实想澄清一点,我真的不需要一个有效解决方案的查询。感谢下面的小马已经提供了一个。我需要知道的是,是否有其他人遇到过这个问题并且可以解释为什么会发生这种情况以及我可以为这个简单或声明使用这两个索引做些什么。

1 个答案:

答案 0 :(得分:1)

如果您知道不会有重复项,请将UNION更改为UNION ALLUNION 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表。