如何提高风数据SQL查询性能
Posted
技术标签:
【中文标题】如何提高风数据SQL查询性能【英文标题】:How to improve wind data SQL query performance 【发布时间】:2015-04-22 18:38:28 【问题描述】:我正在寻求有关如何优化(如果可能的话)SQL
查询性能的帮助,该查询用于读取风信息(见下文),方法是更改例如数据库结构、查询还是其他?
我使用托管数据库来存储一个包含超过 800,000 行风信息(速度和方向)的表。风速计每分钟添加新数据。使用php
脚本访问该数据库,该脚本创建一个网页,用于使用 Google 的可视化 API 绘制数据。
加载网页大约需要 15 秒。我在PHP
和javascript
部分添加了一些时间测量来分析代码并找到可能的改进领域。
我希望改进的部分是以下查询,它需要大约 4 秒来执行。查询的目的是对 15 分钟的风速(min/max/mean)进行分组,并计算出这段测量期间的平均值和总 min/max。
SELECT AVG(d_mean) AS group_mean,
MAX(d_max) as group_max,
MIN(d_min) AS
group_min,
dir,
FROM_UNIXTIME(MAX(dt),'%Y-%m-%d %H:%i') AS group_dt
FROM (
SELECT @i:=@i+1,
FLOOR(@i/15) AS group_id,
CAST(mean AS DECIMAL(3,1)) AS d_mean,
CAST(min AS DECIMAL(3,1)) AS d_min,
CAST(max AS DECIMAL(3,1)) AS d_max,
dir,
UNIX_TIMESTAMP(STR_TO_DATE(dt, '%Y-%m-%d %H:%i')) AS dt
FROM table, (SELECT @i:=-1) VAR_INIT
ORDER BY id DESC
) AS T
GROUP BY group_id
LIMIT 0, 360
...
$oResult = mysql_query($sSQL);
表格结构如下:
1 ID int(11) AUTO_INCREMENT
2 mean varchar(5) utf8_general_ci
3 max varchar(5) utf8_general_ci
4 min varchar(5) utf8_general_ci
5 dt varchar(20) utf8_general_ci // Date and time
6 dir varchar(5) utf8_general_ci
使用以下设置:
数据库:MariaDB,5.5.42-MariaDB-1~wheezy 数据库客户端版本:libmysql - 5.1.66 PHP 版本:5.6 PHP 扩展:mysqli【问题讨论】:
5 dt varchar(20) utf8_general_ci // Date and time
不要在字符字段中存储日期+时间。使用日期时间或时间戳(如果可用)并且,速度和方向类似:使用整数、数字甚至浮点类型,但不是字符类型来存储它们。
你能发布一个解释和数据模型吗?另外:请稍微格式化一下您的代码,使其更具可读性。
您的问题的很大一部分可能是隐式转换。这也会让您在查询时面临不必要的错误风险。只有 800k 行可能不是什么大问题,但这仍然是一个问题。还有糟糕的设计。
【参考方案1】:
到目前为止,我非常同意 cmets -- 在将数据放入表中时对其进行清理。
完成清理后,让我们通过执行...来避免子查询
SELECT MIN(dt) as 'Start of 15 mins',
FORMAT(AVG(mean), 1) as 'Avg wind speed',
...
FROM table
GROUP BY FLOOR(UNIX_TIMESTAMP(dt) / 900)
ORDER BY FLOOR(UNIX_TIMESTAMP(dt) / 900);
我不明白LIMIT
的用途。我猜你想一次几天。为此,我建议您在 FROM
和 GROUP BY
之间添加(aftercleaning)。
WHERE dt >= '2015-04-10'
AND dt < '2015-04-10' + INTERVAL 7 DAY
这将显示 7 天,从 '2015-04-10' 早上开始。
为了处理 800K 的表,您肯定需要(再次, 清理后):
INDEX(dt)
要清理 800K 行,有多种方法。我建议创建一个新表,将数据复制进去,测试并最终交换。比如……
CREATE TABLE new (
dt DATETIME,
mean FLOAT,
...
PRIMARY KEY(dt) -- assuming you have only one row per minute?
) ENGINE=InnoDB;
INSERT INTO new (dt, mean, ...)
SELECT str_to_date(...),
mean, -- I suspect that the CAST is not needed
...;
编写新的选择并测试它。
现在new
缺少更新的行。您可以重建它并希望在一分钟内完成所有事情,或者玩其他游戏。如果您需要帮助,请告诉我们。
【讨论】:
很抱歉没有更清楚地了解细节。您对使用 LIMIT 的假设是正确的。 我复制了该表,并按照您的建议更改了表中的两种数据类型并重写了 SQL 查询。一切正常。至于性能,查询的执行速度快了大约 1 秒,因此大约是 1 秒。速度提高 25%。 我错过了 INDEX(dt) 部分。您能否再解释一下这样做的目的是什么?通过运行“CREATE INDEX index_name ON table_name (column_name);”之类的查询是一次性任务吗?索引是我应该以某种方式使用的东西还是数据库内部问题? 索引是在添加新数据时自动更新,还是我必须不时手动重新索引? 索引对高性能至关重要。该索引很有用,因为它可能会缩小要查看的行数。 (我说“可能”是因为如果范围覆盖了表的“太多”,优化器可能会合法地选择扫描表而不是使用索引。)是的,CREATE INDEX
(或ALTER TABLE..ADD INDEX..
)是一个-时间任务;这需要一些时间。之后,索引将在插入行时自动(并且快速)更新。以上是关于如何提高风数据SQL查询性能的主要内容,如果未能解决你的问题,请参考以下文章