On Sat, 10 Oct 2020 at 15:45, Hou, Zhijie <houzj.f...@cn.fujitsu.com> wrote: > I found some code places call list_delete_ptr can be replaced by > list_delete_xxxcell which can be faster. > > diff --git a/src/backend/optimizer/path/joinpath.c > b/src/backend/optimizer/path/joinpath.c > index db54a6b..61ef7c8 100644 > --- a/src/backend/optimizer/path/joinpath.c > +++ b/src/backend/optimizer/path/joinpath.c > @@ -1005,8 +1005,8 @@ sort_inner_and_outer(PlannerInfo *root, > /* Make a pathkey list with this guy first */ > if (l != list_head(all_pathkeys)) > outerkeys = lcons(front_pathkey, > - > list_delete_ptr(list_copy(all_pathkeys), > - > front_pathkey)); > + > list_delete_nth_cell(list_copy(all_pathkeys), > + > foreach_current_index(l))); > else > outerkeys = all_pathkeys; /* no work at first > one... */
That looks ok to me. It would be more optimal if we had a method to move an element to the front of a list, or to any specified position, but I can't imagine it's worth making such a function just for that. So what you have there seems fine. > diff --git a/src/backend/rewrite/rewriteHandler.c > b/src/backend/rewrite/rewriteHandler.c > index fe777c3..d0f15b8 100644 > --- a/src/backend/rewrite/rewriteHandler.c > +++ b/src/backend/rewrite/rewriteHandler.c > @@ -650,7 +650,7 @@ adjustJoinTreeList(Query *parsetree, bool removert, int > rt_index) > if (IsA(rtr, RangeTblRef) && > rtr->rtindex == rt_index) > { > - newjointree = list_delete_ptr(newjointree, > rtr); > + newjointree = list_delete_cell(newjointree, > l); I think you may as well just use newjointree = foreach_delete_current(newjointree, l);. The comment about why the list_delete is ok inside a foreach is then irrelevant since foreach_delete_current() is designed for deleting the current foreach cell. Looking around for other places I found two more in equivclass.c. These two do require an additional moving part to keep track of the index we want to delete, so they're not quite as clear cut a win to do. However, I don't think tracking the index makes the code overly complex, so I'm thinking they're both fine to do. Does anyone think differently? Updated patch attached. David
diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c index 823422edad..690b753369 100644 --- a/src/backend/optimizer/path/equivclass.c +++ b/src/backend/optimizer/path/equivclass.c @@ -137,6 +137,7 @@ process_equivalence(PlannerInfo *root, EquivalenceMember *em1, *em2; ListCell *lc1; + int ec2_idx; /* Should not already be marked as having generated an eclass */ Assert(restrictinfo->left_ec == NULL); @@ -258,6 +259,7 @@ process_equivalence(PlannerInfo *root, */ ec1 = ec2 = NULL; em1 = em2 = NULL; + ec2_idx = -1; foreach(lc1, root->eq_classes) { EquivalenceClass *cur_ec = (EquivalenceClass *) lfirst(lc1); @@ -311,6 +313,7 @@ process_equivalence(PlannerInfo *root, equal(item2, cur_em->em_expr)) { ec2 = cur_ec; + ec2_idx = foreach_current_index(lc1); em2 = cur_em; if (ec1) break; @@ -371,7 +374,7 @@ process_equivalence(PlannerInfo *root, ec1->ec_max_security = Max(ec1->ec_max_security, ec2->ec_max_security); ec2->ec_merged = ec1; - root->eq_classes = list_delete_ptr(root->eq_classes, ec2); + root->eq_classes = list_delete_nth_cell(root->eq_classes, ec2_idx); /* just to avoid debugging confusion w/ dangling pointers: */ ec2->ec_members = NIL; ec2->ec_sources = NIL; @@ -1964,6 +1967,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) bool matchleft; bool matchright; ListCell *lc2; + int coal_idx = -1; /* Ignore EC unless it contains pseudoconstants */ if (!cur_ec->ec_has_const) @@ -2008,6 +2012,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) if (equal(leftvar, cfirst) && equal(rightvar, csecond)) { + coal_idx = foreach_current_index(lc2); match = true; break; } @@ -2072,7 +2077,7 @@ reconsider_full_join_clause(PlannerInfo *root, RestrictInfo *rinfo) */ if (matchleft && matchright) { - cur_ec->ec_members = list_delete_ptr(cur_ec->ec_members, coal_em); + cur_ec->ec_members = list_delete_nth_cell(cur_ec->ec_members, coal_idx); return true; } diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index db54a6ba2e..4a35903b29 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -1005,8 +1005,8 @@ sort_inner_and_outer(PlannerInfo *root, /* Make a pathkey list with this guy first */ if (l != list_head(all_pathkeys)) outerkeys = lcons(front_pathkey, - list_delete_ptr(list_copy(all_pathkeys), - front_pathkey)); + list_delete_nth_cell(list_copy(all_pathkeys), + foreach_current_index(l))); else outerkeys = all_pathkeys; /* no work at first one... */ diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index fe777c3103..1faaafab08 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -650,11 +650,7 @@ adjustJoinTreeList(Query *parsetree, bool removert, int rt_index) if (IsA(rtr, RangeTblRef) && rtr->rtindex == rt_index) { - newjointree = list_delete_ptr(newjointree, rtr); - - /* - * foreach is safe because we exit loop after list_delete... - */ + newjointree = foreach_delete_current(newjointree, l); break; } }