|
29 | 29 | * which saves the results in a temporary file or memory. After the
|
30 | 30 | * initial call, returns a tuple from the file with each call.
|
31 | 31 | *
|
| 32 | + * There are two distinct ways that this sort can be performed: |
| 33 | + * |
| 34 | + * 1) When the result is a single column we perform a Datum sort. |
| 35 | + * |
| 36 | + * 2) When the result contains multiple columns we perform a tuple sort. |
| 37 | + * |
| 38 | + * We could do this by always performing a tuple sort, however sorting |
| 39 | + * Datums only can be significantly faster than sorting tuples, |
| 40 | + * especially when the Datums are of a pass-by-value type. |
| 41 | + * |
32 | 42 | * Conditions:
|
33 | 43 | * -- none.
|
34 | 44 | *
|
@@ -86,31 +96,56 @@ ExecSort(PlanState *pstate)
|
86 | 96 | outerNode = outerPlanState(node);
|
87 | 97 | tupDesc = ExecGetResultType(outerNode);
|
88 | 98 |
|
89 |
| - tuplesortstate = tuplesort_begin_heap(tupDesc, |
90 |
| - plannode->numCols, |
91 |
| - plannode->sortColIdx, |
92 |
| - plannode->sortOperators, |
93 |
| - plannode->collations, |
94 |
| - plannode->nullsFirst, |
95 |
| - work_mem, |
96 |
| - NULL, |
97 |
| - node->randomAccess); |
| 99 | + if (node->datumSort) |
| 100 | + tuplesortstate = tuplesort_begin_datum(TupleDescAttr(tupDesc, 0)->atttypid, |
| 101 | + plannode->sortOperators[0], |
| 102 | + plannode->collations[0], |
| 103 | + plannode->nullsFirst[0], |
| 104 | + work_mem, |
| 105 | + NULL, |
| 106 | + node->randomAccess); |
| 107 | + else |
| 108 | + tuplesortstate = tuplesort_begin_heap(tupDesc, |
| 109 | + plannode->numCols, |
| 110 | + plannode->sortColIdx, |
| 111 | + plannode->sortOperators, |
| 112 | + plannode->collations, |
| 113 | + plannode->nullsFirst, |
| 114 | + work_mem, |
| 115 | + NULL, |
| 116 | + node->randomAccess); |
98 | 117 | if (node->bounded)
|
99 | 118 | tuplesort_set_bound(tuplesortstate, node->bound);
|
100 | 119 | node->tuplesortstate = (void *) tuplesortstate;
|
101 | 120 |
|
102 | 121 | /*
|
103 |
| - * Scan the subplan and feed all the tuples to tuplesort. |
| 122 | + * Scan the subplan and feed all the tuples to tuplesort using the |
| 123 | + * appropriate method based on the type of sort we're doing. |
104 | 124 | */
|
105 |
| - |
106 |
| - for (;;) |
| 125 | + if (node->datumSort) |
107 | 126 | {
|
108 |
| - slot = ExecProcNode(outerNode); |
109 |
| - |
110 |
| - if (TupIsNull(slot)) |
111 |
| - break; |
112 |
| - |
113 |
| - tuplesort_puttupleslot(tuplesortstate, slot); |
| 127 | + for (;;) |
| 128 | + { |
| 129 | + slot = ExecProcNode(outerNode); |
| 130 | + |
| 131 | + if (TupIsNull(slot)) |
| 132 | + break; |
| 133 | + slot_getsomeattrs(slot, 1); |
| 134 | + tuplesort_putdatum(tuplesortstate, |
| 135 | + slot->tts_values[0], |
| 136 | + slot->tts_isnull[0]); |
| 137 | + } |
| 138 | + } |
| 139 | + else |
| 140 | + { |
| 141 | + for (;;) |
| 142 | + { |
| 143 | + slot = ExecProcNode(outerNode); |
| 144 | + |
| 145 | + if (TupIsNull(slot)) |
| 146 | + break; |
| 147 | + tuplesort_puttupleslot(tuplesortstate, slot); |
| 148 | + } |
114 | 149 | }
|
115 | 150 |
|
116 | 151 | /*
|
@@ -144,15 +179,27 @@ ExecSort(PlanState *pstate)
|
144 | 179 | SO1_printf("ExecSort: %s\n",
|
145 | 180 | "retrieving tuple from tuplesort");
|
146 | 181 |
|
| 182 | + slot = node->ss.ps.ps_ResultTupleSlot; |
| 183 | + |
147 | 184 | /*
|
148 |
| - * Get the first or next tuple from tuplesort. Returns NULL if no more |
149 |
| - * tuples. Note that we only rely on slot tuple remaining valid until the |
150 |
| - * next fetch from the tuplesort. |
| 185 | + * Fetch the next sorted item from the appropriate tuplesort function. For |
| 186 | + * datum sorts we must manage the slot ourselves and leave it clear when |
| 187 | + * tuplesort_getdatum returns false to indicate there are no more datums. |
| 188 | + * For tuple sorts, tuplesort_gettupleslot manages the slot for us and |
| 189 | + * empties the slot when it runs out of tuples. |
151 | 190 | */
|
152 |
| - slot = node->ss.ps.ps_ResultTupleSlot; |
153 |
| - (void) tuplesort_gettupleslot(tuplesortstate, |
154 |
| - ScanDirectionIsForward(dir), |
155 |
| - false, slot, NULL); |
| 191 | + if (node->datumSort) |
| 192 | + { |
| 193 | + ExecClearTuple(slot); |
| 194 | + if (tuplesort_getdatum(tuplesortstate, ScanDirectionIsForward(dir), |
| 195 | + &(slot->tts_values[0]), &(slot->tts_isnull[0]), NULL)) |
| 196 | + ExecStoreVirtualTuple(slot); |
| 197 | + } |
| 198 | + else |
| 199 | + (void) tuplesort_gettupleslot(tuplesortstate, |
| 200 | + ScanDirectionIsForward(dir), |
| 201 | + false, slot, NULL); |
| 202 | + |
156 | 203 | return slot;
|
157 | 204 | }
|
158 | 205 |
|
@@ -221,6 +268,15 @@ ExecInitSort(Sort *node, EState *estate, int eflags)
|
221 | 268 | ExecInitResultTupleSlotTL(&sortstate->ss.ps, &TTSOpsMinimalTuple);
|
222 | 269 | sortstate->ss.ps.ps_ProjInfo = NULL;
|
223 | 270 |
|
| 271 | + /* |
| 272 | + * We perform a Datum sort when we're sorting just a single column, |
| 273 | + * otherwise we perform a tuple sort. |
| 274 | + */ |
| 275 | + if (ExecGetResultType(outerPlanState(sortstate))->natts == 1) |
| 276 | + sortstate->datumSort = true; |
| 277 | + else |
| 278 | + sortstate->datumSort = false; |
| 279 | + |
224 | 280 | SO1_printf("ExecInitSort: %s\n",
|
225 | 281 | "sort node initialized");
|
226 | 282 |
|
|
0 commit comments