diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index dae7a842a1..7f4cc2add8 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -68,6 +68,7 @@ static Bitmapset *get_eclass_indexes_for_relids(PlannerInfo *root,
 							  Relids relids);
 static void delete_eclass(PlannerInfo *root, EquivalenceClass *ec,
 			  int ec_index);
+static ListCell *list_skip_forward(ListCell *lc, int forward);
 
 
 /*
@@ -1131,7 +1132,8 @@ generate_join_implied_equalities_for_ecs(PlannerInfo *root,
 	Bitmapset  *inner_ecs;
 	Bitmapset  *join_ecs;
 	Bitmapset  *matching_ecs;
-	int			i;
+	int			i, last;
+	ListCell   *lc;
 
 	/* If inner rel is a child, extra setup work is needed */
 	if (IS_OTHER_REL(inner_rel))
@@ -1155,12 +1157,18 @@ generate_join_implied_equalities_for_ecs(PlannerInfo *root,
 	/* Determine all eclasses in common between inner rels and join rels */
 	matching_ecs = bms_int_members(inner_ecs, join_ecs);
 
+	lc = list_head(root->eq_classes);
+	last = 0;
 	i = -1;
 	while ((i = bms_next_member(matching_ecs, i)) >= 0)
 	{
-		EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		EquivalenceClass *ec;
 		List	   *sublist = NIL;
 
+		lc = list_skip_forward(lc, i - last);
+		last = i;
+		ec = (EquivalenceClass *) lfirst(lc);
+
 		/* ECs containing consts do not need any further enforcement */
 		if (ec->ec_has_const)
 			continue;
@@ -2080,19 +2088,26 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
 	Oid			eqop = fkinfo->conpfeqop[colno];
 	List	   *opfamilies = NIL;	/* compute only if needed */
 	Bitmapset  *matching_ecs;
-	int			i;
+	int			i, last;
+	ListCell   *lc;
 
 	/* Determine which eclasses contain members for both of the relations */
 	matching_ecs = bms_intersect(root->simple_rel_array[var1varno]->eclass_indexes,
 								 root->simple_rel_array[var2varno]->eclass_indexes);
 
+	lc = list_head(root->eq_classes);
+	last = 0;
 	i = -1;
 	while ((i = bms_next_member(matching_ecs, i)) >= 0)
 	{
-		EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		EquivalenceClass *ec;
 		bool		item1member = false;
 		bool		item2member = false;
-		ListCell   *lc;
+		ListCell   *lc2;
+
+		lc = list_skip_forward(lc, i - last);
+		last = i;
+		ec = (EquivalenceClass *) lfirst(lc);
 
 		/* Never match to a volatile EC */
 		if (ec->ec_has_volatile)
@@ -2102,9 +2117,9 @@ match_eclasses_to_foreign_key_col(PlannerInfo *root,
 		/* Ensure no corruption of eclass_indexes */
 		Assert(bms_is_member(var1varno, ec->ec_relids));
 		Assert(bms_is_member(var2varno, ec->ec_relids));
-		foreach(lc, ec->ec_members)
+		foreach(lc2, ec->ec_members)
 		{
-			EquivalenceMember *em = (EquivalenceMember *) lfirst(lc);
+			EquivalenceMember *em = (EquivalenceMember *) lfirst(lc2);
 			Var		   *var;
 
 			if (em->em_is_child)
@@ -2273,7 +2288,8 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 	List	   *result = NIL;
 	bool		is_child_rel = (rel->reloptkind == RELOPT_OTHER_MEMBER_REL);
 	Relids		parent_relids;
-	int			i;
+	int			i, last;
+	ListCell   *lc;
 
 	/* Indexes are available only on base or "other" member relations. */
 	Assert(IS_SIMPLE_REL(rel));
@@ -2284,12 +2300,18 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 	else
 		parent_relids = NULL;	/* not used, but keep compiler quiet */
 
+	lc = list_head(root->eq_classes);
+	last = 0;
 	i = -1;
 	while ((i = bms_next_member(rel->eclass_indexes, i)) >= 0)
 	{
-		EquivalenceClass *cur_ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		EquivalenceClass *cur_ec;
 		EquivalenceMember *cur_em;
-		ListCell   *lc;
+		ListCell   *lc2;
+
+		lc = list_skip_forward(lc, i - last);
+		last = i;
+		cur_ec = (EquivalenceClass *) lfirst(lc);
 
 		/*
 		 * Won't generate joinclauses if const or single-member (the latter
@@ -2316,9 +2338,9 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		 * match.  See also get_eclass_for_sort_expr.)
 		 */
 		cur_em = NULL;
-		foreach(lc, cur_ec->ec_members)
+		foreach(lc2, cur_ec->ec_members)
 		{
-			cur_em = (EquivalenceMember *) lfirst(lc);
+			cur_em = (EquivalenceMember *) lfirst(lc2);
 			if (bms_equal(cur_em->em_relids, rel->relids) &&
 				callback(root, rel, cur_ec, cur_em, callback_arg))
 				break;
@@ -2332,9 +2354,9 @@ generate_implied_equalities_for_column(PlannerInfo *root,
 		 * Found our match.  Scan the other EC members and attempt to generate
 		 * joinclauses.
 		 */
-		foreach(lc, cur_ec->ec_members)
+		foreach(lc2, cur_ec->ec_members)
 		{
-			EquivalenceMember *other_em = (EquivalenceMember *) lfirst(lc);
+			EquivalenceMember *other_em = (EquivalenceMember *) lfirst(lc2);
 			Oid			eq_op;
 			RestrictInfo *rinfo;
 
@@ -2401,7 +2423,8 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
 	Bitmapset	   *rel1_ecs;
 	Bitmapset	   *rel2_ecs;
 	Bitmapset	   *matching_ecs;
-	int				i;
+	int				i, last;
+	ListCell	   *lc;
 
 	rel1_ecs = get_eclass_indexes_for_relids(root, rel1->relids);
 	rel2_ecs = get_eclass_indexes_for_relids(root, rel2->relids);
@@ -2409,10 +2432,16 @@ have_relevant_eclass_joinclause(PlannerInfo *root,
 
 	/* XXX or can we just return bms_overlap(rel1_ecs, rel2_ecs) ? */
 
+	lc = list_head(root->eq_classes);
+	last = 0;
 	i = -1;
 	while ((i = bms_next_member(matching_ecs, i)) >= 0)
 	{
-		EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		EquivalenceClass *ec;
+
+		lc = list_skip_forward(lc, i - last);
+		last = i;
+		ec = (EquivalenceClass *) lfirst(lc);
 
 		/*
 		 * Won't generate joinclauses if single-member (this test covers the
@@ -2468,18 +2497,24 @@ bool
 has_relevant_eclass_joinclause(PlannerInfo *root, RelOptInfo *rel1)
 {
 	Bitmapset	   *matched_ecs;
-	int				i;
+	int			i, last;
+	ListCell   *lc;
 
 	if (IS_SIMPLE_REL(rel1))
 		matched_ecs = rel1->eclass_indexes;
 	else
 		matched_ecs = get_eclass_indexes_for_relids(root, rel1->relids);
 
+	lc = list_head(root->eq_classes);
+	last = 0;
 	i = -1;
 	while ((i = bms_next_member(matched_ecs, i)) >= 0)
 	{
-		EquivalenceClass *ec = (EquivalenceClass *) list_nth(root->eq_classes, i);
+		EquivalenceClass *ec;
 
+		lc = list_skip_forward(lc, i - last);
+		last = i;
+		ec = (EquivalenceClass *) lfirst(lc);
 		/*
 		 * Won't generate joinclauses if single-member (this test covers the
 		 * volatile case too)
@@ -2716,3 +2751,12 @@ delete_eclass(PlannerInfo *root, EquivalenceClass *ec, int ec_index)
 	ec->ec_derives = NIL;
 	ec->ec_relids = NULL;
 }
+
+/* XXX remove when list_nth is O(1) */
+static ListCell *
+list_skip_forward(ListCell *lc, int forward)
+{
+	while (forward--)
+		lc = lnext(lc);
+	return lc;
+}
