在 rails 上使用 postgresql 和 ruby 优化时间序列数据检索的数据库查询
Optimize database query for time series data retrieving using postgresql and ruby on rails
大家好,我正在开发一个有趣的实时应用程序。
该应用程序是因为 follows.I 有一个 meter
模型和 meter_info
模型
calss Meter
has_many :meter_infos
# filed: id
end
class MeterInfo
belongs_to :meter
# field: meter_id, voltage
end
每两分钟就有一个新数据被保存到 meter_info
table.So 你可以想象那里有一个巨大的数据集。
现在我要做的是在1天内以10分钟为间隔,一次准确地找出10条meters
一条电压记录。
所以结果会是这样的
id created_at meter_id voltage
2001 2017-10-19 15:40:00 2 100
2001 2017-10-19 15:45:00 1 100
2001 2017-10-19 15:39:00 3 100
2001 2017-10-19 15:48:00 4 100
2001 2017-10-19 15:38:00 5 100
2001 2017-10-19 15:42:00 6 100
...
...
我尝试了几次查询,但由于查找记录花费了太多时间,请求超时。这是我为
尝试过的
(('2017-07-02 00:00:00').to_datetime.to_i ..
('2017-07-02 23:59:59').to_datetime.to_i).step(10.minutes) do |date|
query = "SELECT created_at, meter_id, voltage
FROM meter_infos
WHERE created_at between '#{Time.at(date).utc}' and
'#{Time.at(date).utc + 10.minutes}'
AND meter_id in (1,2,3,4,5)
ORDER BY id desc limit 1"
voltages = ActiveRecord::Base.connection.execute(query)
end
即使在开发环境中也会超时。
然后我尝试使用 Postgresql
的 generated_series
,如下所示
query= "SELECT meter_id,voltage, count(id) as ids
, GENERATE_SERIES( timestamp without time zone '2017-10-19',
timestamp without time zone '2017-10-19',
'10 min') as time_range
from meter_infos
where meter_infos.created_at between '2017-10-19 00:00:01'::timestamp and '2017-10-19 23:59:59'::timestamp
and meter_infos.meter_id in (1,2,3,4,5)
GROUP BY meter_id, voltage
ORDER BY meter_id ASC limit 1"
sbps_plot = ActiveRecord::Base.connection.execute(query)
哪个更快但给我错误的数据。
我正在使用 Ruby on Rails
和 Postgresql
。
有人可以帮我编写更快的查询来找出时间数据,或者建议我处理时间序列数据分析的任何程序。
提前致谢。
您每两分钟就有一次记录,但您想从十分钟的间隔获取样本记录。这是我建议的解决方案:
您可以对 created_at
时间戳的纪元时间取模 600(十分钟以秒为单位)。然后将其与某个 'tolerance' 值(例如 119 秒或更短)进行比较,以防您的记录的时间戳未与完美的十分钟间隔对齐。想一想在一天中每隔 10 分钟后的 2 分钟 window 内检索带有 created_at
的第一条记录。
例如,
MeterInfo
.where(
meter_id: [1, 2, 3, 4, 5],
created_at: your_date.beginning_of_day..your_date.end_of_day
)
.where("(cast(extract(epoch from created_at) as integer) % 600) < 119")
试一试,看看它是否适合你。
大家好,我正在开发一个有趣的实时应用程序。
该应用程序是因为 follows.I 有一个 meter
模型和 meter_info
模型
calss Meter
has_many :meter_infos
# filed: id
end
class MeterInfo
belongs_to :meter
# field: meter_id, voltage
end
每两分钟就有一个新数据被保存到 meter_info
table.So 你可以想象那里有一个巨大的数据集。
现在我要做的是在1天内以10分钟为间隔,一次准确地找出10条meters
一条电压记录。
所以结果会是这样的
id created_at meter_id voltage
2001 2017-10-19 15:40:00 2 100
2001 2017-10-19 15:45:00 1 100
2001 2017-10-19 15:39:00 3 100
2001 2017-10-19 15:48:00 4 100
2001 2017-10-19 15:38:00 5 100
2001 2017-10-19 15:42:00 6 100
...
...
我尝试了几次查询,但由于查找记录花费了太多时间,请求超时。这是我为
尝试过的(('2017-07-02 00:00:00').to_datetime.to_i ..
('2017-07-02 23:59:59').to_datetime.to_i).step(10.minutes) do |date|
query = "SELECT created_at, meter_id, voltage
FROM meter_infos
WHERE created_at between '#{Time.at(date).utc}' and
'#{Time.at(date).utc + 10.minutes}'
AND meter_id in (1,2,3,4,5)
ORDER BY id desc limit 1"
voltages = ActiveRecord::Base.connection.execute(query)
end
即使在开发环境中也会超时。
然后我尝试使用 Postgresql
的 generated_series
,如下所示
query= "SELECT meter_id,voltage, count(id) as ids
, GENERATE_SERIES( timestamp without time zone '2017-10-19',
timestamp without time zone '2017-10-19',
'10 min') as time_range
from meter_infos
where meter_infos.created_at between '2017-10-19 00:00:01'::timestamp and '2017-10-19 23:59:59'::timestamp
and meter_infos.meter_id in (1,2,3,4,5)
GROUP BY meter_id, voltage
ORDER BY meter_id ASC limit 1"
sbps_plot = ActiveRecord::Base.connection.execute(query)
哪个更快但给我错误的数据。
我正在使用 Ruby on Rails
和 Postgresql
。
有人可以帮我编写更快的查询来找出时间数据,或者建议我处理时间序列数据分析的任何程序。
提前致谢。
您每两分钟就有一次记录,但您想从十分钟的间隔获取样本记录。这是我建议的解决方案:
您可以对 created_at
时间戳的纪元时间取模 600(十分钟以秒为单位)。然后将其与某个 'tolerance' 值(例如 119 秒或更短)进行比较,以防您的记录的时间戳未与完美的十分钟间隔对齐。想一想在一天中每隔 10 分钟后的 2 分钟 window 内检索带有 created_at
的第一条记录。
例如,
MeterInfo
.where(
meter_id: [1, 2, 3, 4, 5],
created_at: your_date.beginning_of_day..your_date.end_of_day
)
.where("(cast(extract(epoch from created_at) as integer) % 600) < 119")
试一试,看看它是否适合你。