使用 LEFT JOINS 优化 MySql 查询
Optimising MySql Query with LEFT JOINS
我正在尝试获取 6 个月或更长时间未订购的客户列表。我在查询中使用了 4 tables
- 帐户(account_id)
- 商店(store_id、account_id)
- 客户(store_id、customer_id)
- 订单(order_id、customer_id、store_id)
客户和订单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 的新手时并没有很好的直觉来判断哪些索引有用,哪些索引没用。因此,在寻求帮助时,展示您的索引总是好的。与此同时,阅读这篇文章:
从这里开始:
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" 问题。)
我正在尝试获取 6 个月或更长时间未订购的客户列表。我在查询中使用了 4 tables
- 帐户(account_id)
- 商店(store_id、account_id)
- 客户(store_id、customer_id)
- 订单(order_id、customer_id、store_id)
客户和订单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 的新手时并没有很好的直觉来判断哪些索引有用,哪些索引没用。因此,在寻求帮助时,展示您的索引总是好的。与此同时,阅读这篇文章:
从这里开始:
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" 问题。)