aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/common/tupconvert.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2018-07-13 19:54:05 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2018-07-13 19:54:05 +0300
commit42f70cd9c3dbfcdfbeea4e24d5921173d0eaab66 (patch)
treead9ba510d642e3751527a2b9ea6ceda141a2c274 /src/backend/access/common/tupconvert.c
parent130beba36d6dd46b8c527646f9f2433347cbfb11 (diff)
downloadpostgresql-42f70cd9c3dbfcdfbeea4e24d5921173d0eaab66.tar.gz
postgresql-42f70cd9c3dbfcdfbeea4e24d5921173d0eaab66.zip
Improve performance of tuple conversion map generation
Previously convert_tuples_by_name_map naively performed a search of each outdesc column starting at the first column in indesc and searched each indesc column until a match was found. When partitioned tables had many columns this could result in slow generation of the tuple conversion maps. For INSERT and UPDATE statements that touched few rows, this could mean a very large overhead indeed. We can do a bit better with this loop. It's quite likely that the columns in partitioned tables and their partitions are in the same order, so it makes sense to start searching for each column outer column at the inner column position 1 after where the previous match was found (per idea from Alexander Kuzmenkov). This makes the best case search O(N) instead of O(N^2). The worst case is still O(N^2), but it seems unlikely that would happen. Likewise, in the planner, make_inh_translation_list's search for the matching column could often end up falling back on an O(N^2) type search. This commit also improves that by first checking the column that follows the previous match, instead of the column with the same attnum. If we fail to match here we fallback on the syscache's hashtable lookup. Author: David Rowley Reviewed-by: Alexander Kuzmenkov Discussion: https://www.postgresql.org/message-id/CAKJS1f9-wijVgMdRp6_qDMEQDJJ%2BA_n%3DxzZuTmLx5Fz6cwf%2B8A%40mail.gmail.com
Diffstat (limited to 'src/backend/access/common/tupconvert.c')
-rw-r--r--src/backend/access/common/tupconvert.c36
1 files changed, 28 insertions, 8 deletions
diff --git a/src/backend/access/common/tupconvert.c b/src/backend/access/common/tupconvert.c
index 2d0d2f4b32f..3bc67b846d4 100644
--- a/src/backend/access/common/tupconvert.c
+++ b/src/backend/access/common/tupconvert.c
@@ -295,12 +295,16 @@ convert_tuples_by_name_map(TupleDesc indesc,
const char *msg)
{
AttrNumber *attrMap;
- int n;
+ int outnatts;
+ int innatts;
int i;
+ int nextindesc = -1;
- n = outdesc->natts;
- attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
- for (i = 0; i < n; i++)
+ outnatts = outdesc->natts;
+ innatts = indesc->natts;
+
+ attrMap = (AttrNumber *) palloc0(outnatts * sizeof(AttrNumber));
+ for (i = 0; i < outnatts; i++)
{
Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
char *attname;
@@ -313,10 +317,27 @@ convert_tuples_by_name_map(TupleDesc indesc,
attname = NameStr(outatt->attname);
atttypid = outatt->atttypid;
atttypmod = outatt->atttypmod;
- for (j = 0; j < indesc->natts; j++)
+
+ /*
+ * Now search for an attribute with the same name in the indesc. It
+ * seems likely that a partitioned table will have the attributes in
+ * the same order as the partition, so the search below is optimized
+ * for that case. It is possible that columns are dropped in one of
+ * the relations, but not the other, so we use the 'nextindesc'
+ * counter to track the starting point of the search. If the inner
+ * loop encounters dropped columns then it will have to skip over
+ * them, but it should leave 'nextindesc' at the correct position for
+ * the next outer loop.
+ */
+ for (j = 0; j < innatts; j++)
{
- Form_pg_attribute inatt = TupleDescAttr(indesc, j);
+ Form_pg_attribute inatt;
+ nextindesc++;
+ if (nextindesc >= innatts)
+ nextindesc = 0;
+
+ inatt = TupleDescAttr(indesc, nextindesc);
if (inatt->attisdropped)
continue;
if (strcmp(attname, NameStr(inatt->attname)) == 0)
@@ -330,7 +351,7 @@ convert_tuples_by_name_map(TupleDesc indesc,
attname,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
- attrMap[i] = (AttrNumber) (j + 1);
+ attrMap[i] = inatt->attnum;
break;
}
}
@@ -343,7 +364,6 @@ convert_tuples_by_name_map(TupleDesc indesc,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
}
-
return attrMap;
}