2

我有以下 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;
4

5 回答 5

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
于 2009-08-26T16:22:41.913 回答
1

我想外连接正在强制进行表扫描,因为它需要包含所有匹配的记录并为不匹配的记录提供空值。

mck89 的解决方案可能会很好用,虽然我从来没有理由使用它……我很好奇结果如何。

于 2009-08-26T16:13:04.850 回答
1

第一个可以使用索引,因为在内部联接中,您正在根据索引所基于的列 (Event_Time) 的值过滤联接的结果集...

在第二个查询中,您使用的是外连接,您没有过滤输出,因此无论 event_time 的值如何,它都需要包含结果集中的所有记录,因此它必须进行完整的表扫描...

于 2009-08-26T16:16:55.670 回答
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
于 2009-08-26T16:19:17.460 回答
-1

您可以使用FORCE INDEX

于 2009-08-26T16:09:31.753 回答