本篇内容主要讲解“怎么使用PostgreSQL的tuplesort_performsort函数”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用PostgreSQL的tuplesort_performsort函数”吧!

TupleTableSlot
执行器在”tuple table”中存储元组,这个表是各自独立的TupleTableSlots链表.

/*----------*Theexecutorstorestuplesina"tupletable"whichisaListof*independentTupleTableSlots.Thereareseveralcasesweneedtohandle:*1.physicaltupleinadiskbufferpage*2.physicaltupleconstructedinpalloc'edmemory*3."minimal"physicaltupleconstructedinpalloc'edmemory*4."virtual"tupleconsistingofDatum/isnullarrays*执行器在"tupletable"中存储元组,这个表是各自独立的TupleTableSlots链表.*有以下情况需要处理:*1.磁盘缓存页中的物理元组*2.在已分配内存中构造的物理元组*3.在已分配内存中构造的"minimal"物理元组*4.含有Datum/isnull数组的"virtual"虚拟元组**Thefirsttwocasesaresimilarinthattheybothdealwith"materialized"*tuples,butresourcemanagementisdifferent.Foratupleinadiskpage*weneedtoholdapinonthebufferuntiltheTupleTableSlot'sreference*tothetupleisdropped;whileforapalloc'dtupleweusuallywantthe*tuplepfree'dwhentheTupleTableSlot'sreferenceisdropped.*最上面2种情况跟"物化"元组的处理方式类似,但资源管理是不同的.*对于在磁盘页中的元组,需要pin在缓存中直至TupleTableSlot依赖的元组被清除,*而对于通过palloc分配的元组在TupleTableSlot依赖被清除后通常希望使用pfree释放**A"minimal"tupleishandledsimilarlytoapalloc'dregulartuple.*Atpresent,minimaltuplesneverarestoredinbuffers,sothereisno*paralleltocase1.Notethataminimaltuplehasno"systemcolumns".*(Actually,itcouldhaveanOID,butwehavenoneedtoaccesstheOID.)*"minimal"元组与通常的palloc分配的元组处理类似.*截止目前为止,"minimal"元组不会存储在缓存中,因此对于第一种情况不会存在并行的问题.*注意"minimal"没有"systemcolumns"系统列*(实际上,可以有OID,但不需要访问OID列)**A"virtual"tupleisanoptimizationusedtominimizephysicaldata*copyinginanestofplannodes.Anypass-by-referenceDatumsinthe*tuplepointtostoragethatisnotdirectlyassociatedwiththe*TupleTableSlot;generallytheywillpointtopartofatuplestoredin*alowerplannode'soutputTupleTableSlot,ortoafunctionresult*constructedinaplannode'sper-tupleecontext.Itistheresponsibility*ofthegeneratingplannodetobesuretheseresourcesarenotreleased*foraslongasthevirtualtupleneedstobevalid.Weonlyusevirtual*tuplesintheresultslotsofplannodes---tuplestobecopiedanywhere*elseneedtobe"materialized"intophysicaltuples.Notealsothata*virtualtupledoesnothaveany"systemcolumns".*"virtual"元组是用于在嵌套计划节点中拷贝时最小化物理数据的优化.*所有通过引用传递指向与TupleTableSlot非直接相关的存储的元组的Datums使用,*通常它们会指向存储在低层节点输出的TupleTableSlot中的元组的一部分,*或者指向在计划节点的per-tuple内存上下文econtext中构造的函数结果.*产生计划节点的时候有责任确保这些资源未被释放,确保virtual元组是有效的.*我们使用计划节点中的结果slots中的虚拟元组---元组会拷贝到其他地方需要"物化"到物理元组中.*注意virtual元组不需要有"systemcolumns"**ItisalsopossibleforaTupleTableSlottoholdbothphysicalandminimal*copiesofatuple.Thisisdonewhentheslotisrequestedtoprovide*theformatotherthantheoneitcurrentlyholds.(Originallyweattempted*tohandlesuchrequestsbyreplacingoneformatwiththeother,butthat*hadthefataldefectofinvalidatinganypass-by-referenceDatumspointing*intotheexistingslotcontents.)Bothcopiesmustcontainidenticaldata*payloadswhenthisisthecase.*TupleTableSlot包含物理和minimal元组拷贝是可能的.*在slot需要提供格式化而不是当前持有的格式时会出现这种情况.*(原始的情况是我们准备通过另外一种格式进行替换来处理这种请求,但在校验引用传递Datums时会出现致命错误)*同时在这种情况下,拷贝必须含有唯一的数据payloads.**TheDatum/isnullarraysofaTupleTableSlotservedoubleduty.Whenthe*slotcontainsavirtualtuple,theyaretheauthoritativedata.Whenthe*slotcontainsaphysicaltuple,thearrayscontaindataextractedfrom*thetuple.(Inthisstate,anypass-by-referenceDatumspointinto*thephysicaltuple.)Theextractedinformationisbuilt"lazily",*ie,onlyasneeded.Thisservestoavoidrepeatedextractionofdata*fromthephysicaltuple.*TupleTableSlot中的Datum/isnull数组有双重职责.*在slot包含虚拟元组时,它们是authoritative(权威)数据.*在slot包含物理元组时,时包含从元组中提取的数据的数组.*(在这种情况下,所有通过引用传递的Datums指向物理元组)*提取的信息通过'lazily'在需要的时候才构建.*这样可以避免从物理元组的重复数据提取.**ATupleTableSlotcanalsobe"empty",holdingnovaliddata.Thisis*theonlyvalidstateforafreshly-createdslotthathasnotyethada*tupledescriptorassignedtoit.Inthisstate,tts_isemptymustbe*true,tts_shouldFreefalse,tts_tupleNULL,tts_bufferInvalidBuffer,*andtts_nvalidzero.*TupleTableSlot可能为"empty",没有有效数据.*对于新鲜创建仍未分配描述的的slot来说这是唯一有效的状态.*在这种状态下,tts_isempty必须为T,tts_shouldFree为F,tts_tuple为NULL,*tts_buffer为InvalidBuffer,tts_nvalid为0.**ThetupleDescriptorissimplyreferenced,notcopied,bytheTupleTableSlot*code.ThecallerofExecSetSlotDescriptor()isresponsibleforproviding*adescriptorthatwillliveaslongastheslotdoes.(Typically,both*slotsanddescriptorsareinper-querymemoryandarefreedbymemory*contextdeallocationatqueryend;soit'snotworthprovidinganyextra*mechanismtodomore.However,theslotwillincrementthetupdesc*referencecountifareference-countedtupdescissupplied.)*tupleDescriptor只是简单的引用并没有通过TupleTableSlot中的代码进行拷贝.*ExecSetSlotDescriptor()的调用者有责任提供与slot生命周期一样的描述符.*(典型的,不管是slots还是描述符会在per-query内存中,*并且会在查询结束时通过内存上下文的析构器释放,因此不需要提供额外的机制来处理.*但是,如果使用了引用计数型tupdesc,slot会增加tupdesc引用计数)**Whentts_shouldFreeistrue,thephysicaltupleis"owned"bytheslot*andshouldbefreedwhentheslot'sreferencetothetupleisdropped.*在tts_shouldFree为T的情况下,物理元组由slot持有,并且在slot引用元组被清除时释放内存.**Iftts_bufferisnotInvalidBuffer,thentheslotisholdingapin*ontheindicatedbufferpage;dropthepinwhenwereleasethe*slot'sreferencetothatbuffer.(tts_shouldFreeshouldalwaysbe*falseinsuchacase,sincepresumablytts_tupleispointingatthe*bufferpage.)*如tts_buffer不是InvalidBuffer,那么slot持有缓存页中的pin,在释放引用该buffer的slot时会清除该pin.*(tts_shouldFree通常来说应为F,因为tts_tuple会指向缓存页)**tts_nvalidindicatesthenumberofvalidcolumnsinthetts_values/isnull*arrays.Whentheslotisholdinga"virtual"tuplethismustbeequal*tothedescriptor'snatts.Whentheslotisholdingaphysicaltuple*thisisequaltothenumberofcolumnswehaveextracted(wealways*extractcolumnsfromlefttoright,sotherearenoholes).*tts_nvalid指示了tts_values/isnull数组中的有效列数.*如果slot含有虚拟元组,该字段必须跟描述符的natts一样.*在slot含有物理元组时,该字段等于我们提取的列数.*(我们通常从左到右提取列,因此不会有空洞存在)**tts_values/tts_isnullareallocatedwhenadescriptorisassignedtothe*slot;theyareoflengthequaltothedescriptor'snatts.*在描述符分配给slot时tts_values/tts_isnull会被分配内存,长度与描述符natts长度一样.**tts_mintuplemustalwaysbeNULLiftheslotdoesnotholda"minimal"*tuple.Whenitdoes,tts_mintuplepointstotheactualMinimalTupleData*object(thethingtobepfree'diftts_shouldFreeMinistrue).Iftheslot*hasonlyaminimalandnotalsoaregularphysicaltuple,thentts_tuple*pointsattts_minhdrandthefieldsofthatstructaresetcorrectly*foraccesstotheminimaltuple;inparticular,tts_minhdr.t_datapoints*MINIMAL_TUPLE_OFFSETbytesbeforetts_mintuple.Thisallowscolumn*extractiontotreatthecaseidenticallytoregularphysicaltuples.*如果slot没有包含minimal元组,tts_mintuple通常必须为NULL.*如含有,则tts_mintuple执行实际的MinimalTupleData对象(如tts_shouldFreeMin为T,则需要通过pfree释放内存).*如果slot只有一个minimal而没有通常的物理元组,那么tts_tuple指向tts_minhdr,*结构体的其他字段会被正确的设置为用于访问minimal元组.*特别的,tts_minhdr.t_data指向tts_mintuple前的MINIMAL_TUPLE_OFFSET字节.*这可以让列提取可以独立处理通常的物理元组.**tts_slow/tts_offaresavedstateforslot_deform_tuple,andshouldnot*betouchedbyanyothercode.*tts_slow/tts_off用于存储slot_deform_tuple状态,不应通过其他代码修改.*----------*/typedefstructTupleTableSlot{NodeTagtype;//Node标记//如slot为空,则为Tbooltts_isempty;/*true=slotisempty*///是否需要pfreetts_tuple?booltts_shouldFree;/*shouldpfreetts_tuple?*///是否需要pfreetts_mintuple?booltts_shouldFreeMin;/*shouldpfreetts_mintuple?*/#defineFIELDNO_TUPLETABLESLOT_SLOW4//为slot_deform_tuple存储状态?booltts_slow;/*savedstateforslot_deform_tuple*/#defineFIELDNO_TUPLETABLESLOT_TUPLE5//物理元组,如为虚拟元组则为NULLHeapTupletts_tuple;/*physicaltuple,orNULLifvirtual*/#defineFIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR6//slot中的元组描述符TupleDesctts_tupleDescriptor;/*slot'stupledescriptor*///slot所在的上下文MemoryContexttts_mcxt;/*slotitselfisinthiscontext*///元组缓存,如无则为InvalidBufferBuffertts_buffer;/*tuple'sbuffer,orInvalidBuffer*/#defineFIELDNO_TUPLETABLESLOT_NVALID9//tts_values中的有效值inttts_nvalid;/*#ofvalidvaluesintts_values*/#defineFIELDNO_TUPLETABLESLOT_VALUES10//当前每个属性的值Datum*tts_values;/*currentper-attributevalues*/#defineFIELDNO_TUPLETABLESLOT_ISNULL11//isnull数组bool*tts_isnull;/*currentper-attributeisnullflags*///minimal元组,如无则为NULLMinimalTupletts_mintuple;/*minimaltuple,orNULLifnone*///在minimal情况下的工作空间HeapTupleDatatts_minhdr;/*workspaceforminimal-tuple-onlycase*/#defineFIELDNO_TUPLETABLESLOT_OFF14//slot_deform_tuple的存储状态uint32tts_off;/*savedstateforslot_deform_tuple*///不能被变更的描述符(固定描述符)booltts_fixedTupleDescriptor;/*descriptorcan'tbechanged*/}TupleTableSlot;/*basetupletableslottype*/typedefstructTupleTableSlot{NodeTagtype;//Node标记#defineFIELDNO_TUPLETABLESLOT_FLAGS1uint16tts_flags;/*布尔状态;Booleanstates*/#defineFIELDNO_TUPLETABLESLOT_NVALID2AttrNumbertts_nvalid;/*在tts_values中有多少有效的values;#ofvalidvaluesintts_values*/constTupleTableSlotOps*consttts_ops;/*slot的实际实现;implementationofslot*/#defineFIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR4TupleDesctts_tupleDescriptor;/*slot的元组描述符;slot'stupledescriptor*/#defineFIELDNO_TUPLETABLESLOT_VALUES5Datum*tts_values;/*当前属性值;currentper-attributevalues*/#defineFIELDNO_TUPLETABLESLOT_ISNULL6bool*tts_isnull;/*当前属性isnull标记;currentper-attributeisnullflags*/MemoryContexttts_mcxt;/*内存上下文;slotitselfisinthiscontext*/}TupleTableSlot;/*routinesforaTupleTableSlotimplementation*///TupleTableSlot的"小程序"structTupleTableSlotOps{/*Minimumsizeoftheslot*///slot的最小化大小size_tbase_slot_size;/*Initialization.*///初始化方法void(*init)(TupleTableSlot*slot);/*Destruction.*///析构方法void(*release)(TupleTableSlot*slot);/**Clearthecontentsoftheslot.Onlythecontentsareexpectedtobe*clearedandnotthetupledescriptor.Typicallyanimplementationof*thiscallbackshouldfreethememoryallocatedforthetuplecontained*intheslot.*清除slot中的内容。*只希望清除内容,而不希望清除元组描述符。*通常,这个回调的实现应该释放为slot中包含的元组分配的内存。*/void(*clear)(TupleTableSlot*slot);/**Fillupfirstnattsentriesoftts_valuesandtts_isnullarrayswith*valuesfromthetuplecontainedintheslot.Thefunctionmaybecalled*withnattsmorethanthenumberofattributesavailableinthetuple,*inwhichcaseitshouldsettts_nvalidtothenumberofreturned*columns.*用slot中包含的元组的值填充tts_values和tts_isnull数组的第一个natts条目。*在调用该函数时,natts可能多于元组中可用属性的数量,在这种情况下,*应该将tts_nvalid设置为返回列的数量。*/void(*getsomeattrs)(TupleTableSlot*slot,intnatts);/**Returnsvalueofthegivensystemattributeasadatumandsetsisnull*tofalse,ifit'snotNULL.Throwsanerroriftheslottypedoesnot*supportsystemattributes.*将给定系统属性的值作为基准返回,如果不为NULL,*则将isnull设置为false。如果slot类型不支持系统属性,则引发错误。*/Datum(*getsysattr)(TupleTableSlot*slot,intattnum,bool*isnull);/**Makethecontentsoftheslotsolelydependontheslot,andnoton*underlyingresources(likeanothermemorycontext,buffers,etc).*使slot的内容完全依赖于slot,而不是底层资源(如另一个内存上下文、缓冲区等)。*/void(*materialize)(TupleTableSlot*slot);/**Copythecontentsofthesourceslotintothedestinationslot'sown*context.Invokedusingcallbackofthedestinationslot.*将源slot的内容复制到目标slot自己的上下文中。*使用目标slot的回调函数调用。*/void(*copyslot)(TupleTableSlot*dstslot,TupleTableSlot*srcslot);/**Returnaheaptuple"owned"bytheslot.Itisslot'sresponsibilityto*freethememoryconsumedbytheheaptuple.Iftheslotcannot"own"a*heaptuple,itshouldnotimplementthiscallbackandshouldsetitas*NULL.*返回slot“拥有”的堆元组。*slot负责释放堆元组分配的内存。*如果slot不能“拥有”堆元组,它不应该实现这个回调函数,应该将它设置为NULL。*/HeapTuple(*get_heap_tuple)(TupleTableSlot*slot);/**Returnaminimaltuple"owned"bytheslot.Itisslot'sresponsibility*tofreethememoryconsumedbytheminimaltuple.Iftheslotcannot*"own"aminimaltuple,itshouldnotimplementthiscallbackandshould*setitasNULL.*返回slot“拥有”的最小元组。*slot负责释放最小元组分配的内存。*如果slot不能“拥有”最小元组,它不应该实现这个回调函数,应该将它设置为NULL。*/MinimalTuple(*get_minimal_tuple)(TupleTableSlot*slot);/**Returnacopyofheaptuplerepresentingthecontentsoftheslot.The*copyneedstobepalloc'dinthecurrentmemorycontext.Theslot*itselfisexpectedtoremainunaffected.Itis*not*expectedtohave*meaningful"systemcolumns"inthecopy.Thecopyisnotbe"owned"by*thesloti.e.thecallerhastotakeresponsibiltytofreememory*consumedbytheslot.*返回表示slot内容的堆元组副本。*需要在当前内存上下文中对副本进行内存分配palloc。*预计slot本身不会受到影响。*它不希望在副本中有有意义的“系统列”。副本不是slot“拥有”的,即调用方必须负责释放slot消耗的内存。*/HeapTuple(*copy_heap_tuple)(TupleTableSlot*slot);/**Returnacopyofminimaltuplerepresentingthecontentsoftheslot.The*copyneedstobepalloc'dinthecurrentmemorycontext.Theslot*itselfisexpectedtoremainunaffected.Itis*not*expectedtohave*meaningful"systemcolumns"inthecopy.Thecopyisnotbe"owned"by*thesloti.e.thecallerhastotakeresponsibiltytofreememory*consumedbytheslot.*返回表示slot内容的最小元组的副本。*需要在当前内存上下文中对副本进行palloc。*预计slot本身不会受到影响。*它不希望在副本中有有意义的“系统列”。副本不是slot“拥有”的,即调用方必须负责释放slot消耗的内存。*/MinimalTuple(*copy_minimal_tuple)(TupleTableSlot*slot);};typedefstructtupleDesc{intnatts;/*tuple中的属性数量;numberofattributesinthetuple*/Oidtdtypeid;/*tuple类型的组合类型ID;compositetypeIDfortupletype*/int32tdtypmod;/*tuple类型的typmode;typmodfortupletype*/inttdrefcount;/*依赖计数,如为-1,则没有依赖;referencecount,or-1ifnotcounting*/TupleConstr*constr;/*约束,如无则为NULL;constraints,orNULLifnone*//*attrs[N]isthedescriptionofAttributeNumberN+1*///attrs[N]是第N+1个属性的描述符FormData_pg_attributeattrs[FLEXIBLE_ARRAY_MEMBER];}*TupleDesc;

SortState
排序运行期状态信息

/*----------------*SortStateinformation*排序运行期状态信息*----------------*/typedefstructSortState{//基类ScanStatess;/*itsfirstfieldisNodeTag*///是否需要随机访问排序输出?boolrandomAccess;/*needrandomaccesstosortoutput?*///结果集是否存在边界?boolbounded;/*istheresultsetbounded?*///如存在边界,需要多少个元组?int64bound;/*ifbounded,howmanytuplesareneeded*///是否已完成排序?boolsort_Done;/*sortcompletedyet?*///是否使用有界值?boolbounded_Done;/*valueofboundedwedidthesortwith*///使用的有界值?int64bound_Done;/*valueofboundwedidthesortwith*///tuplesort.c的私有状态void*tuplesortstate;/*privatestateoftuplesort.c*///是否worker?boolam_worker;/*areweaworker?*///每个worker对应一个条目SharedSortInfo*shared_info;/*oneentryperworker*/}SortState;/*----------------*Sharedmemorycontainerforper-workersortinformation*per-worker排序信息的共享内存容器*----------------*/typedefstructSharedSortInfo{//worker个数?intnum_workers;//排序机制TuplesortInstrumentationsinstrument[FLEXIBLE_ARRAY_MEMBER];}SharedSortInfo;

TuplesortInstrumentation
报告排序统计的数据结构.

/**Datastructuresforreportingsortstatistics.Notethat*TuplesortInstrumentationcan'tcontainanypointersbecausewe*sometimesputitinsharedmemory.*报告排序统计的数据结构.*注意TuplesortInstrumentation不能包含指针因为有时候会把该结构体放在共享内存中.*/typedefenum{SORT_TYPE_STILL_IN_PROGRESS=0,//仍然在排序中SORT_TYPE_TOP_N_HEAPSORT,//TOPN堆排序SORT_TYPE_QUICKSORT,//快速排序SORT_TYPE_EXTERNAL_SORT,//外部排序SORT_TYPE_EXTERNAL_MERGE//外部排序后的合并}TuplesortMethod;//排序方法typedefenum{SORT_SPACE_TYPE_DISK,//需要用上磁盘SORT_SPACE_TYPE_MEMORY//使用内存}TuplesortSpaceType;typedefstructTuplesortInstrumentation{//使用的排序算法TuplesortMethodsortMethod;/*sortalgorithmused*///排序使用空间类型TuplesortSpaceTypespaceType;/*typeofspacespaceUsedrepresents*///空间消耗(以K为单位)longspaceUsed;/*spaceconsumption,inkB*/}TuplesortInstrumentation;二、源码解读

tuplesort_performsort是排序的实现.

/**Alltupleshavebeenprovided;finishthesort.*已存在元组,执行排序!*/voidtuplesort_performsort(Tuplesortstate*state){MemoryContextoldcontext=MemoryContextSwitchTo(state->sortcontext);#ifdefTRACE_SORTif(trace_sort)elog(LOG,"performsortofworker%dstarting:%s",state->worker,pg_rusage_show(&state->ru_start));#endif//根据状态执行不同的逻辑switch(state->status){caseTSS_INITIAL:/**Wewereabletoaccumulateallthetupleswithintheallowed*amountofmemory,orleadertotakeoverworkertapes*可以在允许的内存大小中积累所有的元组,或者让协调者接管工作tapes.*/if(SERIAL(state)){/*Justqsort'emandwe'redone*///快速排序tuplesort_sort_memtuples(state);state->status=TSS_SORTEDINMEM;}elseif(WORKER(state)){/**Parallelworkersmuststilldumpouttuplestotape.No*mergeisrequiredtoproducesingleoutputrun,though.*并行worker必须dump元组到磁盘上.*但是,生成单个输出运行不需要合并.*/inittapes(state,false);dumptuples(state,true);worker_nomergeruns(state);state->status=TSS_SORTEDONTAPE;}else{/**Leaderwilltakeoverworkertapesandmergeworkerruns.*Notethatmergerunssetsthecorrectstate->status.*并行协调器会接管工作进程的数据并合并工作线程运行.*注意mergeruns会设置正确的状态:state->status*/leader_takeover_tapes(state);mergeruns(state);}state->current=0;state->eof_reached=false;state->markpos_block=0L;state->markpos_offset=0;state->markpos_eof=false;break;caseTSS_BOUNDED://堆排序/**Wewereabletoaccumulateallthetuplesrequiredforoutput*inmemory,usingaheaptoeliminateexcesstuples.Nowwe*havetotransformtheheaptoaproperly-sortedarray.*使用堆来消除多余的元组,在内存可以积累所有的元组用于输出.*现在我们必须转换堆为已排序的数组.*/sort_bounded_heap(state);state->current=0;state->eof_reached=false;state->markpos_offset=0;state->markpos_eof=false;state->status=TSS_SORTEDINMEM;break;caseTSS_BUILDRUNS:/**Finishtape-basedsort.First,flushalltuplesremainingin*memoryouttotape;thenmergeuntilwehaveasingleremaining*run(or,if!randomAccessand!WORKER(),onerunpertape).*Notethatmergerunssetsthecorrectstate->status.*完成tape-based排序.*首先刷新所有在内存的元组到tape(持久化存储)上,然后合并直至只留下一个在运行.*(否则,如果!randomAccess且!WORKER(),一个tape运行一次)*///全部刷到磁盘上dumptuples(state,true);//合并执行mergeruns(state);state->eof_reached=false;state->markpos_block=0L;state->markpos_offset=0;state->markpos_eof=false;break;default:elog(ERROR,"invalidtuplesortstate");break;}#ifdefTRACE_SORTif(trace_sort){if(state->status==TSS_FINALMERGE)elog(LOG,"performsortofworker%ddone(except%d-wayfinalmerge):%s",state->worker,state->activeTapes,pg_rusage_show(&state->ru_start));elseelog(LOG,"performsortofworker%ddone:%s",state->worker,pg_rusage_show(&state->ru_start));}#endifMemoryContextSwitchTo(oldcontext);}三、跟踪分析

测试脚本

select*fromt_sortorderbyc1,c2;

跟踪分析

(gdb)btuplesort_begin_heapBreakpoint1at0xa6ffa1:filetuplesort.c,line812.(gdb)btuplesort_puttupleslotBreakpoint2at0xa7119d:filetuplesort.c,line1436.(gdb)btuplesort_performsortBreakpoint3at0xa71f45:filetuplesort.c,line1792.(gdb)cContinuing.Breakpoint1,tuplesort_begin_heap(tupDesc=0x208fa40,nkeys=2,attNums=0x2081858,sortOperators=0x2081878,sortCollations=0x2081898,nullsFirstFlags=0x20818b8,workMem=4096,coordinate=0x0,randomAccess=false)attuplesort.c:812812Tuplesortstate*state=tuplesort_begin_common(workMem,coordinate,(gdb)

tuplesort_begin_heap
输入参数

(gdb)p*tupDesc$1={natts=7,tdtypeid=2249,tdtypmod=-1,tdhasoid=false,tdrefcount=-1,constr=0x0,attrs=0x208fa60}(gdb)p*tupDesc->attrs$2={attrelid=0,attname={data='\000'<repeats63times>},atttypid=1043,attstattarget=-1,attlen=-1,attnum=1,attndims=0,attcacheoff=-1,atttypmod=24,attbyval=false,attstorage=120'x',attalign=105'i',attnotnull=false,atthasdef=false,atthasmissing=false,attidentity=0'\000',attisdropped=false,attislocal=true,attinhcount=0,attcollation=100}(gdb)p*attNums$3=2(gdb)p*sortOperators$4=97(gdb)p*sortCollations$5=0(gdb)pnullsFirstFlags$6=(_Bool*)0x20818b8(gdb)p*nullsFirstFlags$7=false(gdb)

获取排序状态,status = TSS_INITIAL

(gdb)p*state$8={status=TSS_INITIAL,nKeys=0,randomAccess=false,bounded=false,boundUsed=false,bound=0,tuples=true,availMem=4169704,allowedMem=4194304,maxTapes=0,tapeRange=0,sortcontext=0x2093290,tuplecontext=0x20992c0,tapeset=0x0,comparetup=0x0,copytup=0x0,writetup=0x0,readtup=0x0,memtuples=0x209b310,memtupcount=0,memtupsize=1024,growmemtuples=true,slabAllocatorUsed=false,slabMemoryBegin=0x0,slabMemoryEnd=0x0,slabFreeHead=0x0,read_buffer_size=0,lastReturnedTuple=0x0,currentRun=0,mergeactive=0x0,Level=0,destTape=0,tp_fib=0x0,tp_runs=0x0,tp_dummy=0x0,tp_tapenum=0x0,activeTapes=0,result_tape=-1,current=0,eof_reached=false,markpos_block=0,markpos_offset=0,markpos_eof=false,worker=-1,shared=0x0,nParticipants=-1,tupDesc=0x0,sortKeys=0x0,onlyKey=0x0,abbrevNext=0,indexInfo=0x0,estate=0x0,heapRel=0x0,indexRel=0x0,enforceUnique=false,high_mask=0,low_mask=0,max_buckets=0,datumType=0,datumTypeLen=0,ru_start={tv={tv_sec=0,tv_usec=0},ru={ru_utime={tv_sec=0,tv_usec=0},ru_stime={tv_sec=0,tv_usec=0},{ru_maxrss=0,__ru_maxrss_word=0},{ru_ixrss=0,__ru_ixrss_word=0},{ru_idrss=0,__ru_idrss_word=0},{ru_isrss=0,__ru_isrss_word=0},{ru_minflt=0,__ru_minflt_word=0},{ru_majflt=0,__ru_majflt_word=0},{ru_nswap=0,__ru_nswap_word=0},{ru_inblock=0,__ru_inblock_word=0},{ru_oublock=0,__ru_oublock_word=0},{ru_msgsnd=0,__ru_msgsnd_word=0},{ru_msgrcv=0,__ru_msgrcv_word=0},{ru_nsignals=0,__ru_nsignals_word=0},{ru_nvcsw=0,__ru_nvcsw_word=0},{ru_nivcsw=0,__ru_nivcsw_word=0}}}}

设置运行状态

(gdb)n819AssertArg(nkeys>0);(gdb)822if(trace_sort)(gdb)828state->nKeys=nkeys;(gdb)830TRACE_POSTGRESQL_SORT_START(HEAP_SORT,(gdb)837state->comparetup=comparetup_heap;(gdb)838state->copytup=copytup_heap;(gdb)839state->writetup=writetup_heap;(gdb)840state->readtup=readtup_heap;(gdb)842state->tupDesc=tupDesc;/*assumeweneednotcopytupDesc*/(gdb)843state->abbrevNext=10;(gdb)846state->sortKeys=(SortSupport)palloc0(nkeys*sizeof(SortSupportData));(gdb)848for(i=0;i<nkeys;i++)(gdb)p*state$9={status=TSS_INITIAL,nKeys=2,randomAccess=false,bounded=false,boundUsed=false,bound=0,tuples=true,availMem=4169704,allowedMem=4194304,maxTapes=0,tapeRange=0,sortcontext=0x2093290,tuplecontext=0x20992c0,tapeset=0x0,comparetup=0xa7525b<comparetup_heap>,copytup=0xa76247<copytup_heap>,writetup=0xa76de1<writetup_heap>,readtup=0xa76ec6<readtup_heap>,memtuples=0x209b310,memtupcount=0,memtupsize=1024,growmemtuples=true,slabAllocatorUsed=false,slabMemoryBegin=0x0,slabMemoryEnd=0x0,slabFreeHead=0x0,read_buffer_size=0,lastReturnedTuple=0x0,currentRun=0,mergeactive=0x0,Level=0,destTape=0,tp_fib=0x0,tp_runs=0x0,tp_dummy=0x0,tp_tapenum=0x0,activeTapes=0,result_tape=-1,current=0,eof_reached=false,markpos_block=0,markpos_offset=0,markpos_eof=false,worker=-1,shared=0x0,nParticipants=-1,tupDesc=0x208fa40,sortKeys=0x20937c0,onlyKey=0x0,abbrevNext=10,indexInfo=0x0,estate=0x0,heapRel=0x0,indexRel=0x0,enforceUnique=false,high_mask=0,low_mask=0,max_buckets=0,datumType=0,datumTypeLen=0,ru_start={tv={tv_sec=0,tv_usec=0},ru={ru_utime={tv_sec=0,tv_usec=0},ru_stime={tv_sec=0,tv_usec=0},{ru_maxrss=0,__ru_maxrss_word=0},{ru_ixrss=0,__ru_ixrss_word=0},{ru_idrss=0,__ru_idrss_word=0},{ru_isrss=0,__ru_isrss_word=0},{ru_minflt=0,__ru_minflt_word=0},{ru_majflt=0,__ru_majflt_word=0},{ru_nswap=0,__ru_nswap_word=0},{ru_inblock=0,__ru_inblock_word=0},{ru_oublock=0,__ru_oublock_word=0},{ru_msgsnd=0,__ru_msgsnd_word=0},{ru_msgrcv=0,__ru_msgrcv_word=0},{ru_nsignals=0,__ru_nsignals_word=0},{ru_nvcsw=0,__ru_nvcsw_word=0},{ru_nivcsw=0,__ru_nivcsw_word=0}}}}(gdb)

为每一列(c1&c2)准备SortSupport数据(分配内存空间)

(gdb)n850SortSupportsortKey=state->sortKeys+i;(gdb)852AssertArg(attNums[i]!=0);(gdb)p*state->sortKeys$10={ssup_cxt=0x0,ssup_collation=0,ssup_reverse=false,ssup_nulls_first=false,ssup_attno=0,ssup_extra=0x0,comparator=0x0,abbreviate=false,abbrev_converter=0x0,abbrev_abort=0x0,abbrev_full_comparator=0x0}(gdb)n853AssertArg(sortOperators[i]!=0);(gdb)855sortKey->ssup_cxt=CurrentMemoryContext;(gdb)856sortKey->ssup_collation=sortCollations[i];(gdb)857sortKey->ssup_nulls_first=nullsFirstFlags[i];(gdb)858sortKey->ssup_attno=attNums[i];(gdb)860sortKey->abbreviate=(i==0);(gdb)862PrepareSortSupportFromOrderingOp(sortOperators[i],sortKey);(gdb)848for(i=0;i<nkeys;i++)(gdb)850SortSupportsortKey=state->sortKeys+i;(gdb)852AssertArg(attNums[i]!=0);(gdb)853AssertArg(sortOperators[i]!=0);(gdb)855sortKey->ssup_cxt=CurrentMemoryContext;(gdb)856sortKey->ssup_collation=sortCollations[i];(gdb)857sortKey->ssup_nulls_first=nullsFirstFlags[i];(gdb)858sortKey->ssup_attno=attNums[i];(gdb)860sortKey->abbreviate=(i==0);(gdb)862PrepareSortSupportFromOrderingOp(sortOperators[i],sortKey);(gdb)848for(i=0;i<nkeys;i++)(gdb)

完成初始化,返回state

(gdb)871if(nkeys==1&&!state->sortKeys->abbrev_converter)(gdb)n874MemoryContextSwitchTo(oldcontext);(gdb)876returnstate;(gdb)p*state$11={status=TSS_INITIAL,nKeys=2,randomAccess=false,bounded=false,boundUsed=false,bound=0,tuples=true,availMem=4169704,allowedMem=4194304,maxTapes=0,tapeRange=0,sortcontext=0x2093290,tuplecontext=0x20992c0,tapeset=0x0,comparetup=0xa7525b<comparetup_heap>,copytup=0xa76247<copytup_heap>,writetup=0xa76de1<writetup_heap>,readtup=0xa76ec6<readtup_heap>,memtuples=0x209b310,memtupcount=0,memtupsize=1024,growmemtuples=true,slabAllocatorUsed=false,slabMemoryBegin=0x0,slabMemoryEnd=0x0,slabFreeHead=0x0,read_buffer_size=0,lastReturnedTuple=0x0,currentRun=0,mergeactive=0x0,Level=0,destTape=0,tp_fib=0x0,tp_runs=0x0,tp_dummy=0x0,tp_tapenum=0x0,activeTapes=0,result_tape=-1,current=0,eof_reached=false,markpos_block=0,markpos_offset=0,markpos_eof=false,worker=-1,shared=0x0,nParticipants=-1,tupDesc=0x208fa40,sortKeys=0x20937c0,onlyKey=0x0,abbrevNext=10,indexInfo=0x0,estate=0x0,heapRel=0x0,indexRel=0x0,enforceUnique=false,high_mask=0,low_mask=0,max_buckets=0,datumType=0,datumTypeLen=0,ru_start={tv={tv_sec=0,tv_usec=0},ru={ru_utime={tv_sec=0,tv_usec=0},ru_stime={tv_sec=0,tv_usec=0},{ru_maxrss=0,__ru_maxrss_word=0},{ru_ixrss=0,__ru_ixrss_word=0},{ru_idrss=0,__ru_idrss_word=0},{ru_isrss=0,__ru_isrss_word=0},{ru_minflt=0,__ru_minflt_word=0},{ru_majflt=0,__ru_majflt_word=0},{ru_nswap=0,__ru_nswap_word=0},{ru_inblock=0,__ru_inblock_word=0},{ru_oublock=0,__ru_oublock_word=0},{ru_msgsnd=0,__ru_msgsnd_word=0},{ru_msgrcv=0,__ru_msgrcv_word=0},{ru_nsignals=0,__ru_nsignals_word=0},{ru_nvcsw=0,__ru_nvcsw_word=0},{ru_nivcsw=0,__ru_nivcsw_word=0}}}}(gdb)

tuplesort_puttupleslot
出现在循环中

for(;;){//从outerplan中获取元组slot=ExecProcNode(outerNode);if(TupIsNull(slot))break;//直至全部获取完毕//排序tuplesort_puttupleslot(tuplesortstate,slot);}

以其中一个slot为例说明

(gdb)cContinuing.Breakpoint2,tuplesort_puttupleslot(state=0x20933a8,slot=0x208f8c8)attuplesort.c:14361436MemoryContextoldcontext=MemoryContextSwitchTo(state->sortcontext);

输入参数,state为先前调用begin_heap返回的state,slot为outer node返回的元组slot

(gdb)p*slot$12={type=T_TupleTableSlot,tts_isempty=false,tts_shouldFree=false,tts_shouldFreeMin=false,tts_slow=false,tts_tuple=0x2090678,tts_tupleDescriptor=0x7f061a300380,tts_mcxt=0x208f270,tts_buffer=103,tts_nvalid=0,tts_values=0x208f928,tts_isnull=0x208f960,tts_mintuple=0x0,tts_minhdr={t_len=0,t_self={ip_blkid={bi_hi=0,bi_lo=0},ip_posid=0},t_tableOid=0,t_data=0x0},tts_off=0,tts_fixedTupleDescriptor=true}(gdb)

slot中的元组数据

(gdb)p*slot->tts_values$13=0(gdb)p*slot->tts_tuple$14={t_len=56,t_self={ip_blkid={bi_hi=0,bi_lo=0},ip_posid=1},t_tableOid=286759,t_data=0x7f05ee0c4648}(gdb)p*slot->tts_tuple->t_data$15={t_choice={t_heap={t_xmin=839,t_xmax=0,t_field3={t_cid=0,t_xvac=0}},t_datum={datum_len_=839,datum_typmod=0,datum_typeid=0}},t_ctid={ip_blkid={bi_hi=0,bi_lo=0},ip_posid=1},t_infomask2=7,t_infomask=2306,t_hoff=24'\030',t_bits=0x7f05ee0c465f""}(gdb)p*slot->tts_tuple->t_data->t_bits$16=0'\000'(gdb)x/16ux*slot->tts_tuple->t_data->t_bits0x0:Cannotaccessmemoryataddress0x0(gdb)x/16uxslot->tts_tuple->t_data->t_bits0x7f05ee0c465f:0x5a470b000x000031300x000001000x000001000x7f05ee0c466f:0x000001000x000001000x000001000x000001000x7f05ee0c467f:0x000000000x8f2828000x000000da0x400238000x7f05ee0c468f:0x042000020x000000200x709fc8000x709f9000(gdb)x/16bxslot->tts_tuple->t_data->t_bits0x7f05ee0c465f:0x000x0b0x470x5a0x300x310x000x000x7f05ee0c4667:0x000x010x000x000x000x010x000x00(gdb)x/16bcslot->tts_tuple->t_data->t_bits0x7f05ee0c465f:0'\000'11'\v'71'G'90'Z'48'0'49'1'0'\000'0'\000'0x7f05ee0c4667:0'\000'1'\001'0'\000'0'\000'0'\000'1'\001'0'\000'0'\000'(gdb)p*slot->tts_tupleDescriptor$17={natts=7,tdtypeid=286761,tdtypmod=-1,tdhasoid=false,tdrefcount=2,constr=0x0,attrs=0x7f061a3003a0}(gdb)p*slot$18={type=T_TupleTableSlot,tts_isempty=false,tts_shouldFree=false,tts_shouldFreeMin=false,tts_slow=false,tts_tuple=0x2090678,tts_tupleDescriptor=0x7f061a300380,tts_mcxt=0x208f270,tts_buffer=103,tts_nvalid=0,tts_values=0x208f928,tts_isnull=0x208f960,tts_mintuple=0x0,tts_minhdr={t_len=0,t_self={ip_blkid={bi_hi=0,bi_lo=0},ip_posid=0},t_tableOid=0,t_data=0x0},tts_off=0,tts_fixedTupleDescriptor=true}(gdb)p*slot->tts_values[0]Cannotaccessmemoryataddress0x0(gdb)pslot->tts_values[0]$19=0(gdb)x/32bcslot->tts_tuple->t_data->t_bits0x7f05ee0c465f:0'\000'11'\v'71'G'90'Z'48'0'49'1'0'\000'0'\000'0x7f05ee0c4667:0'\000'1'\001'0'\000'0'\000'0'\000'1'\001'0'\000'0'\000'0x7f05ee0c466f:0'\000'1'\001'0'\000'0'\000'0'\000'1'\001'0'\000'0'\000'0x7f05ee0c4677:0'\000'1'\001'0'\000'0'\000'0'\000'1'\001'0'\000'0'\000'(gdb)x/32bxslot->tts_tuple->t_data->t_bits0x7f05ee0c465f:0x000x0b0x470x5a0x300x310x000x000x7f05ee0c4667:0x000x010x000x000x000x010x000x000x7f05ee0c466f:0x000x010x000x000x000x010x000x000x7f05ee0c4677:0x000x010x000x000x000x010x000x00

拷贝元组,并放到state->memtuples中

(gdb)n1443COPYTUP(state,&stup,(void*)slot);(gdb)1445puttuple_common(state,&stup);(gdb)stepputtuple_common(state=0x20933a8,tuple=0x7ffe890e0b00)attuplesort.c:16391639Assert(!LEADER(state));(gdb)n1641switch(state->status)(gdb)pstate->status$20=TSS_INITIAL(gdb)n1652if(state->memtupcount>=state->memtupsize-1)(gdb)pstate->memtupcount$21=0(gdb)pstate->memtupsize-1$22=1023(gdb)n1657state->memtuples[state->memtupcount++]=*tuple;(gdb)1671if(state->bounded&&(gdb)pstate->bounded$23=false(gdb)n1688if(state->memtupcount<state->memtupsize&&!LACKMEM(state))(gdb)1689return;(gdb)1743}(gdb)tuplesort_puttupleslot(state=0x20933a8,slot=0x208f8c8)attuplesort.c:14471447MemoryContextSwitchTo(oldcontext);(gdb)1448}(gdb)(gdb)pstate->memtuples[0]$25={tuple=0x20993d8,datum1=1,isnull1=false,tupindex=0}

tuplesort_performsort

(gdb)infobNumTypeDispEnbAddressWhat1breakpointkeepy0x0000000000a6ffa1intuplesort_begin_heapattuplesort.c:812breakpointalreadyhit1time2breakpointkeepy0x0000000000a7119dintuplesort_puttupleslotattuplesort.c:1436breakpointalreadyhit1time3breakpointkeepy0x0000000000a71f45intuplesort_performsortattuplesort.c:1792(gdb)del2(gdb)cContinuing.Breakpoint3,tuplesort_performsort(state=0x20933a8)attuplesort.c:17921792MemoryContextoldcontext=MemoryContextSwitchTo(state->sortcontext);(gdb)

输入参数

(gdb)p*state$27={status=TSS_BUILDRUNS,nKeys=2,randomAccess=false,bounded=false,boundUsed=false,bound=0,tuples=true,availMem=824360,allowedMem=4194304,maxTapes=16,tapeRange=15,sortcontext=0x2093290,tuplecontext=0x20992c0,tapeset=0x2093a00,comparetup=0xa7525b<comparetup_heap>,copytup=0xa76247<copytup_heap>,writetup=0xa76de1<writetup_heap>,readtup=0xa76ec6<readtup_heap>,memtuples=0x2611570,memtupcount=26592,memtupsize=37448,growmemtuples=false,slabAllocatorUsed=false,slabMemoryBegin=0x0,slabMemoryEnd=0x0,slabFreeHead=0x0,read_buffer_size=0,lastReturnedTuple=0x0,currentRun=2,mergeactive=0x2093878,Level=1,destTape=2,tp_fib=0x20938a0,tp_runs=0x20938f8,tp_dummy=0x2093950,tp_tapenum=0x20939a8,activeTapes=0,result_tape=-1,current=0,eof_reached=false,markpos_block=0,markpos_offset=0,markpos_eof=false,worker=-1,shared=0x0,nParticipants=-1,tupDesc=0x208fa40,sortKeys=0x20937c0,onlyKey=0x0,abbrevNext=10,indexInfo=0x0,estate=0x0,heapRel=0x0,indexRel=0x0,enforceUnique=false,high_mask=0,low_mask=0,max_buckets=0,datumType=0,datumTypeLen=0,ru_start={tv={tv_sec=0,tv_usec=0},ru={ru_utime={tv_sec=0,tv_usec=0},ru_stime={tv_sec=0,tv_usec=0},{ru_maxrss=0,__ru_maxrss_word=0},{ru_ixrss=0,__ru_ixrss_word=0},{ru_idrss=0,__ru_idrss_word=0},{ru_isrss=0,__ru_isrss_word=0},{ru_minflt=0,__ru_minflt_word=0},{ru_majflt=0,__ru_majflt_word=0},{ru_nswap=0,__ru_nswap_word=0},{ru_inblock=0,__ru_inblock_word=0},{ru_oublock=0,__ru_oublock_word=0},{ru_msgsnd=0,__ru_msgsnd_word=0},{ru_msgrcv=0,__ru_msgrcv_word=0},{ru_nsignals=0,__ru_nsignals_word=0},{ru_nvcsw=0,__ru_nvcsw_word=0},{ru_nivcsw=0,__ru_nivcsw_word=0}}}}(gdb)pstate->memtupsize$28=37448(gdb)

state->status状态已切换为TSS_BUILDRUNS

(gdb)n1795if(trace_sort)(gdb)1800switch(state->status)(gdb)pstate->status$29=TSS_BUILDRUNS(gdb)

全部刷到磁盘上,归并排序

(gdb)n1864dumptuples(state,true);(gdb)1865mergeruns(state);(gdb)1866state->eof_reached=false;(gdb)1867state->markpos_block=0L;(gdb)1868state->markpos_offset=0;(gdb)1869state->markpos_eof=false;(gdb)1870break;(gdb)1878if(trace_sort)(gdb)1890MemoryContextSwitchTo(oldcontext);(gdb)1891}(gdb)

到此,相信大家对“怎么使用PostgreSQL的tuplesort_performsort函数”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!