使用 LEFT JOINS 优化 MySql 查询

Optimising MySql Query with LEFT JOINS

我正在尝试获取 6 个月或更长时间未订购的客户列表。我在查询中使用了 4 tables

客户和订单table很大,分别是3M和26M行,所以在我的查询中使用左连接使得查询时间非常长。我相信我已经正确索引了我的 tables

这是我使用过的查询

SELECT cus.customer_id, MAX(o.order_date), cus.store_id, s.account_id, store_name
FROM customers cus 
LEFT JOIN stores s ON s.store_id=cus.store_id  
LEFT JOIN orders o ON o.customer_id=cus.customer_id AND o.store_id=cus.store_id
WHERE account_id=26  AND  
    (SELECT order_id 
        FROM orders o 
        WHERE o.customer_id=cus.customer_id 
        AND  o.store_id=cus.store_id 
        AND o.order_date < CURRENT_DATE() - INTERVAL 6 MONTH 
        ORDER BY order_id DESC LIMIT 0,1) IS NOT NULL 
GROUP BY cus.customer_id, cus.client_id;

我需要获取最后订单日期,这就是我加入 orders table 的原因,但是由于客户可以有多个订单,因此返回客户的多行,这就是我使用 group by 子句的原因。

如果有人可以帮助我查询。

您在 orders table 上使用有序且有限的子查询的策略可能是您性能不佳的原因。

此子查询将生成一个虚拟 table,显示每个不同客户的最新订单日期。 (我猜一个独特的客户是由一对 customer_id, store_id 区分的)。

                 SELECT MAX(order_date) recent_order_date,
                        customer_id, store_id
                   FROM orders
                  GROUP BY customer_id, store_id

然后,您可以使用该子查询 ,就好像它是查询中的 table

SELECT cus.customer_id, summary.recent_order_date, 
       cus.store_id, s.account_id, store_name
  FROM customers cus 
  JOIN stores s ON s.store_id=cus.store_id 
  JOIN (
              SELECT MAX(order_date) recent_order_date,
                     customer_id, store_id
                FROM orders
               GROUP BY customer_id, store_id
       ) summary  ON summary.customer_id = cus.customer_id
                 AND summary.store_id = s.store_id
 WHERE summary.recent_order_date < CURRENT_DATE - INTERVAL 6 MONTH
   AND store.account_id = 26

这种方法将 GROUP BY 移动到内部查询,并消除了浪费的 ORDER BY ... LIMIT 查询模式。不必为外部查询中的每一行重新进行内部查询。

我不明白你为什么在查询中使用 LEFT JOIN 操作。

而且,顺便说一句,大多数人在 SQL 的新手时并没有很好的直觉来判断哪些索引有用,哪些索引没用。因此,在寻求帮助时,展示您的索引总是好的。与此同时,阅读这篇文章:

http://use-the-index-luke.com/

从这里开始:

SELECT  customer_id, MAX(order_date) AS last_order_date
    FROM  orders
    GROUP BY  customer_id
    HAVING  last_order_date < NOW() - INTERVAL 6 MONTH;

假设给你相关的customer_ids,然后继续

SELECT ...
    FROM ( that-select-as-a-subquery ) AS old
    JOIN other-tables-as-needed  ON USING(customer_id)

如有必要,JOIN 返回订单以获取更多信息。 不要 尝试获取该子查询中的其他列。 (这是一个 "groupwise max" 问题。)