如何提高风数据SQL查询性能

Posted

技术标签:

【中文标题】如何提高风数据SQL查询性能【英文标题】:How to improve wind data SQL query performance 【发布时间】:2015-04-22 18:38:28 【问题描述】:

我正在寻求有关如何优化(如果可能的话)SQL 查询性能的帮助,该查询用于读取风信息(见下文),方法是更改​​例如数据库结构、查询还是其他?

我使用托管数据库来存储一个包含超过 800,000 行风信息(速度和方向)的表。风速计每分钟添加新数据。使用php 脚本访问该数据库,该脚本创建一个网页,用于使用 Google 的可视化 API 绘制数据。

加载网页大约需要 15 秒。我在PHPjavascript 部分添加了一些时间测量来分析代码并找到可能的改进领域。

我希望改进的部分是以下查询,它需要大约 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 的用途。我猜你想一次几天。为此,我建议您在 FROMGROUP 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查询性能的主要内容,如果未能解决你的问题,请参考以下文章

如何提高Oracle中动态sql的查询性能

如何提高sql中的查询性能?

如何提高下面提到的 SQL 查询中的文本列性能

使用具有中等数据的表提高 SQL Server 查询性能

如何提高包含部分公共子查询的 SQL 查询性能

如何提高子查询的性能或 sql 中子查询的替代方案