LEFT JOIN忽略ON子句并检查每一行。为什么?

时间:2014-08-01 23:17:15

标签: mysql join left-join

我有以下查询

SELECT MAKEDATE( LEFT(IF(i_id = 0, Job.FillDate, BillingDate), 4 ) , 
       RIGHT( IF(i_id = 0, Job.FillDate, BillingDate), 3 ) ) as day, 
       IFNULL(ROUND(SUM(GREATEST((IF(i_id = 0 AND ISNULL(BillAmt), (PaidByPlan1+PaidByPlan2+Cashpaid), IF(ISNULL(BillAmt),(PaidByPlan1+PaidByPlan2+Cashpaid), (BillAmt+Cashpaid)))),0.00)),2),0.00) as total_pay, 
       Count(*) as total_transactions 
FROM `job` AS `Job` 
LEFT JOIN `jobtrak` AS `JobTrack` ON (
  `Job`.`id` = `JobTrack`.`job_id` 
  AND  IF(i_id = 0, `Job`.`FillDate`, BillingDate) BETWEEN 2014183 AND 2014212 
  AND LENGTH( CONV( Jobstatus, 10, 2 ) ) NOT IN ( 5, 6, 8 ) 
  AND `Job`.`Active` = 0 ) 
GROUP BY IF(i_id = 0, `Job`.`FillDate`, BillingDate);

以下查询耗尽了我的mysql服务器并导致页面永远不会加载到我的应用程序上。所以,我查看了解释,它显示Job表正在检索所有493345条记录,JobTrack表从其表中获取所有286812条记录。为什么这样做?有什么建议??

3 个答案:

答案 0 :(得分:1)

`Job`.`id` = `Job`.`job_id` 

您正在加入同一张表中的列

答案 1 :(得分:1)

这是你的查询,清理了一下,所以我发现它更具可读性:

SELECT MAKEDATE( LEFT(IF(i_id = 0, j.FillDate, BillingDate), 4 ) , 
       RIGHT( IF(i_id = 0, j.FillDate, BillingDate), 3 ) ) as day, 
       IFNULL(ROUND(SUM(GREATEST((IF(i_id = 0 AND ISNULL(BillAmt), (PaidByPlan1+PaidByPlan2+Cashpaid), IF(ISNULL(BillAmt),(PaidByPlan1+PaidByPlan2+Cashpaid), (BillAmt+Cashpaid)))),0.00)),2),0.00) as total_pay, 
       Count(*) as total_transactions 
FROM job j LEFT JOIN
     jobtrak jt
     ON j.id = jt.job_id AND
        IF(i_id = 0, j.FillDate, BillingDate) BETWEEN 2014183 AND 2014212 AND
        LENGTH( CONV( Jobstatus, 10, 2 ) ) NOT IN ( 5, 6, 8 ) AND
        j.Active = 0 
GROUP BY IF(i_id = 0, j.FillDate, BillingDate);

j.Active =0子句中的表达式where正在执行 nothing 。因为您有left join,所以从job表返回所有行,即使谓词的计算结果为false也是如此。所以,我怀疑你的意思是:

SELECT MAKEDATE( LEFT(IF(i_id = 0, j.FillDate, BillingDate), 4 ) , 
       RIGHT( IF(i_id = 0, j.FillDate, BillingDate), 3 ) ) as day, 
       IFNULL(ROUND(SUM(GREATEST((IF(i_id = 0 AND ISNULL(BillAmt), (PaidByPlan1+PaidByPlan2+Cashpaid), IF(ISNULL(BillAmt),(PaidByPlan1+PaidByPlan2+Cashpaid), (BillAmt+Cashpaid)))),0.00)),2),0.00) as total_pay, 
       Count(*) as total_transactions 
FROM job j LEFT JOIN
     jobtrak jt
     ON j.id = jt.job_id AND
        IF(i_id = 0, j.FillDate, BillingDate) BETWEEN 2014183 AND 2014212 AND
        LENGTH( CONV( Jobstatus, 10, 2 ) ) NOT IN ( 5, 6, 8 )
WHERE j.Active = 0 
GROUP BY IF(i_id = 0, j.FillDate, BillingDate);

JobStatus位于jobtrak表中。如果没有,它也应该移到where

真正有用的唯一索引是jobtrack(job_id)job(active)。表达式LENGTH( CONV( Jobstatus, 10, 2 ) )非常不寻常。在大多数业务应用程序中,通常不会比较十进制数的二进制表示的长度。

答案 2 :(得分:0)

查询正在检索job表中的所有行,因为没有任何谓词限制从该表返回的行。 (引用该表的谓词出现在ON操作的LEFT JOIN子句中,因此这些谓词仅影响从jobtrack表返回的行。)

就从jobtrak表中获取行而言,该表中的每一行可能“匹配”job表中的一行。如果job_trak.job_id是引用job.id的非NULL FOREIGN KEY,那将是真的。


如果要限制从job表返回的行,则需要在WHERE子句中包含谓词。