Ich glaube, ich sehe, was Sie zu tun versuchen, und ich frage mich, ob interval '5 minutes'
mit would't zügig besser und einfachen Ansatz folgen:
with times as ( -- find the first date in the dataset, up to today
select
date_trunc ('minutes', min("timestamp")) -
mod (extract ('minutes' from min("timestamp"))::int, 5) * interval '1 minute' as bt,
date_trunc ('minutes', current_timestamp) -
mod (extract ('minutes' from current_timestamp)::int, 5) * interval '1 minute' as et
from hst_energy_d
where
idinstrum = 4 and
id_device = 122
), -- generate every possible range between these dates
ranges as (
select
generate_series(bt, et, interval '5 minutes') as range_start
from times
), -- normalize your data to which 5-minut interval it belongs to
rounded_hst as (
select
date_trunc ('minutes', "timestamp") -
mod (extract ('minutes' from "timestamp")::int, 5) * interval '1 minute' as round_time,
*
from hst_energy_d
where
idinstrum = 4 and
id_device = 122
)
select
r.range_start, r.range_start + interval '5 minutes' as range_end,
avg (hd."Al1")
from
ranges r
left join rounded_hst hd on
r.range_start = hd.round_time
group by
r.range_start
order by
r.range_start
By the way, das anspruchsvolle Auge kann frage mich warum mit dem CTE rounded_hst
stören und warum nicht einfach ein "between" in der Join verwenden. Nach allem, was ich getestet und beobachtet habe, explodiert die Datenbank alle Möglichkeiten und testet dann die Zwischenbedingung in einer where-Klausel - einem gefilterten Kartesischen. Für diese vielen Intervalle ist das garantiert ein Mörder.
Das Abschneiden jeder Daten auf die nächsten fünf Minuten ermöglicht eine Standard-SQL-Verknüpfung. Ich ermutige Sie beide zu testen, und ich denke, Sie werden sehen, was ich meine.
- EDIT 2016.11.17 -
Lösung von OP, die die Zeiten sind Zahlen berücksichtigt, nicht die Daten:
with times as ( -- find the first date in the dataset, up to today
select
date_trunc('minutes', to_timestamp(min("timestamp"))::timestamp) -
mod(extract ('minutes' from to_timestamp(min("timestamp"))::timestamp)::int, 5) * interval '1 minute' as bt,
date_trunc('minutes', current_timestamp::timestamp) -
mod(extract ('minutes' from (current_timestamp)::timestamp)::int, 5) * interval '1 minute' as et
from hst_energy_d
where
idinstrum = 4 and
id_device = 122
), -- generate every possible range between these dates
ranges as (
select
generate_series(bt, et, interval '5 minutes') as range_start
from times
), -- normalize your data to which 5-minute interval it belongs to
rounded_hst as (
select
date_trunc ('minutes', to_timestamp("timestamp")::timestamp)::timestamp -
mod (extract ('minutes' from (to_timestamp("timestamp")::timestamp))::int, 5) * interval '1 minute' as round_time,
*
from hst_energy_d
where
idinstrum = 4 and
id_device = 122
)
select
extract('epoch' from r.range_start)::bigint, extract('epoch' from r.range_start + interval '5 minutes')::bigint as range_end,
avg (hd."Al1")
from
ranges r
left join rounded_hst hd on
r.range_start = hd.round_time
group by
r.range_start
order by
r.range_start;
was für eine saubere Abfrage! Leider ist "timestamp" ein 'BIGINT' anstelle eines echten' timestamp', daher meine Mathe mit Zahlen anstelle von Zeitstempeln. – Bertuz
Ich habe Ihren Code angepasst, um mit bigint zu arbeiten, aber ich bin mir nicht sicher, ob das noch funktionieren könnte Nutzen Sie einen leichteren SQL. [gist auf die neue SQL] (https://gist.github.com/bertuz/5544663474b8a0850dcede03d1903a02) können Sie bitte einen Blick und geben Sie mir ein Feedback? Plus: Sie haben darüber gesprochen, dass Postgres besser mit Ihrer Lösung funktioniert: Wie haben Sie das analysiert? Mit 'EXPLAIN'? Hier ist der [Abfrageplan] (https://gist.github.com/bertuz/5f06ab81cde3e78231c94c3a76ad20f8) meine Abfrage führt. Führt es tatsächlich zwei Scans auf hst_energy_d durch? Das ist eine Menge*! Danke – Bertuz
Gut, 'EXPLAIN' spricht für sich selbst: Ihre Lösungen kosten' 48.47', im Gegensatz zu meinen Kosten '247.17' – Bertuz