v8_poc_datum_tuple_sort.patch
application/octet-stream
Filename: v8_poc_datum_tuple_sort.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v8
| File | + | − |
|---|---|---|
| src/backend/executor/nodeSort.c | 146 | 7 |
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index b99027e0d7..f65755d019 100644
--- a/src/backend/executor/nodeSort.c
+++ b/src/backend/executor/nodeSort.c
@@ -29,6 +29,16 @@
* which saves the results in a temporary file or memory. After the
* initial call, returns a tuple from the file with each call.
*
+ * There are two distinct ways that we perform this sort:
+ *
+ * 1) When the result is a single column we perform a Datum sort.
+ *
+ * 2) When the result contains multiple columns we perform a tuple sort.
+ *
+ * We could do this by always performing a tuple sort, however sorting
+ * Datums only can be significantly faster than sorting tuples,
+ * especially when the Datums are of a byval type.
+ *
* Conditions:
* -- none.
*
@@ -37,7 +47,7 @@
* ----------------------------------------------------------------
*/
static TupleTableSlot *
-ExecSort(PlanState *pstate)
+ExecSortTuple(PlanState *pstate)
{
SortState *node = castNode(SortState, pstate);
EState *estate;
@@ -50,7 +60,7 @@ ExecSort(PlanState *pstate)
/*
* get state info from node
*/
- SO1_printf("ExecSort: %s\n",
+ SO1_printf("ExecSortTuple: %s\n",
"entering routine");
estate = node->ss.ps.state;
@@ -68,7 +78,7 @@ ExecSort(PlanState *pstate)
PlanState *outerNode;
TupleDesc tupDesc;
- SO1_printf("ExecSort: %s\n",
+ SO1_printf("ExecSortTuple: %s\n",
"sorting subplan");
/*
@@ -80,7 +90,7 @@ ExecSort(PlanState *pstate)
/*
* Initialize tuplesort module.
*/
- SO1_printf("ExecSort: %s\n",
+ SO1_printf("ExecSortTuple: %s\n",
"calling tuplesort_begin");
outerNode = outerPlanState(node);
@@ -138,10 +148,10 @@ ExecSort(PlanState *pstate)
si = &node->shared_info->sinstrument[ParallelWorkerNumber];
tuplesort_get_stats(tuplesortstate, si);
}
- SO1_printf("ExecSort: %s\n", "sorting done");
+ SO1_printf("ExecSortTuple: %s\n", "sorting done");
}
- SO1_printf("ExecSort: %s\n",
+ SO1_printf("ExecSortTuple: %s\n",
"retrieving tuple from tuplesort");
/*
@@ -156,6 +166,127 @@ ExecSort(PlanState *pstate)
return slot;
}
+static TupleTableSlot *
+ExecSortDatum(PlanState *pstate)
+{
+ SortState *node = castNode(SortState, pstate);
+ EState *estate;
+ ScanDirection dir;
+ Tuplesortstate *tuplesortstate;
+ TupleTableSlot *slot;
+
+ CHECK_FOR_INTERRUPTS();
+
+ /*
+ * get state info from node
+ */
+ SO1_printf("ExecSort: %s\n",
+ "entering routine");
+
+ estate = node->ss.ps.state;
+ dir = estate->es_direction;
+ tuplesortstate = (Tuplesortstate *) node->tuplesortstate;
+
+ /*
+ * If first time through, read all tuples from outer plan and pass them to
+ * tuplesort.c. Subsequent calls just fetch tuples from tuplesort.
+ */
+
+ if (!node->sort_Done)
+ {
+ Sort *plannode = (Sort *) node->ss.ps.plan;
+ PlanState *outerNode;
+ TupleDesc tupDesc;
+
+ SO1_printf("ExecSortDatum: %s\n",
+ "sorting subplan");
+
+ /*
+ * Want to scan subplan in the forward direction while creating the
+ * sorted data.
+ */
+ estate->es_direction = ForwardScanDirection;
+
+ /*
+ * Initialize tuplesort module.
+ */
+ SO1_printf("ExecSortDatum: %s\n",
+ "calling tuplesort_begin");
+
+ outerNode = outerPlanState(node);
+ tupDesc = ExecGetResultType(outerNode);
+
+ tuplesortstate = tuplesort_begin_datum(TupleDescAttr(tupDesc, 0)->atttypid,
+ plannode->sortOperators[0],
+ plannode->collations[0],
+ plannode->nullsFirst[0],
+ work_mem,
+ NULL,
+ node->randomAccess);
+ if (node->bounded)
+ tuplesort_set_bound(tuplesortstate, node->bound);
+ node->tuplesortstate = (void *) tuplesortstate;
+
+ /*
+ * Scan the subplan and feed all the tuples to tuplesort.
+ */
+
+ for (;;)
+ {
+ slot = ExecProcNode(outerNode);
+
+ if (TupIsNull(slot))
+ break;
+ slot_getsomeattrs(slot, 1);
+ tuplesort_putdatum(tuplesortstate,
+ slot->tts_values[0],
+ slot->tts_isnull[0]);
+ }
+
+ /*
+ * Complete the sort.
+ */
+ tuplesort_performsort(tuplesortstate);
+
+ /*
+ * restore to user specified direction
+ */
+ estate->es_direction = dir;
+
+ /*
+ * finally set the sorted flag to true
+ */
+ node->sort_Done = true;
+ node->bounded_Done = node->bounded;
+ node->bound_Done = node->bound;
+ if (node->shared_info && node->am_worker)
+ {
+ TuplesortInstrumentation *si;
+
+ Assert(IsParallelWorker());
+ Assert(ParallelWorkerNumber <= node->shared_info->num_workers);
+ si = &node->shared_info->sinstrument[ParallelWorkerNumber];
+ tuplesort_get_stats(tuplesortstate, si);
+ }
+ SO1_printf("ExecSortDatum: %s\n", "sorting done");
+ }
+
+ SO1_printf("ExecSortDatum: %s\n",
+ "retrieving datum from tuplesort");
+
+ /*
+ * Get the first or next datum from tuplesort. We clear the slot before
+ * doing this. This means when we run out of datums to get that the
+ * function returns false and the slot is left empty.
+ */
+ slot = node->ss.ps.ps_ResultTupleSlot;
+ ExecClearTuple(slot);
+ if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir),
+ &(slot->tts_values[0]), &(slot->tts_isnull[0]), NULL))
+ ExecStoreVirtualTuple(slot);
+ return slot;
+}
+
/* ----------------------------------------------------------------
* ExecInitSort
*
@@ -177,7 +308,6 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
sortstate = makeNode(SortState);
sortstate->ss.ps.plan = (Plan *) node;
sortstate->ss.ps.state = estate;
- sortstate->ss.ps.ExecProcNode = ExecSort;
/*
* We must have random access to the sort output to do backward scan or
@@ -221,6 +351,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
sortstate->ss.ps.ps_ProjInfo = NULL;
+ /*
+ * We perform a Datum sort when we're sorting just a single column,
+ * otherwise we perform a tuple sort.
+ */
+ if (ExecGetResultType(outerPlanState(sortstate))->natts == 1)
+ sortstate->ss.ps.ExecProcNode = ExecSortDatum;
+ else
+ sortstate->ss.ps.ExecProcNode = ExecSortTuple;
+
SO1_printf("ExecInitSort: %s\n",
"sort node initialized");