有没有办法提高此查询的性能?

时间:2015-03-25 07:52:47

标签: mysql sql performance

我有这种模式:

Customer  (1) .... (n)  Orders

我可以通过简单的查询找到一个客户的所有订单:

select * from Orders o join Customer c on o.customer_id = c.id;

我需要找到所有客户的所有当前(今天)订单(如果他们有),展示所有客户。

EG。我期待的结果是这样的:

Customer     OrderDate           OrderStatus
Customer 1   2/1/2015 12:00:00        active
Customer 2   2/1/2015 13:00:00        closed
Customer 3    null                    null
Customer 4    null                    null 

表格应如下所示:

Customers
Customer 1
Customer 2
Customer 3
Customer 4

Orders        timestamp     CustomerID
Active   1/1/2015  15:00:00   1
Closed   1/1/2015  08:00:00   1
Canceled 1/1/2015  09:00:00   1
Closed   2/1/2015  11:00:00   1
Active   2/1/2015  12:00:00   1  //This is the last one of "TODAY" C1
Active   3/1/2015  18:00:00   1 
Closed   2/1/2015  13:00:00   2  //This is the last one of "TODAY" C2

正在运行的查询是:

select o.status, o.date, c.name from (
     select c.*, (
          select o1.id from orders o1 
             where o1.id_customer = c.id and o1.date between '2/1/2015 00:00:00' and "2/1/2015 23:59:59" 
             order by o1.date desc limit 1) as o
     from cliente c
) c left join orders o on o.id = c.o;

问题是,对于少量订单和客户,查询需要几秒钟才能执行。我预计短期内订单数量也会增加,客户数量也会增加。

有没有办法提高这个查询的效率?我觉得我是以错误的方式解决问题。

旁注:我无法修改模型,不能包含新列。我的第一个解决方案是向客户提供最后一个订单,并在每次创建订单时设置它,但遗憾的是我无法更改数据库。

提前致意并表示感谢!

[编辑]

表定义

CREATE TABLE `customer` (
    `id` char(36) NOT NULL,
    `name` varchar(120) NOT NULL,
    `cabin` enum('CABIN_A','CABIN_B','CABIN_C','CABIN_D','CABIN_E') DEFAULT NULL,
    `addressId` char(36) NOT NULL,
    `phone` varchar(45) DEFAULT NULL,
    `datetime` timestamp NULL DEFAULT NULL,
    `number` bigint(20) unsigned NOT NULL,
    `unitId` char(36) DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `id_UNIQUE` (`id`),
    UNIQUE KEY `number_UNIQUE` (`number`),
    KEY `addressId_idx` (`addressId`),
    KEY `fk_customer_unit_idx` (`unitId`),
    CONSTRAINT `fk_customer_unit` FOREIGN KEY (`unitId`) REFERENCES `unidad` (`unitId`) ON DELETE NO ACTION ON UPDATE NO ACTION,
    CONSTRAINT `fk_address_customer` FOREIGN KEY (`addressId`) REFERENCES `address` (`addressId`) ON DELETE CASCADE ON UPDATE NO ACTION,
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `orders` (
    `id` char(36) NOT NULL,
    `customerId` char(36) NOT NULL,
    `status` enum('ACTIVE','CLOSED','CANCELED') NOT NULL,
    `datetime` timestamp NULL DEFAULT NULL,
    `comment` varchar(700) DEFAULT NULL,
    `programDate` timestamp NULL DEFAULT NULL,
    `cabin` varchar(10) DEFAULT NULL,
    `unitId` char(36) DEFAULT NULL,
    PRIMARY KEY (`id`),
    UNIQUE KEY `id_UNIQUE` (`id`),
    KEY `fk_orders_unit_idx` (`unitId`),
    CONSTRAINT `fk_customer_orders` FOREIGN KEY (`customerId`) REFERENCES `customer` (`customerId`) ON DELETE NO ACTION ON UPDATE NO ACTION,
    CONSTRAINT `fk_unit` FOREIGN KEY (`unitId`) REFERENCES `unit` (`unitId`) ON DELETE NO ACTION ON UPDATE NO ACTION,
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

3 个答案:

答案 0 :(得分:2)

没有子查询的简单LEFT JOIN应该可以加快速度:

select  o.status, o.date, c.name 
from Orders o 
join Customer c
    on o.customer_id = c.id
    AND o.orderDate = '2/1/2015'

我假设,根据原始问题(来自“我期待的结果......”),您希望任何今天没有订单的客户返回NULL。

我有点困惑为什么客户#1的2'​​已关闭'和1'已取消'订单不属于“我期待的结果”,因为您的“查询”中不需要orderStats = 'Active'正在运作“......显然,既然你列出了客户#2的已关闭订单,实际上并不是要求订单开放 - 也许你想详细说明这一点。

答案 1 :(得分:0)

我会选择一个更简单的解决方案,使用LEFT JOIN:

SELECT c.name AS Customer,
       o.date AS  OrderDate,
       o.status AS OrderStatus
FROM cliente c
LEFT JOIN orders o ON (o.id_customer = c.id AND o.date = '2/1/2015')

但我想知道为什么你想要选择这两者之间唯一的第一行:

Closed   2/1/2015  1
Active   2/1/2015  1

这个id是什么?顾客ID?订单ID?不是那么清楚......

答案 2 :(得分:0)

请查看此页面:http://www.mysqltutorial.org/mysql-row_number/

我认为您可以使用每个组的行号。您必须由客户打理,订单是customer_id,status。 在获得行号后,只需选择数字1。