Skip to content

Commit d8f9ab7

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 d1c1e48 commit d8f9ab7

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
@@ -787,6 +787,8 @@ inheritance_planner(PlannerInfo *root)
787787
{
788788
Query *parse = root->parse;
789789
int parentRTindex = parse->resultRelation;
790+
Bitmapset *subqueryRTindexes;
791+
Bitmapset *modifiableARIindexes;
790792
List *final_rtable = NIL;
791793
int save_rel_array_size = 0;
792794
RelOptInfo **save_rel_array = NULL;
@@ -796,6 +798,7 @@ inheritance_planner(PlannerInfo *root)
796798
List *returningLists = NIL;
797799
List *rowMarks;
798800
ListCell *lc;
801+
Index rti;
799802

800803
/*
801804
* We generate a modified instance of the original Query for each target
@@ -811,13 +814,54 @@ inheritance_planner(PlannerInfo *root)
811814
* (1) would result in a rangetable of length O(N^2) for N targets, with
812815
* at least O(N^3) work expended here; and (2) would greatly complicate
813816
* management of the rowMarks list.
817+
*
818+
* To begin with, generate a bitmapset of the relids of the subquery RTEs.
819+
*/
820+
subqueryRTindexes = NULL;
821+
rti = 1;
822+
foreach(lc, parse->rtable)
823+
{
824+
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc);
825+
826+
if (rte->rtekind == RTE_SUBQUERY)
827+
subqueryRTindexes = bms_add_member(subqueryRTindexes, rti);
828+
rti++;
829+
}
830+
831+
/*
832+
* Next, we want to identify which AppendRelInfo items contain references
833+
* to any of the aforesaid subquery RTEs. These items will need to be
834+
* copied and modified to adjust their subquery references; whereas the
835+
* other ones need not be touched. It's worth being tense over this
836+
* because we can usually avoid processing most of the AppendRelInfo
837+
* items, thereby saving O(N^2) space and time when the target is a large
838+
* inheritance tree. We can identify AppendRelInfo items by their
839+
* child_relid, since that should be unique within the list.
840+
*/
841+
modifiableARIindexes = NULL;
842+
if (subqueryRTindexes != NULL)
843+
{
844+
foreach(lc, root->append_rel_list)
845+
{
846+
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
847+
848+
if (bms_is_member(appinfo->parent_relid, subqueryRTindexes) ||
849+
bms_is_member(appinfo->child_relid, subqueryRTindexes) ||
850+
bms_overlap(pull_varnos((Node *) appinfo->translated_vars),
851+
subqueryRTindexes))
852+
modifiableARIindexes = bms_add_member(modifiableARIindexes,
853+
appinfo->child_relid);
854+
}
855+
}
856+
857+
/*
858+
* And now we can get on with generating a plan for each child table.
814859
*/
815860
foreach(lc, root->append_rel_list)
816861
{
817862
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc);
818863
PlannerInfo subroot;
819864
Plan *subplan;
820-
Index rti;
821865

822866
/* append_rel_list contains all append rels; ignore others */
823867
if (appinfo->parent_relid != parentRTindex)
@@ -851,9 +895,29 @@ inheritance_planner(PlannerInfo *root)
851895
/*
852896
* The append_rel_list likewise might contain references to subquery
853897
* RTEs (if any subqueries were flattenable UNION ALLs). So prepare
854-
* to apply ChangeVarNodes to that, too.
898+
* to apply ChangeVarNodes to that, too. As explained above, we only
899+
* want to copy items that actually contain such references; the rest
900+
* can just get linked into the subroot's append_rel_list.
901+
*
902+
* If we know there are no such references, we can just use the outer
903+
* append_rel_list unmodified.
855904
*/
856-
subroot.append_rel_list = (List *) copyObject(root->append_rel_list);
905+
if (modifiableARIindexes != NULL)
906+
{
907+
ListCell *lc2;
908+
909+
subroot.append_rel_list = NIL;
910+
foreach(lc2, root->append_rel_list)
911+
{
912+
AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
913+
914+
if (bms_is_member(appinfo2->child_relid, modifiableARIindexes))
915+
appinfo2 = (AppendRelInfo *) copyObject(appinfo2);
916+
917+
subroot.append_rel_list = lappend(subroot.append_rel_list,
918+
appinfo2);
919+
}
920+
}
857921

858922
/*
859923
* Add placeholders to the child Query's rangetable list to fill the
@@ -873,7 +937,7 @@ inheritance_planner(PlannerInfo *root)
873937
* since subquery RTEs couldn't contain any references to the target
874938
* rel.
875939
*/
876-
if (final_rtable != NIL)
940+
if (final_rtable != NIL && subqueryRTindexes != NULL)
877941
{
878942
ListCell *lr;
879943

@@ -882,7 +946,7 @@ inheritance_planner(PlannerInfo *root)
882946
{
883947
RangeTblEntry *rte = (RangeTblEntry *) lfirst(lr);
884948

885-
if (rte->rtekind == RTE_SUBQUERY)
949+
if (bms_is_member(rti, subqueryRTindexes))
886950
{
887951
Index newrti;
888952

@@ -895,7 +959,20 @@ inheritance_planner(PlannerInfo *root)
895959
newrti = list_length(subroot.parse->rtable) + 1;
896960
ChangeVarNodes((Node *) subroot.parse, rti, newrti, 0);
897961
ChangeVarNodes((Node *) subroot.rowMarks, rti, newrti, 0);
898-
ChangeVarNodes((Node *) subroot.append_rel_list, rti, newrti, 0);
962+
/* Skip processing unchanging parts of append_rel_list */
963+
if (modifiableARIindexes != NULL)
964+
{
965+
ListCell *lc2;
966+
967+
foreach(lc2, subroot.append_rel_list)
968+
{
969+
AppendRelInfo *appinfo2 = (AppendRelInfo *) lfirst(lc2);
970+
971+
if (bms_is_member(appinfo2->child_relid,
972+
modifiableARIindexes))
973+
ChangeVarNodes((Node *) appinfo2, rti, newrti, 0);
974+
}
975+
}
899976
rte = copyObject(rte);
900977
subroot.parse->rtable = lappend(subroot.parse->rtable,
901978
rte);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy