我正在尝试获取可能的客户列表以及订单历史记录的总和(ltv)
如果没有订单,则此查询会在一秒钟内加载。使用order by
,查询时间超过90秒。
SELECT a.customerid,a.firstname,a.lastname,Orders.ltv
FROM customers a
LEFT JOIN (
SELECT customerid,
SUM(amount) as ltv
FROM orders
GROUP BY customerid) Orders
ON Orders.customerid=a.customerid
ORDER BY
Orders.ltv DESC
LIMIT 0,10
任何想法如何加速?
编辑:我想我清理了一下这个问题。该版本的查询实际上要复杂一些。其他数据从customers表中选择,也可以进行排序。答案 0 :(得分:4)
如果没有实际的架构,就很难知道数据是如何相关的,但我想这个查询应该是等效的并且性能更高:
SELECT a.customerid, coalesce(sum(o.amount), 0) TotalLtv FROM customers a
LEFT JOIN orders o ON a.customerid = o.cusomterid
GROUP BY a.customerid
ORDER BY TotalLtv DESC
LIMIT 10
coalesce
将确保您为没有订单的客户返回0
。
正如@ypercube让我注意到的那样,amount
上的索引也无济于事。你可以尝试一下:
ALTER TABLE orders ADD INDEX(customer, amount)
更新问题后
如果需要在select子句中添加功能上依赖于a.customerid
的更多字段,则可以使用非标准MySQL group by
子句。与a.customerid, a.firstname, a.lastname
分组:
SELECT a.customerid, a.firstname, a.lastname, coalesce(sum(o.amount), 0) TotalLtv
FROM customers a
LEFT JOIN orders o ON a.customerid = o.cusomterid
GROUP BY a.customerid
ORDER BY TotalLtv DESC
LIMIT 10
答案 1 :(得分:2)
这里有一些事情。首先,您似乎根本不需要加入customers
表,因为您只将customerid
用于orders
表中已经存在的SELECT customerid, SUM(amount) AS ltv
FROM orders
GROUP BY customerid
ORDER BY ltv DESC LIMIT 0,10
。如果您有超过10个具有相应金额的客户ID,您甚至不需要查看客户ID的列表,这些客户ID不具有您从客户处获得LEFT JOIN所获得的金额。因此,您应该能够减少对此的查询:
SELECT c.customerid, c.firstname, c.lastname, coalesce(o.ltv, 0) AS total
FROM customers AS c
LEFT JOIN (
SELECT customerid, SUM(amount) as ltv
FROM orders
GROUP BY customerid
ORDER BY ltv DESC LIMIT 0,10) AS o
ON c.customerid = o.customerid
您需要有关customerid的索引。不幸的是,排序是在计算字段上进行的,所以从那时起你可以做很多事情来加快速度。
我看到了更新的问题。由于您确实需要客户提供的其他字段,我将修改我的答案以包含客户表
{{1}}
请注意,我正在您在原始查询中加入一个子选择的表,但是我已经对子选择表执行了排序和限制,因此您不必对所有记录进行排序订单表上的条目。
答案 2 :(得分:0)
两件事。首先,不要使用内部查询。 MySQL确实允许在投影别名上使用ORDER BY。其次,你应该通过在组合键(customerid,amount)上使用B-TREE索引来获得相当大的改进。然后引擎将能够通过简单遍历索引来执行此查询,而无需获取任何行数据。