使用union和left join的mysql查询很慢

时间:2014-12-24 14:39:53

标签: mysql join union

SELECT p.*
FROM (
    SELECT ProductID,ProductName,ProductCode,SampleRefNum 
    FROM products
    WHERE hidden = 'N'
    UNION ALL
    SELECT product_variants.ProductID,products.ProductName,product_variants.ProductCode,product_variants.SampleRefNum
    FROM product_variants
    JOIN products 
    ON product_variants.ProductID = products.ProductID
    ) AS p

LEFT JOIN stock_list AS s
ON p.ProductCode = s.ProductCode OR p.SampleRefNum = s.SampleRefNum
WHERE s.ProductCode IS NULL AND p.ProductCode IS NOT NULL AND p.ProductCode <> "" OR s.SampleRefNum IS NULL AND p.SampleRefNum IS NOT NULL AND p.SampleRefNum <> "" 

上面的查询非常慢,1分钟。如果我只是快速做联盟部分。或者只使用产品表而不是快速结合

(我在这做什么?) 产品有变种,所以我结合产品和产品变体,以获得具有产品代码和样品ref num的项目列表。 然后我加入库存清单(包含大约50 000行产品代码和来自另一个系统的示例参考代码的表),这样我就可以得到任何没有匹配的ProductCode或SampleRefNum的记录列表

------------修改

我在所有表格上的ProductID,ProductCode,SampleRefNum上都有索引

- 这很快-----

 SELECT p.ProductID,p.ProductName,p.ProductCode,p.SampleRefNum FROM products AS p
LEFT JOIN stock_list AS s
ON p.ProductCode = s.ProductCode OR p.SampleRefNum = s.SampleRefNum
WHERE p.Hidden = 'N' AND (s.ProductCode IS NULL AND p.ProductCode IS NOT NULL AND p.ProductCode <> "" OR s.SampleRefNum IS NULL AND p.SampleRefNum IS NOT NULL AND p.SampleRefNum <> "" )
AND (p.ProductID NOT IN(SELECT ProductID FROM product_variants) )

---这需要10秒

SELECT p.*
FROM (
    SELECT ProductID,ProductName,ProductCode,SampleRefNum 
    FROM products
    WHERE hidden = 'N'

    ) AS p

LEFT JOIN stock_list AS s
ON p.ProductCode = s.ProductCode OR p.SampleRefNum = s.SampleRefNum
WHERE s.ProductCode IS NULL AND p.ProductCode IS NOT NULL AND p.ProductCode <> "" OR s.SampleRefNum IS NULL AND p.SampleRefNum IS NOT NULL AND p.SampleRefNum <> "" 

1 个答案:

答案 0 :(得分:3)

一般join or条件会变慢。我建议您使用exists或更简单的left joins对查询进行重新措辞。但是,您可以使用两个左连接尝试此操作,看看是否符合您的要求:

SELECT p.*
FROM (SELECT ProductID, ProductName, ProductCode, SampleRefNum 
      FROM products p
      WHERE hidden = 'N'
      UNION ALL
      SELECT pv.ProductID, p.ProductName, pv.ProductCode, pv.SampleRefNum
      FROM product_variants pv JOIN
           products p
           ON pv.ProductID = p.ProductID
     ) p LEFT JOIN
     stock_list s1
     ON p.ProductCode = s1.ProductCode LEFT JOIN
     stock_list s2
     ON p.SampleRefNum = s2.SampleRefNum
WHERE (s1.ProductCode IS NULL AND p.ProductCode IS NOT NULL AND p.ProductCode <> '') OR
      (s2.SampleRefNum IS NULL AND p.SampleRefNum IS NOT NULL AND p.SampleRefNum <> '')

要使其正常运行,您需要stock_list上的两个索引:stock_list(ProductCode)stock_list(SampleRefNum)

注意:如果一个键上的stock_list中存在多个匹配而另一个键没有匹配,则可能会返回多行。我认为您的原始查询具有相同的问题。使用not exists子句可以解决这个问题。

编辑:

not exists看起来像:

WHERE (NOT EXISTS (select 1
                   from stock_list s1
                   where p.ProductCode = s1.ProductCode
                  ) and
       p.ProductCode is not null and p.ProductCode <> ''
      ) AND
      (NOT EXISTS (select 1
                   from stock_list s2
                   where p.SampleRefNum = s1.SampleRefNum
                  ) and
       p.SampleRefNum is not null and p.SampleRefNum <> ''
      )

您可以从join子句中删除from(这需要相同的索引)。