SQL语句性能优化问题

我想实现显示一天当中每分钟的温度,但是我录入的温度数据有空缺不是每分钟都有。
所以我采用下面的方法获取值

WITH RECURSIVE dates(datetime) 
AS ( 
SELECT datetime('2023-08-24 00:00:00') as datetime 
UNION ALL 
SELECT datetime(datetime, '+1 minute') 
FROM dates WHERE datetime < datetime('2023-08-25 00:00:00')
)
SELECT dates.datetime as Time, COALESCE(tb.AT, '999') as VALUE 
FROM dates 
LEFT JOIN (SELECT * FROM OS_AT WHERE OS_AT.StationNo = '1111') AS tb 
ON dates.datetime = datetime(tb.Time) ORDER BY dates.datetime

现在的问题是随着记录数越来越多,这段sql查询需要6秒钟。
希望看到的佬哥能给我一些优化建议,提高查询的速度。

优化建议如下:

  1. 在SELECT语句中避免不必要的计算。

在SELECT语句中,使用COALESCE函数对tb.AT进行了空值处理,但是这个函数的使用可能导致不必要的计算。可以将COALESCE函数替换为直接选择tb.AT的值,并在WHERE子句中添加一个条件来过滤空值。

修改后的查询语句如下:

SELECT dates.datetime as Time, tb.AT as VALUE 
FROM dates 
LEFT JOIN (SELECT * FROM OS_AT WHERE OS_AT.StationNo = '1111') AS tb 
ON dates.datetime = datetime(tb.Time) 
WHERE COALESCE(tb.AT, '999') <> '999' 
ORDER BY dates.datetime
  1. 在JOIN操作中使用索引。

在LEFT JOIN操作中,可以考虑在OS_AT表上创建一个索引,以便加快查询速度。可以使用以下语句创建索引:

CREATE INDEX idx_OS_AT_datetime ON OS_AT (datetime);
  1. 在递归查询中使用LIMIT语句。

递归查询可以导致查询的执行时间较长,因此可以考虑在查询的末尾添加一个LIMIT语句,以限制查询结果的行数。例如,可以在查询的末尾添加以下语句:

LIMIT 1000; -- 可以根据需要调整行数限制

这将限制查询结果的行数,从而减少查询的执行时间。

【以下回答由 GPT 生成】

在这个问题中,主要的性能瓶颈是查询中的递归表达式和LEFT JOIN操作。以下是一些优化建议来提高查询速度:

  1. 避免递归表达式:使用递归表达式可能会导致查询性能下降,尤其是对于大量数据的情况。在这种情况下,可以考虑使用其他技术来生成连续的日期时间序列,例如在应用层代码中生成一个日期时间范围,并将其作为输入参数传递给查询。

  2. 添加索引:确保OS_AT表和dates.datetime列都有适当的索引,以提高查询性能。在这种情况下,你可以为OS_AT表的StationNo列添加一个索引。

  3. 尽量减少查询返回的数据量:在查询中,使用SELECT *会返回所有列的值,但实际上你只需要一些特定的列。指定需要的列可以减少查询的数据量,并提高查询性能。

  4. 考虑缓存数据:如果温度数据变化不频繁,你可以考虑将一天内每分钟的温度数据缓存在应用程序中,在需要时直接从缓存中获取数据,而不是每次都进行数据库查询。

  5. 合理使用数据库缓存:根据你的情况,考虑增加数据库的缓存大小,以便更多的数据可以存储在内存中,从而减少磁盘IO的访问,提高查询性能。

  6. 使用合适的硬件和数据库配置:确保你的数据库服务器具有足够的内存和计算资源来处理查询。此外,还可以优化数据库的配置参数,例如调整查询缓冲区大小或并发连接数等。

以下是优化后的代码示例:

SELECT dates.datetime as Time, COALESCE(tb.AT, '999') as VALUE
FROM (
  SELECT datetime('2023-08-24 00:00:00') as datetime
  UNION ALL
  SELECT datetime(datetime, '+1 minute') 
  FROM (SELECT datetime('2023-08-24 00:00:00') as datetime UNION ALL 
        SELECT datetime('2023-08-24 00:01:00') as datetime UNION ALL
        SELECT datetime('2023-08-24 00:02:00') as datetime) as initial_data
  WHERE datetime < datetime('2023-08-25 00:00:00')
) AS dates
LEFT JOIN (SELECT Time, AT FROM OS_AT WHERE StationNo = '1111') AS tb
ON dates.datetime = tb.Time
ORDER BY dates.datetime;

请注意,以上代码示例中的时间范围只包含了三分钟的数据。你需要将该范围扩展到一天的范围。此外,确保OS_AT.Time列和dates.datetime列具有相同的数据类型和格式以进行连接。

如果以上优化建议无法满足你的需求,请告知,我会考虑其他解决方案。



【相关推荐】



如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^