MySQL LEFT JOIN在两列中的任何一列上

时间:2016-08-24 23:10:45

标签: mysql left-join

我想在两列中的一列上连接两个表。我不知道哪一个会匹配。当从列表表中找到匹配的行时,我想要feed_REIN中的所有记录和其他数据。我认为LEFT JOIN会起作用。

当我只有一个条件(即RETS.list_number = listings.CVMLS)时,它运行正常。一旦我在LEFT JOIN中添加额外的OR条件,就需要永远完成查询。

feed_RETS有大约125,000条记录,列表大约有12k条记录。

我做错了什么?

SELECT 

COUNT(*)

FROM feed_RETS AS RETS LEFT JOIN listings ON listings.statusID IN (1,2,3) AND (RETS.list_number = listings.CVMLS OR RETS.list_number = listings.REIN) 

WHERE RETS.public_status NOT LIKE '%Sold%'

3 个答案:

答案 0 :(得分:0)

试试这个:

SELECT 
COUNT(*)
FROM feed_RETS AS RETS 
LEFT JOIN listings on
    RETS.list_number = listings.CVMLS 
    OR RETS.list_number = listings.REIN
WHERE public_status NOT LIKE '%Sold%' and statusID IN (1,2,3) 

答案 1 :(得分:0)

查看解释计划以更好地理解带有OR子句的查询。对于此查询,唯一可能的连接算法可能是嵌套循环连接,这对于表来说效率非常低。您可以将查询重写为:

SELECT 
COUNT(*)
FROM(
(SELCT * FROM feed_RETS AS RETS LEFT JOIN listings ON statusID IN (1,2,3) AND RETS.list_number = listings.CVMLS WHERE public_status NOT LIKE '%Sold%')
UNION
(SELCT * FROM feed_RETS AS RETS LEFT JOIN listings ON statusID IN (1,2,3) AND RETS.list_number = listings.REIN WHERE public_status NOT LIKE '%Sold%'))T

答案 2 :(得分:0)

如果您打算使用cvmls OR rein(exclusive或),并且应用程序确保其中任何一个都可以为true而不是两者,那么逻辑上LEFT JOIN将是不必要的,并且查询将始终产生相同的行数。但是,如果两者可以在同一行上匹配,那么请考虑是否需要COUNT(*)[所有可能的匹配,包括来自联接左侧的重复]或COUNT(DISTINCT r.list_number)[仅限不同的列表] :

-- Query 1
SELECT COUNT(*)
  FROM feed_RETS AS RETS LEFT JOIN listings 
                                ON listings.statusID IN (1,2,3)
                               AND (    RETS.list_number = listings.CVMLS 
                                     OR RETS.list_number = listings.REIN
                                   ) 
 WHERE RETS.public_status NOT LIKE '%Sold%'
;

-- Query 2 - Is the count the same?
SELECT COUNT(*)
  FROM feed_RETS 
 WHERE public_status NOT LIKE '%Sold%'
;

如果查询2返回不同的计数,那么请注意列表表中有多行被计数多次。如果你不想要那个,那么你需要一个不同的计数 - 或者可能是以下改进之一。

如果查询是为了限制此联接的所有条件返回的行,那么您需要INNER JOIN(为了清楚起见,也可以将ON条件移到WHERE条款):

SELECT COUNT(*)
  FROM feed_RETS AS RETS INNER JOIN listings 
                                 ON (    RETS.list_number = listings.CVMLS 
                                      OR RETS.list_number = listings.REIN
                                    ) 
 WHERE listings.statusID IN (1,2,3)
   AND RETS.public_status NOT LIKE '%Sold%'
;

由于两个原因(根据一般假设尽力诊断),您的查询可能仍然很慢:

  1. OR条件中的JOIN会强制进行全表扫描,因为优化程序不知道要使用哪个索引或是否使用任何索引。
  2. 匹配字符串%开头的通配符'%Sold%强制进行全表扫描,因为通过将列内容从左向右划分来构建正常类型的索引。将索引视为按字母顺序排列的名称列表:如果您在名称的开头匹配("名称以' Jo'"开头),您可以使用您的有序列表,以便快速找到匹配的名称;相反,如果您正在寻找名称中间的某些内容("名称中包含' nat'在其中")那么您的索引对您没用。
  3. 此查询实际上可能更快:

    SELECT SUM(CASE 
                 WHEN l_cvmls.cvmls IS NOT NULL OR l_rein.REIN IS NOT NULL 
                 THEN 1 
                 ELSE 0
               END
              ) listing_count
      FROM (  feed_RETS AS r LEFT JOIN listings l_cvmls
                                   ON l_cvmls.statusID IN (1,2,3)
                                  AND r.list_number = l_cvmls.CVMLS
           ) LEFT JOIN listings l_rein ON l_rein.statusID IN (1,2,3)
                                      AND r.list_number = l_rein.REIN
     WHERE r.public_status NOT LIKE '%Sold%'
    ;
    

    如果您可以避免使用'%Sold%'并使用'Sold%',那么查询可能会更快。