1

我有以下非常慢的 SQL 语句。它从 600-800 毫秒不等!

我正在寻找优化它的可能方法,但不确定最佳路线。我的数据库相当大,entries表有 400,000 行,devices表有 90,000 行。


SQL 语句

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;

这个 SQL 语句慢是因为我在较差的硬件上运行它,还是因为语句不好,或者我没有正确构建表?任何想法将不胜感激!


声明的目标

获取所有设备制造商的列表,以及该制造商在条目表中出现的次数的相关计数。


表结构

设备

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;

参赛作品

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;

另外——我一直在研究备用数据库。考虑到这个数据库将来需要非常快速的读/写,像 Redis 这样的东西有用吗?

4

2 回答 2

2

如果您在 上添加多列索引,查询将运行得更快entries(waypoint_id, updated_at)

此外,您的查询看起来会更好,如下所示:

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

device_idPS:明确声明为外键不是一件好事吗?

于 2013-06-28T02:40:57.143 回答
1

你需要一个关于Entries {waypoint_id, updated_at}. 这应该满足:

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';

根据实际基数,您可能希望也可能不希望反转此复合索引中的字段顺序。

或者,在 上创建一个覆盖索引Entries {waypoint_id, updated_at, device_id},以避免Entries完全访问该表。


最重要的是,考虑在Devices {id, manufacturer}. 希望 MySQL 足够聪明,可以在不访问Devices表的情况下使用它来满足 JOIN 和聚合。

于 2013-06-28T02:47:24.280 回答