2011-06-21 58 views
1

我店每週的場均得分在表中稱爲pref_moneyPostgreSQL的:運行於各行的查詢,並保存結果在它

# select * from pref_money limit 5; 
     id  | money | yw 
----------------+-------+--------- 
OK32378280203 | -27 | 2011-44 
OK274037315447 | -56 | 2011-44 
OK19644992852 |  8 | 2011-44 
OK21807961329 | 114 | 2011-44 
FB1845091917 | 774 | 2011-44 
(5 rows) 

和每個星期的我展示金牌獲獎者(S) :

screenshot

我覺得獎牌用戶數量運行:

# select count(id) from (
    select id, 
      row_number() over(partition by yw order by money desc) as ranking 
    from pref_money 
) x 
where x.ranking = 1 and id='OK260246921082'; 
count 
------- 
    3 
(1 row) 

而且查詢是相當昂貴:

# explain analyze select count(id) from (
    select id, 
      row_number() over(partition by yw order by money desc) as ranking 
    from pref_money 
) x 
where x.ranking = 1 and id='OK260246921082'; 
                   QUERY PLAN 
------------------------------------------------------------------------------------------------------------------------------------------- 
Aggregate (cost=18946.46..18946.47 rows=1 width=82) (actual time=2423.145..2423.145 rows=1 loops=1) 
    -> Subquery Scan x (cost=14829.44..18946.45 rows=3 width=82) (actual time=2400.004..2423.138 rows=3 loops=1) 
     Filter: ((x.ranking = 1) AND ((x.id)::text = 'OK260246921082'::text)) 
     -> WindowAgg (cost=14829.44..17182.02 rows=117629 width=26) (actual time=2289.079..2403.685 rows=116825 loops=1) 
       -> Sort (cost=14829.44..15123.51 rows=117629 width=26) (actual time=2289.069..2319.575 rows=116825 loops=1) 
        Sort Key: pref_money.yw, pref_money.money 
        Sort Method: external sort Disk: 4320kB 
        -> Seq Scan on pref_money (cost=0.00..2105.29 rows=117629 width=26) (actual time=0.006..22.566 rows=116825 loops=1) 
Total runtime: 2425.001 ms 
(9 rows) 

這就是爲什麼(因爲我的網站是在高峯時段掙扎,在pgbouncer日誌中顯示的50個查詢/秒),我想緩存該值並增加一列獎牌到另一個表 - 在pref_users

pref=> \d pref_users; 
       Table "public.pref_users" 
    Column |   Type    | Modifiers 
------------+-----------------------------+--------------- 
id   | character varying(32)  | not null 
first_name | character varying(32)  | 
last_name | character varying(32)  | 
female  | boolean      | 
avatar  | character varying(128)  | 
city  | character varying(32)  | 
lat  | real      | 
lng  | real      | 
login  | timestamp without time zone | default now() 
last_ip | inet      | 
medals  | smallint     | default 0 
logout  | timestamp without time zone | 
Indexes: 
    "pref_users_pkey" PRIMARY KEY, btree (id) 
Check constraints: 
    "pref_users_lat_check" CHECK ((-90)::double precision <= lat AND lat <= 90::double precision) 
    "pref_users_lng_check" CHECK ((-90)::double precision <= lng AND lng <= 90::double precision) 
    "pref_users_medals_check" CHECK (medals >= 0) 

我想創建一個cronjob來運行,每15分鐘更新所有的用戶該列在個pref_users表:

*/15  *  *  *  *  psql -a -f $HOME/bin/medals.sql 

正如你看到的,我已經得到了就地幾乎所有的東西。我的問題是我還沒有拿出SQL語句來更新獎牌列。

請幫忙嗎?

我在CentOS Linux 5.6/64位上使用PostgreSQL 8.4.8。

謝謝! Alex

回答

1

那麼,這不會產生用戶ID和獎牌數的結果?

create view user_medal_count as 
select id, count(*) as medals from (
    select id, 
      row_number() over(partition by yw order by money desc) as ranking 
    from pref_money 
) x 
where x.ranking = 1 
group by id 

所以你需要使用作爲源來更新您的用戶:

update pref_users 
set medals = user_medal_count.medals 
from user_medal_count 
where pref_users.id = user_medal_count.id 
     and (pref_users.medal_count is null 
      or pref_users.medal_count <> user_medal_count.medal_count) 

我希望得到你開始。

還有一些問題需要考慮。您可能想要定義用戶在哪一點獲得獎章 - 「當前周」的獎牌大概可能會發生變化,因此您可能希望將獎牌計數定義爲前幾周獎牌的計數,即時計算當前星期的獎章(這應該要求查看更少的數據),或者簡單地排除它。 (如果你什麼也沒做,那麼你可能會發現,如果用戶暫時獲得本週的獎牌,那麼他們的medal_count爲1,但如果稍後給予其他人,它永遠不會重置爲0。

相關問題