PostgreSQL17random函数还可以这样用?
random函数应该是开发人员使用频率比较高的函数。如果你想要生成1到100的随机函数,你是否有过那么一瞬间,因为它复杂的使用方式而烦恼?PostgreSQL 17的random函数让这一切变得简单,有时正是由于这些小功能的优化,反而让使用者觉得这个数据库真的不错。
在早期的版本中,对于random函数,返回的是[0,1)之间的双精度值,但是在我们真的实际操作中又何时需要这样的一个双精度随机数?这样的场景的应该是比较少见吧,在真实的操作中经常是用该值作为中间值。这个对于研发人员来说也是一个痛点。下面我们来详细的看一下PostgreSQL17中对于random函数进行了哪些方面的优化。
功能介绍
在PostgreSQL17上我们先来看看random函数的定义。
postgres=# \df random
List of functions
Schema | Name | Result data type | Argument data types | Type
------------+--------+------------------+--------------------------+------
pg_catalog | random | double precision | | func
pg_catalog | random | bigint | min bigint, max bigint | func
pg_catalog | random | integer | min integer, max integer | func
pg_catalog | random | numeric | min numeric, max numeric | func
(4 rows)
在PostgreSQL17的补丁新增了3个可通过SQL调用的函数,用于生成指定范围内的均匀分布随机整数或任意精度数字。random函数的返回值在[min, max]的范围内,对于numeric类型,结果的小数位数为max (scale(min), scale(max))即小数点后的位数等于“min”或“max”在小数点后的位数,以位数较多者为准,因此它可以生成超大整数及任意精度小数
应用场景
在PG17之前的版本中,如何生成1到10之间的随机整数?常规操作使用如下的方式:
SELECT floor(random()*10+1) FROM generate_series(1,10);
floor
-------
9
7
3
1
6
8
9
8
5
5
(10 rows)
Time: 15.403 ms
在PG17中的使用方法,看起来更加的直观,使用也很便捷
postgres=# select random(1,10) FROM generate_series(1,10);
random
--------
2
7
9
1
10
9
7
9
2
2
(10 rows)
Time: 1.072 ms
假如我们需要生成小数位为2位精度的小数,在PG17之前的版本,常规操作使用如下的方式:
testdb=# SELECT round((random()*9+1)::numeric,2) FROM generate_series(1,10);
round
-------
7.23
1.38
8.82
5.80
7.69
3.07
7.07
8.27
2.98
8.43
(10 rows)
Time: 0.287 ms
在PG17中,现在只需要很贱的操作,如下:
postgres=# select random(1.0,10.00) FROM generate_series(1,10);
random
--------
3.94
9.55
6.74
9.77
6.93
1.83
3.48
3.52
9.82
2.87
(10 rows)
Time: 0.183 ms
通过对random函数的参数进行限制,就可以精确的保留两位小数。即使当输入的参数小数位不同时,函数也会自动取最大值。 另外我们也可以看到不论是返回整数还是小数,从执行耗时看,返回int类型,耗时从15.403 ms降到1.072 ms,返回numeric类型耗时从0.287 ms降到0.183 ms,综合看性能提升30%以上甚至更多,而且PG17中的random函数使用更加的简洁,可读性也很强。
四大技术优势
在PG17中对于random函数新特性,不仅仅在使用上让我们更加便捷,而且从技术上来说函数也有四大优势。
- 支持任意范围
- 要求满足
max ≥ min
条件,所有的边界值都可以使用 - 传统基于
random()
的SQL/PLpgSQL实现可能因max-min
差值过大导致整数溢出
- 要求满足
- 全区间均匀分布
- 传统实现如
((max-min)*random()+min)::int
会导致端点值出现的概率仅为中间值的50%,这个因为取整导致的
- 传统实现如
- 增强PRNG利用效率
- 突破原有双精度浮点数52位精度限制,PRNG(Pseudo-Random Number Generator,伪随机数生成器)是 PostgreSQL 中生成确定性数值序列的核心算法机制,
- 高效的生成随机数
- 替代传统需多次调用
random()
拼接数字字符串的低效方案 - 生成随机数值的耗时降低50%以上(本机测试,仅供参考)
- 替代传统需多次调用
总结
PostgreSQL17中random函数有两个参数来指定返回随机数的最小值和最大值,可以是int、bigint和numeric类型指定范围,这样既简单又直观明了。说到便捷性,就不得不提到国产数据库,希望能多多的吸收这些优秀的功能点,优化自身产品。
参考
https://www.postgresonline.com/journal/index.php?/archives/419-PG-17-new-random-functions.html#newrandom
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=e6341323a
https://www.postgresql.org/message-id/CAEZATCV89Vxuq93xQdmc0t-0Y2zeeNQTdsjbmV7dyFBPykbV4Q@mail.gmail.com
– / END / –
可以通过下面的方式联系我
如果这篇文章为你带来了灵感或启发,就请帮忙点赞、收藏、转发;如果文章中不严谨或者错漏之处,请及时评论指正。非常感谢!