Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6730685

Browse files
committed
Improve inheritance_planner()'s performance for large inheritance sets.
Commit c03ad56 introduced a planner performance regression for UPDATE/DELETE on large inheritance sets. It required copying the append_rel_list (which is of size proportional to the number of inherited tables) once for each inherited table, thus resulting in O(N^2) time and memory consumption. While it's difficult to avoid that in general, the extra work only has to be done for append_rel_list entries that actually reference subquery RTEs, which inheritance-set entries will not. So we can buy back essentially all of the loss in cases without subqueries in FROM; and even for those, the added work is mainly proportional to the number of UNION ALL subqueries. Back-patch to 9.2, like the previous commit. Tom Lane and Dean Rasheed, per a complaint from Thomas Munro.
1 parent 45a1d77 commit 6730685

File tree

1 file changed

+83
-6
lines changed

1 file changed

+83
-6
lines changed

src/backend/optimizer/plan/planner.c

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,8 @@ inheritance_planner(PlannerInfo *root)
765765
{
766766
Query *parse = root->parse;
767767
int parentRTindex = parse->resultRelation;
768+
Bitmapset *subqueryRTindexes;
769+
Bitmapset *modifiableARIindexes;
768770
List *final_rtable = NIL;
769771
int save_rel_array_size = 0;
770772
RelOptInfo **save_rel_array = NULL;
@@ -773,6 +775,7 @@ inheritance_planner(PlannerInfo *root)
773775
List *returningLists = NIL;
774776
List *rowMarks;
775777
ListCell *lc;
778+
Index rti;
776779

777780
/*
778781
* We generate a modified instance of the original Query for each target
@@ -788,13 +791,54 @@ inheritance_planner(PlannerInfo *root)
788791
* (1) would result in a rangetable of length O(N^2) for N targets, with
789792
* at least O(N^3) work expended here; and (2) would greatly complicate
790793
* management of the rowMarks list.
794+
*
795+
* To begin with, generate a bitmapset of the relids of the subquery RTEs.
796+
*/
797+
subqueryRTindexes = NULL;
798+
rti = 1;
799+
foreach(lc, parse->rtable)
800+
{
801+
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
802+
803+
if (rte->rtekind == RTE_SUBQUERY)
804+
subqueryRTindexes = bms_add_member(subqueryRTindexes, rti);
805+
rti++;
806+
}
807+
808+
/*
809+
* Next, we want to identify which AppendRelInfo items contain references
810+
* to any of the aforesaid subquery RTEs. These items will need to be
811+
* copied and modified to adjust their subquery references; whereas the
812+
* other ones need not be touched. It's worth being tense over this
813+
* because we can usually avoid processing most of the AppendRelInfo
814+
* items, thereby saving O(N^2) space and time when the target is a large
815+
* inheritance tree. We can identify AppendRelInfo items by their
816+
* child_relid, since that should be unique within the list.
817+
*/
818+
modifiableARIindexes = NULL;
819+
if (subqueryRTindexes != NULL)
820+
{
821+
foreach(lc, root->append_rel_list)
822+
{
823+
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
824+
825+
if (bms_is_member(appinfo->parent_relid, subqueryRTindexes) ||
826+
bms_is_member(appinfo->child_relid, subqueryRTindexes) ||
827+
bms_overlap(pull_varnos((Node *) appinfo->translated_vars),
828+
subqueryRTindexes))
829+
modifiableARIindexes = bms_add_member(modifiableARIindexes,
830+
appinfo->child_relid);
831+
}
832+
}
833+
834+
/*
835+
* And now we can get on with generating a plan for each child table.
791836
*/
792837
foreach(lc, root->append_rel_list)
793838
{
794839
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
795840
PlannerInfo subroot;
796841
Plan *subplan;
797-
Index rti;
798842

799843
/* append_rel_list contains all append rels; ignore others */
800844
if (appinfo->parent_relid != parentRTindex)
@@ -828,9 +872,29 @@ inheritance_planner(PlannerInfo *root)
828872
/*
829873
* The append_rel_list likewise might contain references to subquery
830874
* RTEs (if any subqueries were flattenable UNION ALLs). So prepare
831-
* to apply ChangeVarNodes to that, too.
875+
* to apply ChangeVarNodes to that, too. As explained above, we only
876+
* want to copy items that actually contain such references; the rest
877+
* can just get linked into the subroot's append_rel_list.
878+
*
879+
* If we know there are no such references, we can just use the outer
880+
* append_rel_list unmodified.
832881
*/
833-
subroot.append_rel_list = (List *) copyObject(root->append_rel_list);
882+
if (modifiableARIindexes != NULL)
883+
{
884+
ListCell *lc2;
885+
886+
subroot.append_rel_list = NIL;
887+
foreach(lc2, root->append_rel_list)
888+
{
889+
AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
890+
891+
if (bms_is_member(appinfo2->child_relid, modifiableARIindexes))
892+
appinfo2 = (AppendRelInfo *) copyObject(appinfo2);
893+
894+
subroot.append_rel_list = lappend(subroot.append_rel_list,
895+
appinfo2);
896+
}
897+
}
834898

835899
/*
836900
* Add placeholders to the child Query's rangetable list to fill the
@@ -850,7 +914,7 @@ inheritance_planner(PlannerInfo *root)
850914
* since subquery RTEs couldn't contain any references to the target
851915
* rel.
852916
*/
853-
if (final_rtable != NIL)
917+
if (final_rtable != NIL && subqueryRTindexes != NULL)
854918
{
855919
ListCell *lr;
856920

@@ -859,7 +923,7 @@ inheritance_planner(PlannerInfo *root)
859923
{
860924
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lr);
861925

862-
if (rte->rtekind == RTE_SUBQUERY)
926+
if (bms_is_member(rti, subqueryRTindexes))
863927
{
864928
Index newrti;
865929

@@ -872,7 +936,20 @@ inheritance_planner(PlannerInfo *root)
872936
newrti = list_length(subroot.parse->rtable) + 1;
873937
ChangeVarNodes((Node *) subroot.parse, rti, newrti, 0);
874938
ChangeVarNodes((Node *) subroot.rowMarks, rti, newrti, 0);
875-
ChangeVarNodes((Node *) subroot.append_rel_list, rti, newrti, 0);
939+
/* Skip processing unchanging parts of append_rel_list */
940+
if (modifiableARIindexes != NULL)
941+
{
942+
ListCell *lc2;
943+
944+
foreach(lc2, subroot.append_rel_list)
945+
{
946+
AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
947+
948+
if (bms_is_member(appinfo2->child_relid,
949+
modifiableARIindexes))
950+
ChangeVarNodes((Node *) appinfo2, rti, newrti, 0);
951+
}
952+
}
876953
rte = copyObject(rte);
877954
subroot.parse->rtable = lappend(subroot.parse->rtable,
878955
rte);

0 commit comments

Comments
 (0)