2011-01-12 19 views
1

私はデータベースから累積頻度データを取得したいと考えています。私が見たユニークな状態の更新回数とその状態量の更新を持つユーザーの数の単純な一時表を作成しました。SQL:高速累積頻度クエリ(postgres)

 Table "pg_temp_4.statuses_count_tmp" 
    Column  | Type | Modifiers 
----------------+---------+----------- 
statuses_count | integer | 
frequency  | bigint | 
Indexes: 
    "statuses_count_idx" UNIQUE, btree (statuses_count) 

私の現在のクエリは次のとおりです。

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; 

しかし、これにはかなり時間がかかり、クエリの数は非常に急速に成長します。だから私が持っている〜50,000行では、私は50k階乗の行を読むことを検討しています。ここに座って質問を見ると、私はtheresが私がまだ経験していないより良い解決策を望んでいる。このような何か得ることを望ん

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 

答えて

2

は、あなたは、PostgreSQL 8.4以降が想定して、ウィンドウ機能を持つ解けるであるべき。私はtotal_statusesselect sum(frequency) from statuses_count_tmpの行に沿ったビューまたは一時テーブルだと推測していますか?

:あなたの最善の策は、反復的にデータを処理するだけである8.4のウィンドウ関数がなければ

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 

:私はそれが文の間一度だけの結果を計算させるべきここCTEとしてそれを書きました

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(); 
+0

ああ、そのような運はありません。数日後に更新することを本当に望んでいませんが、一度更新すればこのソリューションを念頭に置いておきます。 – Peck

+0

+1ほとんど同じ答えを書いています。 –

+0

@Peck:plpgsql関数を使用して、8.3で動作するはずのソリューションを追加しました。 – araqnid