我有以下SQL代码:
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;
答案 0 :(得分: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
答案 1 :(得分:1)
我认为外连接正在强制进行表扫描,因为它需要包含所有匹配的记录,并为那些不匹配的记录提供空值。
mck89的解决方案可能会很好用,但我从来没有理由使用它......我很好奇这将如何发展。
答案 2 :(得分:1)
第一个可以使用索引,因为在内连接中,您将根据索引所基于的列(Event_Time)的值来过滤连接的结果集...
在第二个查询中,您正在使用外部联接,您不会过滤输出,因此无论event_time的值如何,它都需要包括结果集中的所有记录,因此它必须执行完整的表扫描......
答案 3 :(得分:1)
使用JOIN或WHERE子句中的函数将始终对索引造成严重破坏。例如:
DATE_ADD('1970-01-01 02:00:00', INTERVAL clg.uniqueid SECOND)
数据库正在使用uniqueid索引来查找转换的值,而不是与您的case中的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
答案 4 :(得分:-1)
您可以使用FORCE INDEX