diff --git a/src/backend/access/hash/hashsort.c b/src/backend/access/hash/hashsort.c
index aa61e39f26..fa177272d3 100644
--- a/src/backend/access/hash/hashsort.c
+++ b/src/backend/access/hash/hashsort.c
@@ -42,9 +42,10 @@ struct HSpool
 	Relation	index;
 
 	/*
-	 * We sort the hash keys based on the buckets they belong to. Below masks
-	 * are used in _hash_hashkey2bucket to determine the bucket of given hash
-	 * key.
+	 * We sort the hash keys based on the buckets they belong to, then by
+	 * the hash values themselves, to optimize the insertion onto hash pages.
+	 * The masks below are used in _hash_hashkey2bucket to determine the
+	 * bucket of a given hash key.
 	 */
 	uint32		high_mask;
 	uint32		low_mask;
diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c
index 2933020dcc..61912a25f0 100644
--- a/src/backend/utils/sort/tuplesortvariants.c
+++ b/src/backend/utils/sort/tuplesortvariants.c
@@ -1387,6 +1387,8 @@ comparetup_index_hash(const SortTuple *a, const SortTuple *b,
 {
 	Bucket		bucket1;
 	Bucket		bucket2;
+	uint32		hash1;
+	uint32		hash2;
 	IndexTuple	tuple1;
 	IndexTuple	tuple2;
 	TuplesortPublic *base = TuplesortstateGetPublic(state);
@@ -1409,6 +1411,18 @@ comparetup_index_hash(const SortTuple *a, const SortTuple *b,
 	else if (bucket1 < bucket2)
 		return -1;
 
+	/*
+	 * If bucket values are equal, sort by hash values. This allows us to
+	 * insert directly onto bucket/overflow pages, where the index tuples
+	 * are stored in hash order to allow fast binary search within each page.
+	 */
+	hash1 = DatumGetUInt32(a->datum1);
+	hash2 = DatumGetUInt32(b->datum1);
+	if (hash1 > hash2)
+		return 1;
+	else if (hash1 < hash2)
+		return -1;
+
 	/*
 	 * If hash values are equal, we sort on ItemPointer.  This does not affect
 	 * validity of the finished index, but it may be useful to have index
