MySQL - 用更高效的东西替换子查询

时间:2014-02-18 12:24:35

标签: mysql

我正在尝试显示客户列表以及他们所下订单的数量以及上次订单的日期。有些客户可能没有下订单。

我在注册日期过滤客户,目前我只对最近注册的客户感兴趣。我认为我当前的查询首先为所有客户运行子查询,然后执行WHERE查找。

如何提高此查询的效率?

select 
customers.*, 
addresses.*,
(select count(*) from orders where customerID=customers.customerID) orders,
(select orderDate from orders where customerID=customers.customerID order by orderID desc     limit 1) lastOrder                    
from customers 
left join addresses on customers.defaultCollection=addresses.addressID 
where 
registrationDate >= '2014-02-04' 

2 个答案:

答案 0 :(得分:2)

这是您的查询,每列都有表别名,以清楚地标识它们的来源(我希望我把它们弄好):

select c.*, a.*,
       (select count(*) 
        from orders o
        where o.customerID = c.customerID
       ) as orders,
       (select o.orderDate
        from orders o
        where o.customerID = c.customerID
        order by o.orderID desc
        limit 1
       ) as lastOrder                    
from customers c left join
     addresses a
     on c.defaultCollection = a.addressID 
where c.registrationDate >= '2014-02-04' ;

查询不一定是坏的。它可以从一些索引中受益:customers(registrationDate, defaultCollection, CustomerId)addresses(addressId),最重要的是orders(CustomerID, orderId, orderDate)。这些索引可能足以达到您想要的性能。

实际上,将其转换为聚合查询可能没有用,因为您必须添加聚合:

select c.*, a.*, count(o.customerId) as numOrders,
       substring_index(group_concat(o.OrderDate order by o.OrderId desc), ',', 1) as LastOrderIdOrderDate
from customers c left join
     addresses a
     on c.defaultCollection = a.addressID left join
     orders o
     on o.customerId = c.customerId
where c.registrationDate >= '2014-02-04'
group by c.customerId, a.AddressId;

substring_index()表达式是您在问题中执行的操作 - 获取最大orderId的日期。如果这是最大订单日期,那么更好的表达式是max(o.OrderDate)

答案 1 :(得分:0)

这有效吗?

 select 
 c.*, 
 a.*,
 count(*) ,
 max(orderDate) as  lastOrder
 from customers c 
 left join addresses a 
 on c.defaultCollection=a.addressID 
 left join orders o 
 on o.customerID=c.customerID
 where 
 registrationDate >= '2014-02-04' 
 group by o.customerID