diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index f3344c6..daea137 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -60,15 +60,11 @@ typedef struct sequence_magic
  * session.  This is needed to hold onto nextval/currval state.  (We can't
  * rely on the relcache, since it's only, well, a cache, and may decide to
  * discard entries.)
- *
- * XXX We use linear search to find pre-existing SeqTable entries.	This is
- * good when only a small number of sequences are touched in a session, but
- * would suck with many different sequences.  Perhaps use a hashtable someday.
  */
 typedef struct SeqTableData
 {
+	Oid			relid;			/* pg_class OID of this sequence, hash key must be first */
 	struct SeqTableData *next;	/* link to next SeqTable object */
-	Oid			relid;			/* pg_class OID of this sequence */
 	Oid			filenode;		/* last seen relfilenode of this sequence */
 	LocalTransactionId lxid;	/* xact in which we last did a seq op */
 	bool		last_valid;		/* do we have a valid "last" value? */
@@ -81,7 +77,17 @@ typedef struct SeqTableData
 
 typedef SeqTableData *SeqTable;
 
-static SeqTable seqtab = NULL;	/* Head of list of SeqTable items */
+
+/*
+ * Marks threshold of the number of sequences we store in each backend
+ * in a linear list before we move the list over to a hash table.
+ * This improves performance for backends which must store many hundreds
+ * of sequences.
+ */
+#define SEQ_MOVE_TO_HASHTABLE_THRESHOLD 32
+
+static SeqTable seqlist		= NULL;	/* Head of list of SeqTable items */
+static HTAB		*seqhashtab = NULL; /* Pointer to sequence hash table */
 
 /*
  * last_used_seq is updated by nextval() to point to the last used
@@ -92,6 +98,7 @@ static SeqTableData *last_used_seq = NULL;
 static void fill_seq_with_data(Relation rel, HeapTuple tuple);
 static int64 nextval_internal(Oid relid);
 static Relation open_share_lock(SeqTable seq);
+static void switch_to_hashtable();
 static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
 static Form_pg_sequence read_seq_tuple(SeqTable elm, Relation rel,
 			   Buffer *buf, HeapTuple seqtuple);
@@ -999,6 +1006,43 @@ open_share_lock(SeqTable seq)
 }
 
 /*
+ * Change from storing sequences in a linear list fashion
+ * to storing them in a hash table for fast lookups
+ */
+static void switch_to_hashtable()
+{
+	SeqTable	next, hentry;
+	HASHCTL		ctl;
+
+	Assert(seqhashtab == NULL);
+
+	MemSet(&ctl, 0, sizeof(ctl));
+	ctl.keysize = sizeof(Oid);
+	ctl.entrysize = sizeof(SeqTableData);
+	ctl.hash = oid_hash;
+	ctl.alloc = malloc;
+
+	seqhashtab = hash_create("Sequence table", 1000, &ctl,
+		HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT);
+
+	/* Loop over the linear list and add each item into the hash table */
+	while (seqlist != NULL)
+	{
+		next = seqlist->next;
+
+		hentry = (SeqTable) hash_search(seqhashtab,
+			&seqlist->relid,
+			HASH_ENTER, NULL);
+
+		memcpy(hentry, seqlist, sizeof(SeqTableData));
+		hentry->next = NULL;
+
+		free(seqlist);
+		seqlist = next;
+	}
+}
+
+/*
  * Given a relation OID, open and lock the sequence.  p_elm and p_rel are
  * output parameters.
  */
@@ -1007,22 +1051,51 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 {
 	SeqTable	elm;
 	Relation	seqrel;
+	int			nsequences = 0;
+	bool		found = false;
+
+	/*
+	 * Most workload types will only use a small number of sequences during
+	 * their tasks. However certain workload types will have a much higher
+	 * demand on sequences. For these high demand senarios we'll store these
+	 * sequences in a hash table and since we're unable to tell initally if
+	 * the workload will use many sequences we just start out assuming it won't
+	 * and use a linear list to start of with, then if we reach
+	 * SEQ_MOVE_TO_HASHTABLE_THRESHOLD sequences then we switch over to use a
+	 * hash table.
+	 */
 
-	/* Look to see if we already have a seqtable entry for relation */
-	for (elm = seqtab; elm != NULL; elm = elm->next)
+	/* if the hash table exists then we'll search with that */
+	if (seqhashtab != NULL)
+	{
+		elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
+	}
+	else
+	{
+		/* no hash table, so perform linear search for the sequence */
+		for (elm = seqlist; elm != NULL; elm = elm->next, nsequences++)
 	{
 		if (elm->relid == relid)
+			{
+				found = true;
 			break;
 	}
+		}
 
+		if (!found)
+		{
 	/*
-	 * Allocate new seqtable entry if we didn't find one.
-	 *
-	 * NOTE: seqtable entries remain in the list for the life of a backend. If
-	 * the sequence itself is deleted then the entry becomes wasted memory,
-	 * but it's small enough that this should not matter.
+			 * if the number of sequences found in the list has reached
+			 * the threshold then we'll move the list over to a hash table
 	 */
-	if (elm == NULL)
+			if (nsequences == SEQ_MOVE_TO_HASHTABLE_THRESHOLD)
+			{
+				switch_to_hashtable();
+				elm = (SeqTable) hash_search(seqhashtab, &relid, HASH_ENTER, &found);
+
+				Assert(found == false);
+			}
+			else
 	{
 		/*
 		 * Time to make a new seqtable entry.  These entries live as long as
@@ -1033,13 +1106,29 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
 			ereport(ERROR,
 					(errcode(ERRCODE_OUT_OF_MEMORY),
 					 errmsg("out of memory")));
+
+				/* put this sequence at the top of the list */
+				elm->next = seqlist;
+				seqlist = elm;
+			}
+		}
+	}
+
+	/*
+	* Allocate new seqtable entry if we didn't find one.
+	*
+	* NOTE: With the exception of the use of DISCARD SEQUENCES or DISCARD ALL
+	* seqtable entries remain in the list for the life of a backend. If
+	* the sequence itself is deleted then the entry becomes wasted memory,
+	* but it's small enough that this should not matter.
+	*/
+	if (!found)
+	{
 		elm->relid = relid;
 		elm->filenode = InvalidOid;
 		elm->lxid = InvalidLocalTransactionId;
 		elm->last_valid = false;
 		elm->last = elm->cached = elm->increment = 0;
-		elm->next = seqtab;
-		seqtab = elm;
 	}
 
 	/*
@@ -1611,11 +1700,19 @@ ResetSequenceCaches(void)
 {
 	SeqTableData *next;
 
-	while (seqtab != NULL)
+	/* we should never have both a list and a table */
+	Assert(!(seqlist && seqhashtab));
+
+	while (seqlist != NULL)
 	{
-		next = seqtab->next;
-		free(seqtab);
-		seqtab = next;
+		next = seqlist->next;
+		free(seqlist);
+		seqlist = next;
+	}
+
+	if (seqhashtab) {
+		hash_destroy(seqhashtab);
+		seqhashtab = NULL;
 	}
 
 	last_used_seq = NULL;
