0

我正在尝试获取可能客户的列表以及他们的订单历史总和(ltv)

如果没有 order by,此查询将在一秒钟内加载。使用order byand 查询将花费超过 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

有什么想法可以加快速度吗?

编辑:我想我清理了查询太多了。查询实际上比这个版本复杂一点。其他数据是从客户表中选择的,也可以进行排序。

4

3 回答 3

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)

在您的问题更新后

如果您需要添加更多在功能上依赖于a.customeridselect 子句的字段,您可以使用非标准 MySQLgroup 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
于 2013-10-21T19:37:48.640 回答
2

这里有几件事。首先,您似乎根本不需要customers在这里加入表格,因为您只将它用于tablecustomerid中已经存在的orders. 如果您有超过 10 个具有相应金额的客户 id,您甚至不需要查看客户 id 的列表,这些客户 id 没有从客户处获得的金额。因此,您应该能够将查询减少到:

SELECT customerid, SUM(amount) AS ltv
FROM orders
GROUP BY customerid
ORDER BY ltv DESC LIMIT 0,10

您需要一个关于 customerid 的索引。不幸的是,排序是在计算字段上进行的,因此从那时起,您无法做很多事情来加快速度。

我看到更新的问题。由于您确实需要客户的其他字段,因此我将修改我的答案以包括客户表

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

请注意,我正在加入一个子选定的表,就像您在原始查询中所做的那样,但是我已经对子选定的表执行了排序和限制,因此您不必在没有任何订单条目的情况下对所有记录进行排序桌子。

于 2013-10-21T19:39:21.620 回答
0

两件事情。首先,不要使用内部查询。MySQL 确实允许对投影别名进行 ORDER BY。其次,您应该通过在组合键(customerid、amount)上使用 B-TREE 索引来获得相当大的改进。然后引擎将能够通过简单的索引遍历来执行此查询,而无需获取任何行数据。

于 2013-10-21T19:48:32.767 回答