PostgreSQL:为每一行运行查询并将结果保存在其中

标签 postgresql cron

我将每周游戏得分存储在名为 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)

我会为每周的获胜者展示奖牌:

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 个查询/秒)我想缓存该值并添加一列 medals 到另一个表 - 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

如您所见,我几乎已准备就绪。我的问题是我还没有想出用于更新 medals 列的 SQL 语句。

有什么帮助吗?

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

谢谢! 亚历克斯

最佳答案

那么,这不会产生用户 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)。

关于PostgreSQL:为每一行运行查询并将结果保存在其中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6426272/

相关文章:

sql - 在尝试更改之前如何检查数据库中是否使用了行?

postgresql - 如何在所有表中搜索特定值(PostgreSQL)?

php - 1 小时后删除临时 View

postgresql - 我如何计算 Postgres 9.6 中唯一对的数量?

python - Django读取JSON文件

linux - AWS Linux crontab 作业不执行脚本

java - 如何重新启动服务器关闭后动态创建的 Quartz 作业

php - 如何使用 phpseclib 设置 Cron Job?

php exec() 未通过 cron 作业运行

python - 如何将包含外键模型关系的 Django 模型导出到组合文本文件中