I have the following SQL statement that is VERY slow. It varies from 600-800ms!
I'm looking for possible ways to optimize it, but not sure exactly the best route. My database is fairly big, with the entries
table having 400,000 rows and the devices
table having 90,000 rows.
SQL Statement
SELECT devices.manufacturer, COUNT(devices.manufacturer) AS device_count
FROM entries
JOIN devices ON entries.device_id=devices.id
WHERE waypoint_id IN (1,2,3,5)
AND entries.updated_at >= '2013-06-20 21:01:40 -0400'
AND entries.updated_at <= '2013-06-27 21:01:40 -0400'
GROUP BY devices.manufacturer;
Is this SQL statement slow because I'm running it on poor hardware, or because the statement is bad, or have I not structured the table correctly? Any thoughts would be appreciated!
Goal of Statement
Get a list of all the device manufacturers, and the associated count of how many times that manufacturer showed up in the entries table.
Table Structure
Devices
id int(11) NOT NULL AUTO_INCREMENT,
mac_address varchar(255) DEFAULT NULL,
user_id int(11) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
manufacturer varchar(255) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY mac_address (mac_address),
KEY manufacturer (manufacturer)
ENGINE=InnoDB AUTO_INCREMENT=839310 DEFAULT CHARSET=utf8;
Entries
id int(11) NOT NULL AUTO_INCREMENT,
device_id int(11) DEFAULT NULL,
created_at datetime NOT NULL,
updated_at datetime NOT NULL,
waypoint_id int(11) DEFAULT NULL,
unsure tinyint(1) DEFAULT '0',
PRIMARY KEY (id),
KEY device_index (device_id)
ENGINE=InnoDB AUTO_INCREMENT=3389538 DEFAULT CHARSET=utf8;
Also– I have been looking into alternate databases. Considering this database is going to need very fast read/writes in the future, would something like Redis be of use?
The query would run faster if you added a multiple-column index on entries(waypoint_id, updated_at)
.
Also, you query would look better like this:
SELECT
devices.manufacturer,
COUNT(devices.manufacturer) AS device_count
FROM
entries
JOIN
devices ON devices.id = entries.device_id
WHERE
entries.waypoint_id IN (1,2,3,5)
AND
entries.updated_at BETWEEN '2013-06-20 21:01:40 -0400' AND '2013-06-27 21:01:40 -0400'
GROUP BY
devices.device_id
P.S.: wouldn't it be a good thing to explicitely declare device_id
as a foreign key?