2012-10-26 270 views
2

我的任务是帮助加快此查询,并且我认为这些表中的一些索引没有正确设置。我也相信他们不会全部用于B/C函数应用于我有索引的列。任何人都可以看到我如何优化这些表或查询? requests表将成为3的最大表格,并且将具有超过200k +的记录。 devices目前正在坐~500条记录,clients也会变小。mysql查询优化

查询:

explain extended SELECT MAX(Request.datetime) AS datetime, Device.id, 
     Device.client_id, Device.mac_address, Device.type, Device.manufacturer, 
     Device.model_number, Client.id, Client.email_address, 
     Request.device_id, Request.datetime, Request.ip_address 
    FROM livefi.devices AS Device 
    LEFT JOIN livefi.clients AS Client 
    ON (Client.id   = Device.client_id) 
INNER JOIN livefi.requests AS Request 
    ON (Request.device_id = Device.id) 
GROUP BY Request.device_id, Request.client_id 

+----+-------------+---------+--------+---------------------------------------------------------+---------------+---------+-------------------------+------+----------+---------------------------------+ 
| id | select_type | table | type | possible_keys           | key   | key_len | ref      | rows | filtered | Extra       | 
+----+-------------+---------+--------+---------------------------------------------------------+---------------+---------+-------------------------+------+----------+---------------------------------+ 
| 1 | SIMPLE  | Device | ALL | PRIMARY             | NULL   | NULL | NULL     | 617 | 100.00 | Using temporary; Using filesort | 
| 1 | SIMPLE  | Client | eq_ref | PRIMARY             | PRIMARY  | 4  | livefi.Device.client_id | 1 | 100.00 |         | 
| 1 | SIMPLE  | Request | ref | idx_device_id,inx_requests_deviceId_datetime_ip_address | idx_device_id | 5  | livefi.Device.id  | 144 | 100.00 | Using where      | 
+----+-------------+---------+--------+---------------------------------------------------------+---------------+---------+-------------------------+------+----------+---------------------------------+ 
3 rows in set, 1 warning (0.04 sec) 

表:

CREATE TABLE `clients` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `email_address` varchar(100) DEFAULT NULL, 
    `mac_address` varchar(17) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `email_address` (`email_address`), 
    KEY `idx_mac_address` (`mac_address`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 


CREATE TABLE `devices` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `client_id` int(10) unsigned DEFAULT NULL, 
    `mac_address` varchar(17) DEFAULT NULL, 
    `type` varchar(25) DEFAULT NULL, 
    `manufacturer` varchar(100) DEFAULT NULL, 
    `model_number` varchar(50) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `mac_address` (`mac_address`), 
    KEY `idx_mac_address` (`mac_address`), 
    KEY `fk_devices_clients1` (`client_id`), 
    CONSTRAINT `fk_devices_clients1` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB AUTO_INCREMENT=492 DEFAULT CHARSET=utf8 


CREATE TABLE `requests` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `client_id` int(10) unsigned DEFAULT NULL, 
    `device_id` int(10) unsigned DEFAULT NULL, 
    `domain_id` int(10) unsigned DEFAULT NULL, 
    `ip_address` varchar(15) DEFAULT NULL, 
    `datetime` datetime DEFAULT NULL, 
    `gmt_offset` time DEFAULT NULL, 
    `request_method` varchar(15) DEFAULT NULL, 
    `url` text, 
    `http_protocol` varchar(20) DEFAULT NULL, 
    `http_status_code` varchar(20) DEFAULT NULL, 
    `request_size` int(10) unsigned DEFAULT '0', 
    `referer` text, 
    `user_agent` text, 
    `squid_cache_response` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`id`), 
    KEY `idx_client_id` (`client_id`), 
    KEY `idx_datetime` (`datetime`), 
    KEY `idx_device_id` (`device_id`), 
    KEY `idx_domain_id` (`domain_id`), 
    KEY `idx_id` (`id`), 
    KEY `idx_request_size` (`request_size`), 
    KEY `inx_requests_deviceId_datetime_ip_address` (`device_id`,`datetime`,`ip_address`), 
    CONSTRAINT `fk_requests_clients` FOREIGN KEY (`client_id`) REFERENCES `clients` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_requests_devices1` FOREIGN KEY (`device_id`) REFERENCES `devices` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION, 
    CONSTRAINT `fk_requests_domains1` FOREIGN KEY (`domain_id`) REFERENCES `domains` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION 
) ENGINE=InnoDB AUTO_INCREMENT=200523 DEFAULT CHARSET=utf8 

回答

0

我建议:

ALTER TABLE requests ADD INDEX (device_id, client_id, datetime); 

而且,请注意,您不应该在你的SELECT条款Request.datetime也不Request.ip_address,因为他们不是的一部分3210条款。这是因为requests中的几行可能具有相同的device_idclient_id,并且挑选哪个值为datetimeip_address有点随机。

0

我将有一个设备上的索引(Device_ID,ID),我已经提供了这个过去,并显然为另一个人工作。日期在查询中可能会有点瓶颈,但整数很容易。

如果你只是预先查询Device AND MAX(ID),这实质上是返回最近的日期/时间......因为ID是自动递增的,所以它的日期/时间值将直接关联为最近的..所以他们是一个在同一个。

如果您在多服务器的某种集群环境中可能会添加可能会导致错误最大条目的自己的auto-inc ID列,这是个例外。如果是这种情况,则将索引更改为(Device_ID,DateTime)。

这就是说,我会做以下

SELECT STRAIGHT_JOIN 
     PerQuery.Device_ID, 
     PreQuery.LastRequestID as Request_ID, 
     RDtl.datetime, 
     d.client_id, 
     d.mac_address, 
     d.type, 
     d.manufacturer, 
     d.model_number, 
     c.id, 
     c.email_address, 
     r.ip_address 
    FROM 
     (select rq.Device_ID, 
       MAX(rq.ID) as LastRequestID 
      from 
       livefi.Requests rq 
      group by 
       rq.Device_ID) PreQuery 
     JOIN livefi.Request RDtl 
      ON PreQuery.LastRequestID = RDtl.ID 
      JOIN livefi.Clients c 
       ON RDtl.ClientID = c.ID 
     JOIN livefi.Devices d 
       ON PreQuery.Device_ID = d.ID 

的prequery是唯一一个与GROUP BY和将直接优化索引...由于每个设备将只返回一个记录,其相应的“请求”ID,它将只加入原始请求表中的“其他”细节,客户端和设备细节。