近期Psql相关业务的收获:agg函数对于null值的处理/ array_agg()/ Unmarshal的性能消耗和工作原理

【case 1】
项目背景:
需要返回一些GC的统计数据。相关数据存在frame这张表内,表中的数据一行就是一帧的数据,可以理解为记录了这一帧内的性能信息。与需求相关的col是GcChartSample,是一个json类型的数据,里面存的是该帧触发的各个种类的GC的大小,没有触发的GC的字段将不会列在这个GC中。例如:{"Internal":252,"Other":192,"Scripts":7832},就是InternalGC是252字节,OtherGC是192字节,ScriptsGC是7832字节。
求:各类GC的有效帧均值(即:非0帧的均值)和最大值

我的第一版解法:
将区间内的所有帧的GcChartSample字段取出放入go中,在go中进行处理。即:先开一个gcLineMap记录所有出现过的GC种类,然后再根据gcLineMap建立gcItemArray,分类push 非0的GC值,最后根据各个数组算出统计数据。

弱化部分需求后,mentor推荐的解法:
用户在查看性能报告的时候,通常只会关注部分GC的值,例如:ScriptsGC,RenderingGC等。因此,并不一定要求出所有GC的统计。并且sql擅长做统计的操作。将统计的工作放在sql里做,能够减少IO。
因此,sql修改如下:

select sum(cast(GcChartSample ->> 'Scripts' as Integer)) as ScriptsGCMax, round(count(cast(GcChartSample ->> 'Scripts' as Integer)), 2) as ScriptsGCMean,
       max(cast(GcChartSample ->> 'Rendering' as Integer)) as RenderingGCMax, round(avg(cast(GcChartSample ->> 'Rendering' as Integer)), 2) as RenderingGCMean,
       max(cast(GcChartSample ->> 'GUI' as Integer)) as GUIGCMax, round(avg(cast(GcChartSample ->> 'GUI' as Integer)), 2) as GUIGCMean,
       max(cast(GcChartSample ->> 'Animation' as Integer)) as AnimationGCMax, round(avg(cast(GcChartSample ->> 'Animation' as Integer)), 2) as AnimationGCMean
from upa.frame where partitionkey = 5;

起初担心,使用sql里的avg操作只能返回均值,无法返回有效帧均值。但是,翻阅sql文档后发现,sum会自动忽略值为null的字段。

psql agg操作总结如下:
AVG

SELECT AVG(amount)::numeric(10,2) FROM payment; //To make the output more readable
SELECT AVG(DISTINCT amount)::numeric(10,2) FROM payment; //The following query returns the average payment made by customers. Because we use DISTINCT, PostgreSQL only takes unique amounts and calculates the average.

COUNT

将列名作为参数,得到NULL之外的数据行数
将星号作为参数,得到所有数据的行数(包含NULL)。

SUM

对于列里面数据有NULL的,也是会事先去掉NULL再计算。

【case 2】
翻阅组内项目的时候发现,psql中含有array_agg操作的,通常都不会在go端做处理,而是以string的方式接收,传递给前端解析成json进行操作。

学习笔记:
PostgreSQL array_agg() 函数是一个聚合函数,它返回一个包含了一个分组中的所有的值的组成的数组。

【case 3】
项目背景:
在做一个需求的时候,我将一个某个sql的返回值用string接到后,进行了Unmarshal操作,mentor提示说最好寻找一下优化的方法,因为Unmarshal操作要一个一个的对,比较伤性能。

学习笔记:

  • Unmarshal将json字符串解码到相应的数据结构。
  • json字符串解析时,需要一个“接收体”接受解析后的数据,且Unmarshal时接收体必须传递指针。
  • 解析时,接收体可自行定义。json串中的key自动在接收体中寻找匹配的项进行赋值。
  • 匹配规则:先查找与key一样的json标签,找到则赋值给该标签对应的变量;没有json标签的,就从上往下依次查找变量名与key一样的变量,或者变量名忽略大小写后与key一样的变量,第一个匹配的就赋值,后面就算有匹配的也忽略(变量可导出,首字母大写)。
  • 当接收体中存在json串中匹配不了的项时,解析会自动忽略该项,该项仍保留原值。
  • json解析后,json串中value,只要是"简单数据",都会按照默认的类型赋值。
  • 简单数据:是指不能再进行二次json解析的数据,例如name
  • 复合数据:是可进行二次甚至多次json解析的,因为它的value也是个可被解析的独立json

你可能感兴趣的:(gopostgresql)