中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PostgreSQL中有哪些窗口函數

發布時間:2021-06-15 11:39:11 來源:億速云 閱讀:327 作者:Leah 欄目:大數據

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.
 */
Datum
window_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:83
83	{
(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=<optimized out>, dest=0x1c125e8, direction=<optimized out>, numberTuples=0, sendTuples=true, 
    operation=CMD_SELECT, use_parallel_mode=<optimized out>, planstate=0x1ca23e8, estate=0x1ca21c0) at execMain.c:1648
#5  standard_ExecutorRun (queryDesc=0x1c0eb70, direction=<optimized out>, count=0, execute_once=<optimized out>) 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=<optimized out>, argv=argv@entry=0x1c16f70, dbname=0x1c16e98 "postgres", username=<optimized out>)
    at postgres.c:4256
#10 0x000000000047e579 in BackendRun (port=<optimized out>, port=<optimized out>) 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 void
ExecutePlan(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 void
eval_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); //切換回原上下文
}

看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

集安市| 楚雄市| 思茅市| 青阳县| 龙岩市| 焦作市| 福清市| 松江区| 瑞昌市| 靖边县| 宜昌市| 罗平县| 普兰店市| 平陆县| 渭南市| 广东省| 黄陵县| 托克托县| 临猗县| 林甸县| 南澳县| 景洪市| 碌曲县| 黄大仙区| 个旧市| 乌什县| 保康县| 海阳市| 淮阳县| 南康市| 通城县| 滨海县| 奉贤区| 泾源县| 丰顺县| 灌南县| 南投县| 广汉市| 通化县| 海丰县| 旬阳县|