Commit 8b304b8b authored by Robert Haas's avatar Robert Haas

Remove replacement selection sort.

At the time replacement_sort_tuples was introduced, there were still
cases where replacement selection sort noticeably outperformed using
quicksort even for the first run.  However, those cases seem to have
evaporated as a result of further improvements made since that time
(and perhaps also advances in CPU technology).  So remove replacement
selection and the controlling GUC entirely.  This makes tuplesort.c
noticeably simpler and probably paves the way for further
optimizations someone might want to do later.

Peter Geoghegan, with review and testing by Tomas Vondra and me.

Discussion: https://postgr.es/m/CAH2-WzmmNjG_K0R9nqYwMq3zjyJJK+hCbiZYNGhAy-Zyjs64GQ@mail.gmail.com
parent d2773f9b
......@@ -1505,45 +1505,6 @@ include_dir 'conf.d'
</listitem>
</varlistentry>
<varlistentry id="guc-replacement-sort-tuples" xreflabel="replacement_sort_tuples">
<term><varname>replacement_sort_tuples</varname> (<type>integer</type>)
<indexterm>
<primary><varname>replacement_sort_tuples</> configuration parameter</primary>
</indexterm>
</term>
<listitem>
<para>
When the number of tuples to be sorted is smaller than this number,
a sort will produce its first output run using replacement selection
rather than quicksort. This may be useful in memory-constrained
environments where tuples that are input into larger sort operations
have a strong physical-to-logical correlation. Note that this does
not include input tuples with an <emphasis>inverse</emphasis>
correlation. It is possible for the replacement selection algorithm
to generate one long run that requires no merging, where use of the
default strategy would result in many runs that must be merged
to produce a final sorted output. This may allow sort
operations to complete sooner.
</para>
<para>
The default is 150,000 tuples. Note that higher values are typically
not much more effective, and may be counter-productive, since the
priority queue is sensitive to the size of available CPU cache, whereas
the default strategy sorts runs using a <firstterm>cache
oblivious</firstterm> algorithm. This property allows the default sort
strategy to automatically and transparently make effective use
of available CPU cache.
</para>
<para>
Setting <varname>maintenance_work_mem</varname> to its default
value usually prevents utility command external sorts (e.g.,
sorts used by <command>CREATE INDEX</> to build B-Tree
indexes) from ever using replacement selection sort, unless the
input tuples are quite wide.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-autovacuum-work-mem" xreflabel="autovacuum_work_mem">
<term><varname>autovacuum_work_mem</varname> (<type>integer</type>)
<indexterm>
......
......@@ -5140,7 +5140,7 @@ and many others in the same vein
The new approach makes better use of the <acronym>CPU</> cache
for typical cache sizes and data volumes. Where necessary,
the behavior can be adjusted via the new configuration parameter
<xref linkend="guc-replacement-sort-tuples">.
<literal>replacement_sort_tuples</literal>.
</para>
</listitem>
......
......@@ -112,7 +112,6 @@ bool enableFsync = true;
bool allowSystemTableMods = false;
int work_mem = 1024;
int maintenance_work_mem = 16384;
int replacement_sort_tuples = 150000;
/*
* Primary determinants of sizes of shared-memory structures.
......
......@@ -1933,16 +1933,6 @@ static struct config_int ConfigureNamesInt[] =
NULL, NULL, NULL
},
{
{"replacement_sort_tuples", PGC_USERSET, RESOURCES_MEM,
gettext_noop("Sets the maximum number of tuples to be sorted using replacement selection."),
gettext_noop("When more tuples than this are present, quicksort will be used.")
},
&replacement_sort_tuples,
150000, 0, INT_MAX,
NULL, NULL, NULL
},
/*
* We use the hopefully-safely-small value of 100kB as the compiled-in
* default for max_stack_depth. InitializeGUCOptions will increase it if
......
......@@ -121,7 +121,6 @@
# you actively intend to use prepared transactions.
#work_mem = 4MB # min 64kB
#maintenance_work_mem = 64MB # min 1MB
#replacement_sort_tuples = 150000 # limits use of replacement selection sort
#autovacuum_work_mem = -1 # min 1MB, or -1 to use maintenance_work_mem
#max_stack_depth = 2MB # min 100kB
#dynamic_shared_memory_type = posix # the default is the first option
......
This diff is collapsed.
......@@ -241,7 +241,6 @@ extern bool enableFsync;
extern bool allowSystemTableMods;
extern PGDLLIMPORT int work_mem;
extern PGDLLIMPORT int maintenance_work_mem;
extern PGDLLIMPORT int replacement_sort_tuples;
extern int VacuumCostPageHit;
extern int VacuumCostPageMiss;
......
......@@ -444,22 +444,8 @@ create table clstr_4 as select * from tenk1;
create index cluster_sort on clstr_4 (hundred, thousand, tenthous);
-- ensure we don't use the index in CLUSTER nor the checking SELECTs
set enable_indexscan = off;
-- Use external sort that only ever uses quicksort to sort runs:
-- Use external sort:
set maintenance_work_mem = '1MB';
set replacement_sort_tuples = 0;
cluster clstr_4 using cluster_sort;
select * from
(select hundred, lag(hundred) over () as lhundred,
thousand, lag(thousand) over () as lthousand,
tenthous, lag(tenthous) over () as ltenthous from clstr_4) ss
where row(hundred, thousand, tenthous) <= row(lhundred, lthousand, ltenthous);
hundred | lhundred | thousand | lthousand | tenthous | ltenthous
---------+----------+----------+-----------+----------+-----------
(0 rows)
-- Replacement selection will now be forced. It should only produce a single
-- run, due to the fact that input is found to be presorted:
set replacement_sort_tuples = 150000;
cluster clstr_4 using cluster_sort;
select * from
(select hundred, lag(hundred) over () as lhundred,
......@@ -472,7 +458,6 @@ where row(hundred, thousand, tenthous) <= row(lhundred, lthousand, ltenthous);
reset enable_indexscan;
reset maintenance_work_mem;
reset replacement_sort_tuples;
-- clean up
DROP TABLE clustertest;
DROP TABLE clstr_1;
......
......@@ -203,19 +203,8 @@ create index cluster_sort on clstr_4 (hundred, thousand, tenthous);
-- ensure we don't use the index in CLUSTER nor the checking SELECTs
set enable_indexscan = off;
-- Use external sort that only ever uses quicksort to sort runs:
-- Use external sort:
set maintenance_work_mem = '1MB';
set replacement_sort_tuples = 0;
cluster clstr_4 using cluster_sort;
select * from
(select hundred, lag(hundred) over () as lhundred,
thousand, lag(thousand) over () as lthousand,
tenthous, lag(tenthous) over () as ltenthous from clstr_4) ss
where row(hundred, thousand, tenthous) <= row(lhundred, lthousand, ltenthous);
-- Replacement selection will now be forced. It should only produce a single
-- run, due to the fact that input is found to be presorted:
set replacement_sort_tuples = 150000;
cluster clstr_4 using cluster_sort;
select * from
(select hundred, lag(hundred) over () as lhundred,
......@@ -225,7 +214,6 @@ where row(hundred, thousand, tenthous) <= row(lhundred, lthousand, ltenthous);
reset enable_indexscan;
reset maintenance_work_mem;
reset replacement_sort_tuples;
-- clean up
DROP TABLE clustertest;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment