使用聚合的Mysql自连接速度慢,并且优化与预期不同

时间:2017-11-14 14:02:14

标签: mysql

我的查询执行缓慢(约20秒),经过大量阅读和挖掘后,我似乎无法找到解决方案。

查询是:

EXPLAIN EXTENDED 
SELECT t1.* 
FROM   tire_transaction AS t1 
       INNER JOIN (SELECT license_plate, 
                          Max(transaction_date) AS `last_checkin` 
                   FROM   tire_transaction 
                   GROUP  BY license_plate) AS t2 
               ON t1.license_plate = t2.license_plate 
                  AND t1.transaction_date = t2.last_checkin 
WHERE  ( t1.client_id = '1' ) 
       AND ( t1.deleted = 0 ) 

结果是:

id  select_type  table             type    possible_keys                                                              key                  key_len  ref                                 rows  filtered  Extra        
 1  PRIMARY      <derived2>        ALL     (NULL)                                                                     (NULL)               (NULL)   (NULL)                             69121    100.00               
 1  PRIMARY      t1                ref     client_id,license_plate,tire_transaction_date,deleted,license__trans_date  license__trans_date  67       t2.last_checkin,t2.license_plate       1    100.00  Using where  
 2  DERIVED      tire_transaction  index   (NULL)                                                                     license_plate        63       (NULL)                            366423    100.00               

表格是:

CREATE TABLE `tire_transaction` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `entity_id` int(11) DEFAULT NULL,
  `client_id` int(11) NOT NULL,
  `company_id` int(11) NOT NULL,
  `parent_id` int(11) DEFAULT NULL,
  `transaction_type` tinyint(1) DEFAULT '0',
  `transaction_date` date DEFAULT NULL,
  `transaction_status` int(11) DEFAULT NULL,
  `transaction_urgent` tinyint(1) NOT NULL DEFAULT '0',
  `license_plate` varchar(20) DEFAULT NULL,
  `license_plate_country` varchar(2) DEFAULT 'NL',
  `chassis_number` varchar(40) DEFAULT NULL,
  `brand` varchar(255) DEFAULT NULL,
  `brand_type` varchar(255) DEFAULT NULL,
  `client_name` varchar(255) DEFAULT NULL,
  `client_salutation` varchar(255) DEFAULT NULL,
  `client_company` varchar(255) DEFAULT NULL,
  `client_street` varchar(255) DEFAULT NULL,
  `client_number` varchar(255) DEFAULT NULL,
  `client_postalcode` varchar(255) DEFAULT NULL,
  `client_city` varchar(255) DEFAULT NULL,
  `client_phone` varchar(255) DEFAULT NULL,
  `client_phone_alt` varchar(255) DEFAULT NULL,
  `client_email` varchar(255) DEFAULT NULL,
  `tire_type` tinyint(1) DEFAULT '0',
  `set_price` int(11) DEFAULT NULL,
  `rim_material` tinyint(1) DEFAULT '0',
  `notes` text,
  `created` datetime DEFAULT NULL,
  `deleted` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `client_id` (`client_id`) USING BTREE,
  KEY `company_id` (`company_id`) USING BTREE,
  KEY `license_plate` (`license_plate`) USING BTREE,
  KEY `client_name` (`client_name`) USING BTREE,
  KEY `tire_transaction_entityId` (`entity_id`) USING BTREE,
  KEY `tire_transaction_parentId` (`parent_id`) USING BTREE,
  KEY `tire_transaction_date` (`transaction_date`),
  KEY `deleted` (`deleted`),
  KEY `license__trans_date` (`transaction_date`,`license_plate`)
) ENGINE=InnoDB AUTO_INCREMENT=418618 DEFAULT CHARSET=utf8

有400K行。 Mysql正在优化查询并将ON语句重写为WHERE语句,我认为这是缓慢的来源。

对此有什么看法?谢谢!

2 个答案:

答案 0 :(得分:0)

将过滤器添加到子查询中。我不确定这是否会返回相同的结果。但是根据列名称,看起来应该是这样。

SELECT t1.* 
FROM   tire_transaction AS t1 
       INNER JOIN (SELECT license_plate, 
                          Max(transaction_date) AS `last_checkin` 
                   FROM   tire_transaction 
                   WHERE  ( t1.client_id = '1' )  -- line added
                     AND  ( t1.deleted = 0 )      -- line added
                   GROUP  BY license_plate) AS t2 
               ON t1.license_plate = t2.license_plate 
                  AND t1.transaction_date = t2.last_checkin 
WHERE  ( t1.client_id = '1' ) -- line can probably be deleted
       AND ( t1.deleted = 0 ) -- line can probably be deleted

您还应该在(client_id, license_plate, transaction_date)上添加索引。

答案 1 :(得分:0)

您可能能够提高性能的一个方面是子查询,它涉及GROUP BY聚合(别名为t2)。考虑在license_platetransaction_date上添加综合索引:

CREATE INDEX tire_idx on tire_transaction(license_plate, transaction_date);

如果您在优化GROUP BY查询时仔细阅读MySQL documentation,则上述索引应允许MySQL通过松散索引扫描进行聚合。如果上述情况有效,那么当您运行Using index for group-by时,您应该会在Extra列中看到EXPLAIN