aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeSort.c106
-rw-r--r--src/include/nodes/execnodes.h1
2 files changed, 82 insertions, 25 deletions
diff --git a/src/backend/executor/nodeSort.c b/src/backend/executor/nodeSort.c
index b99027e0d7f..c68d9e41c2e 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 this sort can be performed:
+ *
+ * 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 pass-by-value type.
+ *
* Conditions:
* -- none.
*
@@ -86,31 +96,56 @@ ExecSort(PlanState *pstate)
outerNode = outerPlanState(node);
tupDesc = ExecGetResultType(outerNode);
- tuplesortstate = tuplesort_begin_heap(tupDesc,
- plannode->numCols,
- plannode->sortColIdx,
- plannode->sortOperators,
- plannode->collations,
- plannode->nullsFirst,
- work_mem,
- NULL,
- node->randomAccess);
+ if (node->datumSort)
+ tuplesortstate = tuplesort_begin_datum(TupleDescAttr(tupDesc, 0)->atttypid,
+ plannode->sortOperators[0],
+ plannode->collations[0],
+ plannode->nullsFirst[0],
+ work_mem,
+ NULL,
+ node->randomAccess);
+ else
+ tuplesortstate = tuplesort_begin_heap(tupDesc,
+ plannode->numCols,
+ plannode->sortColIdx,
+ plannode->sortOperators,
+ plannode->collations,
+ plannode->nullsFirst,
+ 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.
+ * Scan the subplan and feed all the tuples to tuplesort using the
+ * appropriate method based on the type of sort we're doing.
*/
-
- for (;;)
+ if (node->datumSort)
{
- slot = ExecProcNode(outerNode);
-
- if (TupIsNull(slot))
- break;
-
- tuplesort_puttupleslot(tuplesortstate, slot);
+ for (;;)
+ {
+ slot = ExecProcNode(outerNode);
+
+ if (TupIsNull(slot))
+ break;
+ slot_getsomeattrs(slot, 1);
+ tuplesort_putdatum(tuplesortstate,
+ slot->tts_values[0],
+ slot->tts_isnull[0]);
+ }
+ }
+ else
+ {
+ for (;;)
+ {
+ slot = ExecProcNode(outerNode);
+
+ if (TupIsNull(slot))
+ break;
+ tuplesort_puttupleslot(tuplesortstate, slot);
+ }
}
/*
@@ -144,15 +179,27 @@ ExecSort(PlanState *pstate)
SO1_printf("ExecSort: %s\n",
"retrieving tuple from tuplesort");
+ slot = node->ss.ps.ps_ResultTupleSlot;
+
/*
- * Get the first or next tuple from tuplesort. Returns NULL if no more
- * tuples. Note that we only rely on slot tuple remaining valid until the
- * next fetch from the tuplesort.
+ * Fetch the next sorted item from the appropriate tuplesort function. For
+ * datum sorts we must manage the slot ourselves and leave it clear when
+ * tuplesort_getdatum returns false to indicate there are no more datums.
+ * For tuple sorts, tuplesort_gettupleslot manages the slot for us and
+ * empties the slot when it runs out of tuples.
*/
- slot = node->ss.ps.ps_ResultTupleSlot;
- (void) tuplesort_gettupleslot(tuplesortstate,
- ScanDirectionIsForward(dir),
- false, slot, NULL);
+ if (node->datumSort)
+ {
+ ExecClearTuple(slot);
+ if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir),
+ &(slot->tts_values[0]), &(slot->tts_isnull[0]), NULL))
+ ExecStoreVirtualTuple(slot);
+ }
+ else
+ (void) tuplesort_gettupleslot(tuplesortstate,
+ ScanDirectionIsForward(dir),
+ false, slot, NULL);
+
return slot;
}
@@ -221,6 +268,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->datumSort = true;
+ else
+ sortstate->datumSort = false;
+
SO1_printf("ExecInitSort: %s\n",
"sort node initialized");
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index ffc78447563..37cb4f3d59a 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -2151,6 +2151,7 @@ typedef struct SortState
int64 bound_Done; /* value of bound we did the sort with */
void *tuplesortstate; /* private state of tuplesort.c */
bool am_worker; /* are we a worker? */
+ bool datumSort; /* Datum sort instead of tuple sort? */
SharedSortInfo *shared_info; /* one entry per worker */
} SortState;