我将每周游戏分数存储在一个名为 pref_money 的表格中:
# 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)
对于每周的获奖者,我会展示奖章:
我通过运行来找到用户的奖牌数量:
# 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)
我想创建一个每15分钟运行一次的cronjob,以便为 pref_users 表中的所有用户更新该列:
*/15 * * * * psql -a -f $HOME/bin/medals.sql
如你所见,我几乎掌握了一切。我的问题是我还没有提出用于更新奖牌列的SQL语句。
请帮忙吗?
我正在使用PostgreSQL 8.4.8和CentOS Linux 5.6 / 64位。
谢谢! 亚历
答案 0 :(得分: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)
我希望能让你开始。
还有一些问题需要考虑。您可能想要定义用户获得奖牌的时间点 - “当前周”的奖牌可能会发生变化,因此您可能希望将奖牌数量定义为稳定计数前几周的奖牌,即时计算当前一周的奖牌(这应该要求查看更少的数据),或者只是排除它。 (如果你没有做任何事情,那么你可能会发现如果用户暂时获得当前一周的奖牌,他们会获得1的medal_count,但如果稍后将其重新授予其他人,则永远不会重置为0。