【问题标题】:mysql query with union and left join is slow带有联合和左连接的mysql查询很慢
【发布时间】:2015-02-22 16:01:51
【问题描述】:
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分钟。如果我只是快速完成工会部分。或者只使用 products 表而不联合它的快

(我在这里做什么?) 产品有变体,因此我将产品和产品变体结合起来,以获得具有产品代码和示例参考编号的项目列表。 然后我加入库存列表(包含大约 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. 如果您还没有这样做,请提供适当的 DDL(和/或 sqlfiddle),以便我们可以更轻松地复制问题。 2. 如果您尚未这样做,请提供与步骤 1 中提供的信息相对应的所需结果集。

标签: mysql join union


【解决方案1】:

通常joinor 条件会很慢。我建议您使用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 <> ''
      )

您将从from 子句中删除joins(这需要相同的索引)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-03
    相关资源
    最近更新 更多