2009-08-26 17 views
2

运行永远我有以下SQL代码:MySQL的SELECT联接时改变

select val.PersonNo, 
     val.event_time, 
     clg.number_dialed 
    from vicidial_agent_log val 
     join 
     call_log   clg on date_add('1970-01-01 02:00:00', interval clg.uniqueid second) = val.event_time 
order by val.event_time desc 
limit 100; 

其执行并在不到1秒返回行。但是,如果我改变直接加入到left outer

select val.PersonNo, 
     val.event_time, 
     clg.number_dialed 
    from vicidial_agent_log val 
     left outer join 
     call_log   clg on date_add('1970-01-01 02:00:00', interval clg.uniqueid second) = val.event_time 
order by val.event_time desc 
limit 100; 

查询永远运行,并使用〜服务器的CPU的100%。

我跑了explain这两个查询和第一次点击event_time索引vicidial_agent_log,而第二个忽略所有索引。有一个索引call_log.uniqueid

vicidial_agent_log包含〜41,000行,call_log包含〜43,000。

所以我的问题是 - 为什么MySQL没有触及我定义的索引,有没有办法强制它这样做,如果没有,我该如何让这个查询以可接受的速度运行?

编辑

完整的解决方案:

select val.PersonNo, 
     val.event_time, 
     cl.number_dialed 
    from vicidial_agent_log val 
     left outer join 
     (select date_add('1970-01-01 02:00:00', interval clg.uniqueid second) as 'converted_date', 
       number_dialed 
      from call_log clg) cl ON cl.converted_date = val.event_time 
order by val.event_time desc 
limit 100; 

回答

1

在JOIN或WHERE子句中使用函数总是会对索引造成严重破坏。例如:

DATE_ADD('1970-01-01 02:00:00', INTERVAL clg.uniqueid SECOND) 

该数据库使用UNIQUEID索引来查找值的转换,而不是相比于你的情况EVENT_TIME柱。如果这是开启PLW错误的Oracle,您将收到关于潜在转换数据类型的通知。

这种情况应该始终在比较之前处理,这意味着使用内联视图执行转换并加入到结果列中。 IE:

JOIN (SELECT DATE_ADD('1970-01-01 02:00:00', INTERVAL clg.uniqueid SECOND) 'converted_date' 
     FROM CALL_LOG clg) cl ON cl.converted_date = val.event_time 
+0

读取所有的行仍然直观地阅读。但是,Quassnoi的回答和评论也非常有用。 – 2009-08-27 07:29:57

-1

您可以使用FORCE INDEX

+0

FORCE INDEX不会改善的事情,因为外部联接仍然需要,因为这个代码运行速度最快,从接受这个作为答案vicidial_agent_log表 – 2009-08-26 16:18:46

1

我想象中的外部联接强制表扫描,因为它需要包括所有匹配的记录,为那些没有的人提供空值。

mck89的解决方案可能工作得很好,虽然我从来没有理由使用它......我很好奇这将如何结果。

1

第一可以使用索引,因为在一个内连接要筛选的结果集的基础上,柱(EVENT_TIME)该指数基于的值加入...

在第二查询,在您使用外连接的情况下,您不会筛选输出,因此无论event_time的值如何,都需要包括结果集中的所有记录,因此它必须执行完整的表扫描...

3

当您使用LEFT JOIN,该LEFT表始终领先MySQL

在您的初始查询中,MySQL可以选择哪个表作为主导,并选择clg

现在它不能选择,而这种情况:date_add('1970-01-01 02:00:00', interval clg.uniqueid second)是不可挑剔的。

date_add('1970-01-01 02:00:00', interval clg.uniqueid second)没有索引MySQL可用于查找val.event_time的值。

重写查询,因为这:

SELECT val.PersonNo, 
     val.event_time, 
     clg.number_dialed 
FROM vicidial_agent_log val 
LEFT OUTER JOIN 
     call_log clg 
ON  clg.uniqueid = UNIX_TIMESTAMP(val.event_time) - 7200 
ORDER BY 
     val.event_time desc 
LIMIT 100 
+0

mysql是否支持函数索引? – 2009-08-26 18:17:00

+0

'@ rexem':没有。它也不支持'HASH JOIN'或'MERGE JOIN'。使查询快速运行的唯一方法是将其重写为使用可靠的条件。 – Quassnoi 2009-08-26 18:31:41

+0

使用物化视图怎么样? – 2009-08-26 18:35:29