Postgres的级数生成函数generate_series应用
引用:http://postgres.cn/docs/12/functions-srf.html
函数文档
函数 参数类型 返回类型 描述
generate_series(start, stop) int、bigint或者numeric setof int、setof bigint或者setof numeric(与参数类型相同) 产生一系列值,从start到stop,步长为 1
generate_series(start, stop, step) int、bigint或者numeric setof int、setof bigint或者setof numeric(与参数类型相同) 产生一系列值,从start到stop,步长为step
generate_series(start, stop, step interval) timestamp或timestamp with time zone setof timestamp或setof timestamp with time zone(和参数类型相同) 产生一系列值,从start到stop,步长为step
当step为正时,如果start大于stop则返回零行。相反,当step为负时,如果start小于stop则返回零行。对于NULL输入也会返回零行。step为零是一个错误。
案例
SELECT * FROM generate_series(2,4);
generate_series
-----------------
2
3
4
(3 rows)
SELECT * FROM generate_series(5,1,-2);
generate_series
-----------------
5
3
1
(3 rows)
SELECT * FROM generate_series(4,3);
generate_series
-----------------
(0 rows)
SELECT generate_series(1.1, 4, 1.3);
generate_series
-----------------
1.1
2.4
3.7
(3 rows)
-- 这个例子依赖于日期+整数操作符
SELECT current_date + s.a AS dates FROM generate_series(0,14,7) AS s(a);
dates
------------
2004-02-05
2004-02-12
2004-02-19
(3 rows)
SELECT * FROM generate_series('2008-03-01 00:00'::timestamp, '2008-03-04 12:00', '10 hours');
generate_series
---------------------
2008-03-01 00:00:00
2008-03-01 10:00:00
2008-03-01 20:00:00
2008-03-02 06:00:00
2008-03-02 16:00:00
2008-03-03 02:00:00
2008-03-03 12:00:00
2008-03-03 22:00:00
2008-03-04 08:00:00
(9 rows)
应用
上个月做了个大屏项目,系统涉及到很多资源各个层级维度的统计,资源存在于很多不同的数据库或者文件,最低计算粒度是按日统计前一天的数据。
跑任务每日任务和图表查询需求拆分实现。项目实现了在线配置数据源和 SQL 任务,支持动态配置更新的数据源/任务调度/任务SQL。(调度周期通过 cron 表达式定义)。
除了mysql/pg/oracle库,项目还有很多 hive 任务,背后基于 MapReduce 实现调度离线文档分析,由于 hive 任务都比较重,执行时间比较长,并发也是有限制的。
一两百个 hive 任务,为避开集中调度高峰,现打散任务调度时间,每隔5分钟执行一个新任务。
今天的主角,Postgres 的序列数据生成函数generate_series(),就可以帮到忙。
# SELECT 60 * 24 = 1440 分钟
SELECT ('0 ' || (generate_series(0, 1440, 5) % 60) || ' ' || (generate_series(0, 1440, 5) / 60) || ' * * ?') AS cron
0 0 0 * * ?
0 5 0 * * ?
0 10 0 * * ?
0 15 0 * * ?
……
0 55 23 * * ?
0 0 24 * * ? # 此时间不存在,需要剔除
附录
cron 表达式
用来定义定时任务的执行策略,表达式字符串由 6 个空格分为 7 个域,每一个域代表一个时间含义。
[秒] [分] [时] [日] [月] [周] [年]
0 */1 * * * ? # 每隔1分钟执行一次
0 0 22 * * ? # 每天22点执行一次
0 0 1 1 * ? # 每月1号凌晨1点执行一次
0 0 23 L * ? # 每月最后一天23点执行一次
0 0 3 ? * L # 每周周六凌晨3点实行一次
0 24,30 * * * ? # 在24分、30分执行一次