PostgreSQL中有哪些窗口函数
发表于:2025-02-06 作者:千家信息网编辑
千家信息网最后更新 2025年02月06日,PostgreSQL中有哪些窗口函数,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。窗口函数:窗口函数在一组表行中执行计算
千家信息网最后更新 2025年02月06日PostgreSQL中有哪些窗口函数
PostgreSQL中有哪些窗口函数,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。
窗口函数:
窗口函数在一组表行中执行计算,这些表行以某种方式与当前行相关。 这与使用聚合函数可以完成的计算类型相当。 但是,窗口函数不会导致行被分组到单个输出行,就像非窗口聚合调用一样。 相反,行保留其独立的身份。 在幕后,窗口功能不仅可以访问查询结果的当前行。
row_number使用示例:
[postgres@shawnpc bin]$ ./psql psql (13devel)Type "help" for help.postgres=# select row_number() over() as rownum, id from aa; rownum | id --------+---- 1 | 1 2 | 2 3 | 3 4 | 4 5 | 5 6 | 6 7 | 7 8 | 8 9 | 9 10 | 10(10 rows)postgres=#
row_number代码:
/* * row_number * just increment up from 1 until current partition finishes. */Datumwindow_row_number(PG_FUNCTION_ARGS){ WindowObject winobj = PG_WINDOW_OBJECT(); //获取窗口函数内存上下文 int64 curpos = WinGetCurrentPosition(winobj); //初始化位置 WinSetMarkPosition(winobj, curpos); //将行号和位置绑定 PG_RETURN_INT64(curpos + 1); //返回行号}
看起来似乎非常简单,但是经过调试发现这里和执行计划耦合度很高: 设置函数断点:
Breakpoint 1, window_row_number (fcinfo=0x7ffc158cce90) at windowfuncs.c:8383 {(gdb) bt#0 window_row_number (fcinfo=0x7ffc158cce90) at windowfuncs.c:83#1 0x0000000000632956 in eval_windowfunction (perfuncstate=0x1ca3768, result=0x1ca3738, isnull=0x1ca3750, winstate=0x1ca23e8, winstate=0x1ca23e8) at nodeWindowAgg.c:1056#2 0x0000000000635174 in ExecWindowAgg (pstate=0x1ca23e8) at nodeWindowAgg.c:2198#3 0x0000000000605b82 in ExecProcNode (node=0x1ca23e8) at ../../../src/include/executor/executor.h:240#4 ExecutePlan (execute_once=, dest=0x1c125e8, direction= , numberTuples=0, sendTuples=true, operation=CMD_SELECT, use_parallel_mode= , planstate=0x1ca23e8, estate=0x1ca21c0) at execMain.c:1648#5 standard_ExecutorRun (queryDesc=0x1c0eb70, direction= , count=0, execute_once= ) at execMain.c:365#6 0x000000000074c81b in PortalRunSelect (portal=portal@entry=0x1c52e90, forward=forward@entry=true, count=0, count@entry=9223372036854775807, dest=dest@entry=0x1c125e8) at pquery.c:929#7 0x000000000074db60 in PortalRun (portal=portal@entry=0x1c52e90, count=count@entry=9223372036854775807, isTopLevel=isTopLevel@entry=true, run_once=run_once@entry=true, dest=dest@entry=0x1c125e8, altdest=altdest@entry=0x1c125e8, completionTag=completionTag@entry=0x7ffc158cd7e0 "") at pquery.c:770#8 0x0000000000749bc6 in exec_simple_query (query_string=0x1becfa0 "select row_number() over() as rownum, id from aa;") at postgres.c:1231#9 0x000000000074aea2 in PostgresMain (argc= , argv=argv@entry=0x1c16f70, dbname=0x1c16e98 "postgres", username= ) at postgres.c:4256#10 0x000000000047e579 in BackendRun (port= , port= ) at postmaster.c:4446#11 BackendStartup (port=0x1c0ee70) at postmaster.c:4137#12 ServerLoop () at postmaster.c:1704#13 0x00000000006ddb9d in PostmasterMain (argc=argc@entry=3, argv=argv@entry=0x1be7bb0) at postmaster.c:1377#14 0x000000000047f243 in main (argc=3, argv=0x1be7bb0) at main.c:210
从上可知,首先row_number函数执行是在执行计划执行之后进行调用的。 首先进入的是ExecutePlan:
static voidExecutePlan(EState *estate, PlanState *planstate, bool use_parallel_mode, CmdType operation, bool sendTuples, uint64 numberTuples, ScanDirection direction, DestReceiver *dest, bool execute_once){ TupleTableSlot *slot; uint64 current_tuple_count;略 for (;;) { /* Reset the per-output-tuple exprcontext */ ResetPerTupleExprContext(estate); /* * Execute the plan and obtain a tuple */ slot = ExecProcNode(planstate);略}
这里调用了ExecProcNode(宏定义,调用了ExecWindowAgg),ExecWindowAgg调用了eval_windowfunction,而正是eval_windowfunction完成了row_number的调用,并且构建了相关数据。通过调试可以发现,多少行数据就会调用多少次row_number。
eval_windowfunction:
/* * eval_windowfunction * * Arguments of window functions are not evaluated here, because a window * function can need random access to arbitrary rows in the partition. * The window function uses the special WinGetFuncArgInPartition and * WinGetFuncArgInFrame functions to evaluate the arguments for the rows * it wants. */static voideval_windowfunction(WindowAggState *winstate, WindowStatePerFunc perfuncstate, Datum *result, bool *isnull){ LOCAL_FCINFO(fcinfo, FUNC_MAX_ARGS); MemoryContext oldContext; oldContext = MemoryContextSwitchTo(winstate->ss.ps.ps_ExprContext->ecxt_per_tuple_memory); //切换至tuple的内存上下文 /* * We don't pass any normal arguments to a window function, but we do pass * it the number of arguments, in order to permit window function * implementations to support varying numbers of arguments. The real info * goes through the WindowObject, which is passed via fcinfo->context. */ InitFunctionCallInfoData(*fcinfo, &(perfuncstate->flinfo), perfuncstate->numArguments, perfuncstate->winCollation, (void *) perfuncstate->winobj, NULL);//初始化fcinfo,为下面调用函数使用 /* Just in case, make all the regular argument slots be null */ for (int argno = 0; argno < perfuncstate->numArguments; argno++) fcinfo->args[argno].isnull = true;//见注释 /* Window functions don't have a current aggregate context, either */ winstate->curaggcontext = NULL;//见注释 *result = FunctionCallInvoke(fcinfo);//调用函数 *isnull = fcinfo->isnull; /* * Make sure pass-by-ref data is allocated in the appropriate context. (We * need this in case the function returns a pointer into some short-lived * tuple, as is entirely possible.) */ if (!perfuncstate->resulttypeByVal && !fcinfo->isnull && !MemoryContextContains(CurrentMemoryContext, DatumGetPointer(*result))) *result = datumCopy(*result, perfuncstate->resulttypeByVal, perfuncstate->resulttypeLen); //见注释 MemoryContextSwitchTo(oldContext); //切换回原上下文}
看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注行业资讯频道,感谢您对的支持。
函数
上下
上下文
注释
位置
内存
数据
行号
切换
帮助
清楚
代码
内容
功能
单个
对此
文章
断点
新手
方式
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全法知识学习心得体会
软件开发工程师就业怎么样
上海虹越互联网科技
自由开源服务器管理软件是什么
互联网 科技公司
管理服务器系统
数据库px是什么意思
asp编号插入数据库
将服务器设置为跨域 安全
软件开发实现开题报告
华为hpibm服务器价格表
网络安全宣传展板图片
天津先进软件开发供应商
软件开发资源管理计划
防盗防骗网络安全
语音数据库 开源
有什么软件清理qq数据库
吴中区品质网络技术诚信经营
电脑服务器噪音太大
送外卖如何选择服务器
部队网络安全宣传周海报
网络安全风险问题表格
南方数据库
北洋标签打印机的数据库
远程服务器配置
db2数据库查看游标数
学生网络安全观后感
网络安全协议课后题答案
网络安全工作总结机关单位
软件开发绩效考核可以量化的指标