分享人:Digoal 阿里云资深数据库专家
正文:pg在高级SQL这块的一些的功能
一、基本功能
1)物化视图
首先讲物化视图的功能,普通视图是我们create一个view,后面是一堆的query,普通视图解决写的复杂的SQL,人为查询时会发现太长也记不住,可以创建一个视图,基于视图去做查询。通常视图会用在两类场景,一类是dba,为了简化日常的工作,把常用的SQL创建成视图,后面去查视图就好了。比如说Oracle数据库有很多内置视图,内置视图用来简化管理的人员操作。还有一个类场景是为了隐藏一些数据,比如一些应用、财务软件,公司的财务数据是比较敏感的,意味着一张每个字段的数据对所有人都是可见的,这时可以通过视图去做一些隐藏。比如创建一个视图,只有某一些人能查这些字段,另外一些人就查不了这些字段。
普通视图有一个比较大的问题,后面的query是查询的时候来做数据过滤,也就是说如果你的这个query涉及到一些运算的话。
举个例子,每个小时的做聚合,用一个普通视图,每次来查时后台都要做每个小时计算聚合,如果重复查同一个小时的数据,它就会重复的计算很多次,第一浪费资源,第二响应延迟会比较高,一个请求几十要几十秒才返回。可以增量的刷新物化视图,refresh materialized view,刷新时会重复计算后台的query,把结果算一遍后刷新到物化视图里,刷新后查到的结果就是刷新后的结果,这个就是物化视图,是pg的一个高级功能。
2)实时数据清洗、转换
第二个功能是实时的数据清洗,实时数据清洗通常出现在什么场景呢?物联网的场景,比如客户端上传包含经度和纬度的数据,考虑到通用性,就把精度和纬度分成两个字段,存numeric就存成了经度、纬度的number,在数据库里希望把它合并到geometry里去,我们可以通过实时清洗的方法,基于终端上报的数据,把它上传的数据转,终端往这张表写入,在nt表上建立一个规则,当这个数据写进来的时候,把它转换insert到另外一张表geometry,用ST_MakePoint函数,把两个numeric合并起来,合并起来之后就转geometry字段,写入到目标表。用户数据写进来后直接就清洗掉。
这是通过规则实现数据的实时清洗和转换。再举一个例子,客户端上传一个非结构化数据jsonb的格式, jsonb可以兼容更多的客户端,当服务端和客户端是解耦的情况下,在修改客户端时服务端不用修改去解耦。传承json对数据分析和查询来说比较痛苦,有一些必选字段c1,c2,c3,希望数据写进来时做一次转换,把里面的c1、c2、c3三个字段转换出来,基于原表建立一个规则,数据写进来的时候,我把这个jsonb里面的c1、c2、c3提取出来存到这个表里,原始的jsonb保留下来。比如do instead插入到目标表,目标表里可以加一个c4的字段,把字段的内容填充到c4的字段去,就有了c1c2c3的解析字段内容,ok,这也是数据的实施清洗和转换的例子。
3)数据采样
这是数据采样的功能。数据采样是说在生产库里有一些table,举个例子,我需要提取一些测试数据,提取一些采样的数据,这就会涉及到数据库数据采样的方法,在pg里也支持采样的语法,在表里指定table sample,采样查询这张表,数据库内置了两种采样方法:一个是基于行的采样方法,另一个是基于数据块的采样方法,如果指定采样1%的记录,这张表有1万条1%就是采100条。基于行的采样方法会扫描整张表,它会做一次全面扫描,随机拿到1%的记录。基于块级的随机采样方法,如果这张表有1000个数据块,采样1%就是十个数据块,这时只需采样十个数据块。
块级随机采样力度会更粗,一旦数据块被采样到,这数据块里面的所有的记录都会被拿走,所以采样的离散度没有基于行的离散度高。
数据采样除了用在提取测试数据,还会用在采样评估,比如我想知道这个表里面江西省或者浙江省的记录数有多少?有一种方法是估算法,使用会计采样,采样1/10的数据看浙江省有多少?比如1/10里面有100条是浙江省,采纳1/10也就是再乘十就等于这整个表里有的浙江省的数据,这就是估算方法。数据采样的应用场景还有生成统计信息等。
4)数据加密
数据加密的功能在核心业务场景中会用到,比如财务系统里的薪资就要存的成加密的,一旦数据库被侵入,员工的薪资信息可能就会泄露了,其它的核心的场景也都有类似的需求。我们可以选择好多种加密的手段,比如应用端加密,加解密都在应用端,数据库里存的都是加密后的,这种方法数据库本身的安全性就更高了,因为数据库被入侵后也拿不到原始数据,加解密都在应用端完成,而且是不可逆的加密。
5)字段加密
还有一种方法是在数据库端存进去的时候使用加密函数做转换,就是把铭文的值转换成加密的值,加密的动作也可以在数据库端完成。在数据客户端完成加密,pgcrypto插件可以来完成加密的动作,它支持对称加密、非对称加密,混淆加密等,根据不同的需求选择不同的加密函数,加密密钥可以用客户端保管,加密的时候上传sort加密密钥去做加密,解密时把它提取走去解密,提取到后端解密也是ok的。
6)数据脱敏
数据脱敏跟加密有点类似,使用手段可能不太一样,比如存了一些手机号码、地址等,希望把一些内容替换掉,或者加一些随机的干扰内容进去,我们有类似的这种方法。
举个数据脱敏的例子,写进去的时候用replace的函数替换,把查出来的数据的加了星号的,就是看不到原始的数据,采样测试环境时,不希望看到原始数据,就把敏感信息给脱敏掉,也是一类需求,就是说取头取尾,中间用星号代替的方法,这种脱敏是不可逆的。
7)数据去重
pg支持窗口函数,通常去重用窗口函数。重复数据有很多种场景,比如多列重复、行重复、多列混合重复,多列混合重复的,比如ab两个字段, a
=1,b=2,那么一条是a=2,b=1,这种情况正常来说是不重复的,但有一些业务有去重的需求,a和b集合是重复的,就认为它是重复的。
针对这四类场景,这里都举了去重的例子,去重的SQL都已经写好了,第一种方法是聚合。用not in,比如把max id取出来,保留id的最大值,其它的都删掉。
另外一种是窗口查询,当我select table时,可以指定row_number,当row_number不等于1的时候,意味着c1字段有重复,id是什么无所谓, id落在low number不等于1的记录时说明重复了,我们要保留id最小的那个。
存储过程使用排序加游标的方法。select这张table,按c1跟id做排序,当我要保留的是id里面c1最大的,3就是当c1字段的内容出现翻转,它在临界点的时候,说明这条记录是要删掉的。
8)去重最常用SQL
去重最常用的SQL是low_number,如果c1字段有重复保留ts字段最大的,也是最近的时间戳最大的记录。
9)多字段范围检索加速
举个例子比如有一家企业的业务遍布在中国的很多城市,希望在北上广北上广建三个机房,希望广州用户走广州的线路去访问,当用户出差到北京了,他能就近访问北京的服务,这时候要用到智能解析的路由,当他的手机接入端根据接入端的ip地址的范围去判断,映射到北京地址段的话,就去访问北京。用户登录的时候要查询地址列表,开始的ip和结束的ip有一个范围,不同范围对应不同地区,我们查询where用户ip大于开始地址and用户ip小于结束地址。普通的dba的优化手段是创建一个联合索引,开始ip和结束ip的两个字段的联合索引,它能够命中开始字段,因为开始字段也是一个范围查询,所以过滤结束ip范围的时候,有大量的记录通过索引扫描出来是不要的,也就是索引没有帮你精准的过滤你要的记录,所以一个八核的服务器的话去处理这种请求, qps也只能达三千多。
这里应用了pg的range索引,在pg里有专门的范围类型,可以把数据存成范围类型、表达式索引两个字段,可以转换成范围类型再去建索引。
举个例子,这是ip地址,这个是table,把地址的数据导入到数据库里面,建立两个字段的联合索引, qps的达到三千多。用范围索引能够达到八万多,这就是典型的用range加空间索引解决多个字段范围检索的加速。如果你有三个字段的范围检索,就可以用cube 类型。
10)VPD(RLS)
我有一张表要做saas类的业务,一家erp的企业会向多个中小企业提供服务,每一个中小企业在数据库里都对应一份数据,中小企业登陆的时候不应该看到其它企业的数据,但是在应用里面用的是同一张表,就是不同企业的数据是存在同样的表里,这是一种设计方法。
如果要服务1000万家企业,就会有1000张表,如果大家不共用表,要去服务这1000万家企业要创就建1000×1000万张,就是100亿张表。
所以当a企业登录的时候,访问这张表时,不能访问到其他企业的更新数据、删除数据、插入数据,都不能影响其它企业的内容。a企业有对应的企业id,当你写入数据的时候,一定只会写入这个企业id的数据,这是在应用端做的控制,但是又不够严谨,一旦企业系统被攻击或者有一些漏洞,就会导致这个企业会影响其它企业。
我们在数据库里有一种安全控制方法叫行级安全,针对不同的user去控制在同一张表里查询、删除、插入更新的记录是哪一些,符合条件他才能去做。
就这里有三个角色r1、r2、r3,创建一个测试表,里面有三条记录,其中一个字段叫r,也就是用来标记这个角色的字段。比如说企业有id,我把这张表的权限赋予所有人都能做增删改查,接下来创建了一个叫with check的策略,就是他们check这个r等于current user, insert的时候要检查r字段的值是不是等于current user,current user就是登录数据库的用户,但是这个规则是disable的,这时去插入会发现当前角色r1、r2都能插进去,因为当前策略是disable,接着把策略enable,再来插入字段的value是r2的话就不让你插了,因为这里check必须要等于当前user才可以,必须要当前r的name的字段的value必须要等于current user,所以插r1,字段内容是r1等于刚当前登录的user name的就可以插入。
二、语法介绍
1)WITH ORDINALITY
在pg里函数是可以返回多条记录的,这一个函数返回记录唯一的number,如果想知道就在函数调用接口后面加一个WITH ORDINALITY,返回的value重新定义一下,比如它返回的是v,这个i就是number,比如这是第一条,这是第二条,这第三条,这是第四条。
比如一个table里面存了多个多值类型字段的话,我想知道这个多值类型字段的一一对应关系,我们就可以用ordinality去打印多直列的解析后的行号,去把它联合起来,这是一种方法比较笨的方法。实际上在数据库内部,已经自动做了内部对齐,将来如果要做特殊应用的时候就可以用这个方法,可以打印出来function的每一条记录的行号。
2)LATERAL
lateral语法是什么呢?literary语法就是在这个子查询里面去关联外面table,我们就可以用到lateral,把lateral放在子查询的前面,在子查询里就可以关联比子查询出现的更早的table或者子句,比如select * from foo逗号,(select * from bar where bar.id=foo.bar_id)如果不带lateral,是不能直接关联外面子句或者table的,这就是lateral的用法。
3)GROUPING SETS, CUBE and ROLLUP , grouping
如果想针对用户表的属性维度做多种透视,比如我想省份加行业的透视、行业加收入范围的透视、性别加什么的透视,因为group维度不一样,每一个group维度都得做一次query,都得做一次表的扫描。比如要查看100个维度,要扫描表100次,有了grouping sets、cube rollup语法之后,我们可以直接在一条SQL里面group by多个维度,好处是不需要扫描那么多次table,整体的性能会更高,整体的性能会更高,同时SQL会更简单,不用写那100条了,只需写一条搞定。
举个例子,比如select brand,size,sum(sales) from items_sold group by groupingsets (brand),(size),在这条SQL里面group by了三次,一次是group by id,一次是group by size,还有一次是group,就是那个空,它的返回结果就是这个样。我们可以一次group by多个东西。
还有一种叫rollup,比如写了e1、e2、e3等,它是逐级收敛的,grouping sets,第一个是e1、e2、e3、e4、e5、e6等,第二个e1e2e3e4等,然后是e1,再加上总的,它是逐级收敛,它每一个都会group by到。
还有一种是cube,cube就是排列组合,有abc、ab、ac、bc等组合,还有一个总的没有group by,没有分组就整个打包到一起,这个就是cube。
它支持内部分组,比如带了括号的ab就是一个组,它不会再拆了,就是abcd、abc等,它把bc当成一个组来看待,如果你带了括号它会当成一个组来看待。
它排列组合的时候把ab、 cd当成一个组。
它也可以混合用,就是group by a逗号,每次都会带上a,cube是排列组合, bc或者ab,grouping sets也是同样的道理。
如果把所有的group bye都输出到一次结果的话,那这条记录属于哪一个group呢?是哪几个字段的group产生的呢?在这里就会有一个grouping的语法,放在select结果里面,group里面带上make model,是我们group by后面选择的字段,当group bye里面包含了指定的make model字段,比特位上面就会置为零,包含它就置为零,不包含就置。
make就是有,model就是没有的,你像这个,对吧?它是基于make来做,3代表11,11是两个都没有,零是代表两个都有。
通过grouping记录就知道是来自哪个分组?来自哪个分组的?所以grouping sizes适合多个字段的组合透视,可以在一个query里面完成大量的多个维度的运算,减少数据的扫描次数,提升查询的一个效率。
三、窗口
1)窗口和帧
窗口是我们要指定的一个window,指的是计算的数据区间。比如求一个sum字段的内容,然后over一个window,window里面在字段相同的所有记录,某一个字段相同的所有记录就叫一个窗口,有多少窗口取决于有多少唯一值,比如有十个唯一值,总共有1000万条记录。总共有十个唯一值就有十个窗口,每个窗口有多少条记录取决于value窗口有多少条记录。
举个例子,我们做一个滑窗的分析,在同一个窗口的不同的位置,有一个轨迹数据、经纬度的点、时间、每一笔订单的id对应一个轨迹、很多订单,订单里面每一个点相近的上报时间间隔是一样的。假如五秒钟上报一次,每一个点的最近30秒的平均速度或者平均移动的范围是什么样的,就用帧来算,做完时间排序后,每一条记录的前五条和后五条,加上自己的总共11条记录来做平均值,这个就叫帧。每一条记录帧的内容都是不一样的,因为它是移动的。
这个非常的重要,窗口和帧的概念理解后,在数据库里用SQL就可以解决很多业务问题。如果不理解这两个概念,把数据全部放到应用,在应用里写程序去算,效率就非常低。
2)窗口、帧查询
我想知道每一条记录附近十条,包括自己就11条记录的平均值,就是前面五条,后面五条,你这条记录的前面五条和后面五条算一个平均值。
我想知道每一天比前一天新增uv,还有最近七天的新增uv,我们用到了数据库的扩展包,今天的数据减去昨天的数据,就是新增的uv,最近七天新增的uv是拿前六条加当前的总共七条。这七条的window作为窗口,每一天的最近七天,比如今天是礼拜五,最近七天就是上个礼拜五到今天,它是滑动。通过窗口查询帧的范围限定,就能够来查滑动窗口,就可以支持滑动窗口。
3)找到数据关键点-高潮、尿点、低谷
还有一个窗口能查出数据的骤变。到底哪个时间点的数据是关键数据,一个曲线一直都是同一个斜率运行的话。下面这条线一直往一个方向走,发现这里好像没有关键点,因为运动速率、斜率是一样的。上面这条线就比较搞笑,他突然上去,然后比较平缓,轻微的抖动一下,然后又平缓又轻微抖动一下,它到一个点后急剧下降掉到谷底,然后在谷底点又上来了,又上的很高,这条线的关键点在哪呢?它的关键点就在斜率的骤变点,这些骤变点是它的关键点。
这条曲线也是一样,有小骤变点,下来又有骤变点,然后又跌下来了,然后又上来了。
分析下这张表里的骤变点,左边相邻的十个点的最小值,辐射半径值越大就可以找到更平滑变化的高潮和低谷,左边相邻的十个点的最大值找到的是下滑和低谷,高潮和低谷都是通过这个点来找的。那么右边相邻的最小值、最大值以及左边相邻的十个点的最小值最大值,左边相邻的十个点的最小值、最大值,左边相邻十个点的最小值,最小值包括当前点,辐射半径是两边全部,这里指的是左右相邻的20个点,20个点找到一个中间点。
全局最小值指的是窗口,上面指的between10 and current row 是当前行,这个是current row and 10 following,也就是前后各十个。基于差值,左边和右边出现的骤变,说明它可能是一个关键点。
我们就放了很多where条件。比如找的是越过低水位后的局部低谷的开始,然后是一个拐点,找到越过低水位后的局部低谷的结束,低谷结束了就开始上扬,这个query非常复杂非常长,我们可以慢慢去理解,这个过程比较长。
基于原始数据找到它的骤变点,通过上面的查询找到它的骤变点,就变成了上面这个图,发生剧烈变化的高低点都找出来了。
这张图生成了一堆数据,它也找出了骤变点,开始点、同一个斜率的结束点、斜率变化后到了下一个点,下一个点的转折点,这些转折点都会帮你打印出来。
通过query5产生了几千条记录后,我们就筛选出32条关键点,这是通过窗口、帧数据的变化和平均值的变化做比较,找到你要这个转折点。
比如这个,它左边距离相近的十个点都比它小,它右边可能大于等于它的,它是一个转折点,因为它左边只有比它小的点,右边可能是平的或者是小的,那它右边比它小,说明这是一个最高点,还要看平均值。这种抖动都是可以判断出来的。
四、cte,递归
1)应用场景
cte是一个标准的SQL语法,递归可以用在图式搜索,比如社交关系,里面你认识哪些人,或者你跟哪些人是好友。我们的业务系统推荐好友的时候,它可能会把你好友的好友推荐给你,扩大你的朋友圈,这是找你好友的好友的好友的逐级扩展,这是树状的或者是图谱的查询。比如说你的好友的好友的好友可能本身就是你的好友,它在你的网络图谱里面就是个环。
图式搜索除了递归搜索,还有一种是找两个点的最近距离。比如在数据库系统里,我跟成龙经过最短几跳就能探取到他,这也是一个图式搜索,就是图上两个点的最近距离,经过几个人就能够探取到它。
还有一类是索引的跳跃扫描,比如在数据库里面,有一个查询是select from table,然后where性别,年龄小于十,性别等于男,这时要创建什么索引能够最快速去响应这个请求呢?要创建一个联合索引,性别逗号年龄,但是再来一个请求,直接table where年龄小于十,不管男女,小于十岁的,这个时候索引它会很慢,他要把整张索引全扫一遍,因为没有把驱动力告诉它。在OPPO里可以使用跳跃扫描,在pg里面不支持跳跃扫描,就可以用递归查询来模拟。还有树状数据类型的处理,比如基于互联网的分销体系,比如你发展了你的下限,你的下线又可以发展他的下线等,在分佣金的时候,可能你能拿到你下限的下限,下限的下限等,他们产生的销售你都能拿到佣金。我们在统计结算的时候得去递归统计你下级你的下级的下级等,这时候也可以用递归查询完成。
这种业务模型,就是用了递归的业务形态,它的团队效率是非常高的,它可以时时去分配佣金,用递归可以去优化,比如SQL可以降低大量的扫描,类似于skip index的业务场景可以降低大量扫描。
2)递归查询
递归的SQL的写法,启动后第一条是非递归的,有一段output,然后是递归子句,递归子句可以读取output,递归子句大可以读取原始表,又产生了一堆输出,读output的输出又产生一堆输出,会产生临时的temp table,temp table有结果的话又会吐给output, output后发现有了,就会走去执行递归子句,执行这个递归子句同时去读取它,然后又产生了这个临时表,如果有临时表它又会继续,总之只要有结果就会继续递归下去,直到递归子句没有临时结果为止,递归就结束了。所以递归能用图式搜索,skin、index,树状数据处理等,它可以不停的迭代迭代,一直迭代到没有记录为止。
五、skip locked、advisory lock
1)消除锁等待,提高处理吞吐
skype lock是用来解决什么,比如说要去update一批记录,有些记录可能被别人锁住了,这个时候就会等,一旦出现等待你的并发处理能力就一定会下降,怎么来提高呢?大量的每一个人都在批量更新数据并且是并发的,我在更新的记录你也可能会取到,有一种方法是要去更新的这条记录,我拿不到锁的时候就跳过它,我就不锁它也不更新它把能够处理的处理掉,这时就可以用skype log的语法了。
我们来看一下这个语法,我要全表做更新,要并发的大家一起来更新,这是一种方法。另一种是你不做并发就一个人在更新,我更新了1万条记录,花了80秒。
还有另一种方法,我更新它的时候必须拿到lock,只有拿到锁我才会去更新它,或者直接用update把这个放到where条件里面也是ok的。
方法二是跳过,先select它,然后for update skip lock,这个锁我拿不到但别人在更新我就不更新了。比如我开100个并行花了四秒的时间,就把我们单个要花80秒才能更新的就给更新掉了,提升了20倍。并行的处理提高了处理吞吐能力,消除锁等待。
distinct语法应用比较窄,比如一个table里面在优势id上可能有重复的,有重复时就随机拿一条,这个用户今天写了十条记录进来,那个用户今天写了五条记录进来,那我只想返回两条记录,也就是每个用户我返回一条记录,那我们有几种写法呢?一种是用窗口函数,用row number做个排序,取一个row number等于1的,就能够达到这个效果。还有一种是随机的返回,十条里面任意一条都是可以要的,那就用on。C3这个字段是唯一的其它字段是随意,随便它怎么返回,都可以用select distinct on括号c3,后面是输出的结果字段的内容。ok,c3这里 0,1,2,3,4,5,6,7,8,9,10, c2是随机的。
六、秒杀
场景秒杀就是好多并发的数据库update的请求,比如说请求在同样一条记录上面,我们数据库的设计是行,某一个用户在更新这一行记录的时候,或者某一个会话、某一个事物在更新这条记录的时候,其它的会话在同一个时间是不能更新它的,同一条记录上面会有写冲突。秒杀就是某一个热门的商品,好多人同时来买,很多用户在同一个时间点买你的东西,出现好多个请求,同时在更新一条记录,就会出现锁等待,数据库里是串行的它的处理吞吐就会特别低。同一时刻1万个人在秒杀同一个商品,在数据库里面就会有1万个链接,链接一个接一个地更新,秒杀商品只有十个,前面十个人更新出完之后,后面9990个人一起释放,在这段时间之内占用了数据库大量的链接,而且是无用功,十个库存扣减完就不再扣减了,前面的等待都白白占用了数据库的资源。
要想解决这个问题,我们在pg里可以消除这种等待,有四种方法,今天讲两种:一种是advisory lock,一种是skype lock,四种方法都测了一下它的性能,暴力100个并发能处理两千多,两个并发能处理两万多,大量时间在等待,处理并发就低了。
第二个方案叫skip lock,它的吞吐达到五万多,更新时拿到锁就更新,没有拿到直接return返回,这个请求没有等待,处理吞吐能达到五万多。
使用advisory lock会加额外的附加条件,如果商品id是1,这里输的应该是括号id,用户来更新的id等于1的,处理吞吐能达到26万,使用pg advisory lock能够直接把锁消除掉,处理吞吐就高就不用等待。好多个商品在秒杀,一旦商品库存扣减完后,前端就直接回避请求了,所以不会出现大量在同一个商品上浪费大量无用功的问题。
七、批量SQL
批量SQL是在数据库里提高数据处理吞吐的问题,批量插入批、批量更新、批量删除、这都是批量的语法。insert 、copy, value 、update、delete都是支持批量的,如果要大量导入数据。
八、数据分析
数据分析讲的是应用场景的用法和cte的语法,比如做间歇性分析,用了with的语句,每五分钟聚合一下,数据在源源不断的写进来,也在源源不断的消费,把数据库当成一个mq加计算两种功能的结合体。比如数据写进来后,用with的语法delete掉,然后return,这个语句基于子句做聚合,在数据库里面自动每隔一段时间去统计,生成的统计结果就是间歇性数据分析,用语法实现间歇性的数据分析,把数据库当成mq加计算能力的引擎。
九、流计算
pg里有pipelinedb的插件可以实现流计算,也可以把数据库当成流计算引擎使用,创建好流和流上面的计算视图,把数据往流里面去写就好。
十、线性回归
线性回归是做数据预测最常用的方法,在pg里支持线性回归的聚合函数,可以算斜率、算截距,算两者的相关性,通过这几个值做推导,自变量是第n周就是它的value,因变量是第n加一周,我们可以通过一组自变量的值预测因变量的值。比如要预测股票数据营收目标,有今年的营收目标、去年的营收的数据、每一周完成情况的比例,基于每周的完成情况预测下一周。比如十个礼拜的数据可生成九行数据,第一周的数据和第二周的数据是什么?第二周的数据和第三周的数据是什么?形成两个字段的九行记录,可以计算这两组数据的截距、斜率等,有了截距和斜率后,就可以去预测第n加x加1周的数据,也就是上一周的数据乘以斜率加截距。这样就能去预测下周的营收数据。
首先算出用来预测下一个目标阶段数据的这一组数据的斜率和截距,你只要知道这个就可以了,用这组数据最后一条记录的值去乘斜率加截距,就等于要预测的下一个值下一个阶段,这个数据就是预测数据。这是用pg内置的线性回归的数学的聚合函数做的,只有一个自变量一个因变量的两组数据,通过同样的方法可以做股票的预测、股价的预测等。
这里有预测第一天的未来一天,未来两天,未来三天,未来四天的值,用的是二元回归的预测方法。
十一、化学分析
化学分析的rdkit功能模块能存化学分子式,做相似分子的查询、相似度的计算等,在化学分析领域用的比较多,也是开源解决方案里重要的数据存储环节。数据库里已经实现分析函数、索引、分子式检索,比你在应用里实现简单的多。
十二、机器学习
在数据库里集成了一款叫madlib的机器学习模块,把机器学习功能模块转换成抽象的数据库。比如对一组数据做聚集分析找到聚集中央点,比如要做多元线性回归,在madlib里支持多元回归。
十三、update|delete limit
在pg里如何实现update或者delete,比如where条件后要update或者delete的量特别大,垃圾在一个事物里面产生要等到事物结束才能回收,比如update直接干掉几千万条记录,只有在干掉后才能把垃圾回收掉,这时候就可以用update limit,比如说分批做1万条,也比一次性干几千万条好
这是语法和条件,我们一次要操作十条,那么就十然后delete from where id in,用这个行号查询,用下面这个语句把它删掉。
十四、prepare 动态sql in function
什么时候在存储过程里绑定变量动态呢?动态绑定要查的对象或者表名是不确定的,因为在函数里操作的。比如saas服务是每个企业在数据库里会对应自己的表,用后缀来表示它,一个企业分配一个企业id,表名是table下划线企业id,不同的企业id会对应不同的表,操作时会带上企业id,在数据库里用动态SQL带来的问题是每次执行时都要做SQL,做query,再去执行计划,意味着会经历两个比较漫长的比较耗费cpu的动作,一个叫SQL的语法,还有一个是执行计划,SQL越复杂生成执行计划的耗费代价会越高,耗费代价会越高。所以如果是一个高并发调用的话,动态查询和绑定变量的方式性能可能会差十倍,用动态SQL只能做5万的qps,用绑定变量,能做50万甚至上百万的qps。
我们在function里面能把动态转成绑定变量吗?把函数绑定变量也放到function里面,支持动态绑定。执行insert的时候,用取模的方式得到后缀名,再去cute,如果exception抛异常了,说明还没绑定,要先绑定再去cute它。使用动态的性能是52000,使用函数内部绑定是13.4万insert。