SQL: Fast Summen Query (Postgres)
-
10-10-2019 - |
Frage
Ich bin auf der Suche Kumulative Frequenzdaten aus unserer Datenbank zu erhalten. Ich habe eine einfache temporäre Tabelle mit all einzigartigen Status-Update zählt geschaffen, dass wir gesehen haben, und die Anzahl der Nutzer, die diese Menge an Status-Updates haben.
Table "pg_temp_4.statuses_count_tmp"
Column | Type | Modifiers
----------------+---------+-----------
statuses_count | integer |
frequency | bigint |
Indexes:
"statuses_count_idx" UNIQUE, btree (statuses_count)
Meine aktuelle Abfrage ist:
select statuses_count, frequency/(select * from total_statuses)::float, (select sum(frequency)/(select * from total_statuses)::float AS percentage from statuses_count_tmp WHERE statuses_count <= SCT.statuses_count) AS cumulative_percent FROM statuses_count_tmp AS SCT ORDER BY statuses_count DESC;
Aber das dauert eine ganze Weile, und die Anzahl der Anfragen wächst ziemlich schnell. So mit den ~ 50.000 Zeilen Ich habe, ich suche bei 50k faktorielles Zeilen gelesen werden. Ich hoffe, Theres eine bessere Lösung, dass ich nicht durch von noch hier sitzen die Abfrage grind beobachten weg.
Hoffnung, etwas zu bekommen:
0 0.26975161 0.26975161
1 0.15306534 0.42281695
2 0.05513516 0.47795211
3 0.03050646 0.50845857
4 0.02064444 0.52910301
Lösung
Sollte mit Windowing-Funktionen auflösbar sein, vorausgesetzt, Sie PostgreSQL 8.4 oder höher. Ich vermute, dass total_statuses
eine Ansicht oder temporäre Tabelle entlang der Linien von select sum(frequency) from statuses_count_tmp
? Ich schrieb es als hier CTE was machen sollte das Ergebnis nur einmal für die Dauer der Anweisung berechnen:
with total_statuses as (select sum(frequency) from statuses_count_tmp)
select statuses_count,
frequency / (select * from total_statuses) as frequency,
sum(frequency) over(order by statuses_count)
/ (select * from total_statuses) as cumulative_frequency
from statuses_count_tmp
Ohne 8.4 Fenster Funktionen die beste Wahl ist einfach die Daten zu verarbeiten iterativ:
create type cumulative_sum_type as ( statuses_count int, frequency numeric, cumulative_frequency numeric );
create or replace function cumulative_sum() returns setof cumulative_sum_type strict stable language plpgsql as $$
declare
running_total bigint := 0;
total bigint;
data_in record;
data_out cumulative_sum_type;
begin
select sum(frequency) into total from statuses_count_tmp;
for data_in in select statuses_count, frequency from statuses_count_tmp order by statuses_count
loop
data_out.statuses_count := data_in.statuses_count;
running_total := running_total + data_in.frequency;
data_out.frequency = data_in.frequency::numeric / total;
data_out.cumulative_frequency = running_total::numeric / total;
return next data_out;
end loop;
end;
$$;
select * from cumulative_sum();