“阅读”表包含今天每 40 秒获取的读数。查询返回 180 秒期间的平均值。 'time_stamp' 已编入索引。下面的查询返回合理数量的行(几百)但访问所有行并且表越大变得越慢。 WHERE 子句似乎并没有将其仅限于今天的行。
EXPLAIN SELECT
DATE_FORMAT(time_stamp, '%Y-%m-%dT%T+00:00') ,
AVG(temp_c)
FROM reading
WHERE DATE(time_stamp) = CURDATE()
GROUP BY round(UNIX_TIMESTAMP(time_stamp) / 180)
表架构:
CREATE TABLE <code>reading</code> (
<code>id</code> bigint(20) NOT NULL AUTO_INCREMENT,
<code>time_stamp</code> timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
<code>temp_c</code> float NOT NULL,
<code>pressure_hpa</code> float NOT NULL,
<code>wind_speed_kt</code> int(11) NOT NULL,
<code>wind_dir_degree</code> int(11) NOT NULL,
<code>rain_mm</code> float NOT NULL,
<code>rain_day_mm</code> float NOT NULL,
<code>wind_gust_kt</code> int(11) NOT NULL,
<code>humidity</code> float DEFAULT NULL,
PRIMARY KEY (<code>id</code>),
KEY <code>time_stamp</code> (<code>time_stamp</code>),
KEY <code>time_stamp_idx</code> (<code>time_stamp</code>)
) ENGINE=InnoDB AUTO_INCREMENT=1747097 DEFAULT CHARSET=latin1;
最佳答案
EXPLAIN SELECT
DATE_FORMAT(time_stamp, '%Y-%m-%dT%T+00:00') ,
AVG(temp_c)
FROM reading
WHERE DATE(time_stamp) = CURDATE()
GROUP BY round(UNIX_TIMESTAMP(time_stamp) / 180)
执行上述查询时,MySQL 优化器对索引扫描不感兴趣(可能是因为成本因素),而是启动全表扫描,问题似乎是因为 WHERE DATE(time_stamp) = CURDATE()
.
将您的 where 子句更改为 time_stamp >= CURDATE()
后,我发现使用了索引并且在避免完全扫描时获取的行数较少。
因此,您的最终查询将是:
EXPLAIN SELECT
DATE_FORMAT(time_stamp, '%Y-%m-%dT%T+00:00') ,
AVG(temp_c)
FROM reading
WHERE time_stamp >= CURDATE()
GROUP BY round(UNIX_TIMESTAMP(time_stamp) / 180);
我怀疑 date(time_stamp)
使用索引时效率不高。讨论了类似的话题here (参见 ypercube 的回答)。
可以通过选择 round(UNIX_TIMESTAMP(time_stamp)/180)
来进一步改进上述查询,因为 UNIX_TIMESTAMP(timestamp)
不使用索引。但是,我不会再尝试了。
希望这对您有所帮助!
关于mysql - 为什么SQL查询要访问所有行而且很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44367108/