Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit42f70cd

Browse files
committed
Improve performance of tuple conversion map generation
Previously convert_tuples_by_name_map naively performed a search of eachoutdesc column starting at the first column in indesc and searched eachindesc column until a match was found. When partitioned tables had manycolumns this could result in slow generation of the tuple conversion maps.For INSERT and UPDATE statements that touched few rows, this could mean avery large overhead indeed.We can do a bit better with this loop. It's quite likely that the columnsin partitioned tables and their partitions are in the same order, so itmakes sense to start searching for each column outer column at the innercolumn position 1 after where the previous match was found (per idea fromAlexander Kuzmenkov). This makes the best case search O(N) instead ofO(N^2). The worst case is still O(N^2), but it seems unlikely that wouldhappen.Likewise, in the planner, make_inh_translation_list's search for thematching 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 followsthe previous match, instead of the column with the same attnum. If wefail to match here we fallback on the syscache's hashtable lookup.Author: David RowleyReviewed-by: Alexander KuzmenkovDiscussion:https://www.postgresql.org/message-id/CAKJS1f9-wijVgMdRp6_qDMEQDJJ%2BA_n%3DxzZuTmLx5Fz6cwf%2B8A%40mail.gmail.com
1 parent130beba commit42f70cd

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

‎src/backend/access/common/tupconvert.c

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,12 +295,16 @@ convert_tuples_by_name_map(TupleDesc indesc,
295295
constchar*msg)
296296
{
297297
AttrNumber*attrMap;
298-
intn;
298+
intoutnatts;
299+
intinnatts;
299300
inti;
301+
intnextindesc=-1;
300302

301-
n=outdesc->natts;
302-
attrMap= (AttrNumber*)palloc0(n*sizeof(AttrNumber));
303-
for (i=0;i<n;i++)
303+
outnatts=outdesc->natts;
304+
innatts=indesc->natts;
305+
306+
attrMap= (AttrNumber*)palloc0(outnatts*sizeof(AttrNumber));
307+
for (i=0;i<outnatts;i++)
304308
{
305309
Form_pg_attributeoutatt=TupleDescAttr(outdesc,i);
306310
char*attname;
@@ -313,10 +317,27 @@ convert_tuples_by_name_map(TupleDesc indesc,
313317
attname=NameStr(outatt->attname);
314318
atttypid=outatt->atttypid;
315319
atttypmod=outatt->atttypmod;
316-
for (j=0;j<indesc->natts;j++)
320+
321+
/*
322+
* Now search for an attribute with the same name in the indesc. It
323+
* seems likely that a partitioned table will have the attributes in
324+
* the same order as the partition, so the search below is optimized
325+
* for that case. It is possible that columns are dropped in one of
326+
* the relations, but not the other, so we use the 'nextindesc'
327+
* counter to track the starting point of the search. If the inner
328+
* loop encounters dropped columns then it will have to skip over
329+
* them, but it should leave 'nextindesc' at the correct position for
330+
* the next outer loop.
331+
*/
332+
for (j=0;j<innatts;j++)
317333
{
318-
Form_pg_attributeinatt=TupleDescAttr(indesc,j);
334+
Form_pg_attributeinatt;
319335

336+
nextindesc++;
337+
if (nextindesc >=innatts)
338+
nextindesc=0;
339+
340+
inatt=TupleDescAttr(indesc,nextindesc);
320341
if (inatt->attisdropped)
321342
continue;
322343
if (strcmp(attname,NameStr(inatt->attname))==0)
@@ -330,7 +351,7 @@ convert_tuples_by_name_map(TupleDesc indesc,
330351
attname,
331352
format_type_be(outdesc->tdtypeid),
332353
format_type_be(indesc->tdtypeid))));
333-
attrMap[i]=(AttrNumber) (j+1);
354+
attrMap[i]=inatt->attnum;
334355
break;
335356
}
336357
}
@@ -343,7 +364,6 @@ convert_tuples_by_name_map(TupleDesc indesc,
343364
format_type_be(outdesc->tdtypeid),
344365
format_type_be(indesc->tdtypeid))));
345366
}
346-
347367
returnattrMap;
348368
}
349369

‎src/backend/optimizer/prep/prepunion.c

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
#include"utils/lsyscache.h"
5252
#include"utils/rel.h"
5353
#include"utils/selfuncs.h"
54+
#include"utils/syscache.h"
5455

5556

5657
typedefstruct
@@ -1895,9 +1896,11 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
18951896
List*vars=NIL;
18961897
TupleDescold_tupdesc=RelationGetDescr(oldrelation);
18971898
TupleDescnew_tupdesc=RelationGetDescr(newrelation);
1899+
Oidnew_relid=RelationGetRelid(newrelation);
18981900
intoldnatts=old_tupdesc->natts;
18991901
intnewnatts=new_tupdesc->natts;
19001902
intold_attno;
1903+
intnew_attno=0;
19011904

19021905
for (old_attno=0;old_attno<oldnatts;old_attno++)
19031906
{
@@ -1906,7 +1909,6 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
19061909
Oidatttypid;
19071910
int32atttypmod;
19081911
Oidattcollation;
1909-
intnew_attno;
19101912

19111913
att=TupleDescAttr(old_tupdesc,old_attno);
19121914
if (att->attisdropped)
@@ -1939,29 +1941,25 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
19391941
* Otherwise we have to search for the matching column by name.
19401942
* There's no guarantee it'll have the same column position, because
19411943
* of cases like ALTER TABLE ADD COLUMN and multiple inheritance.
1942-
* However, in simple cases it will be the same column number, so try
1943-
* that before we go groveling through all the columns.
1944-
*
1945-
* Note: the test for (att = ...) != NULL cannot fail, it's just a
1946-
* notational device to include the assignment into the if-clause.
1944+
* However, in simple cases, the relative order of columns is mostly
1945+
* the same in both relations, so try the column of newrelation that
1946+
* follows immediately after the one that we just found, and if that
1947+
* fails, let syscache handle it.
19471948
*/
1948-
if (old_attno<newnatts&&
1949-
(att=TupleDescAttr(new_tupdesc,old_attno))!=NULL&&
1950-
!att->attisdropped&&
1951-
strcmp(attname,NameStr(att->attname))==0)
1952-
new_attno=old_attno;
1953-
else
1949+
if (new_attno >=newnatts||
1950+
(att=TupleDescAttr(new_tupdesc,new_attno))->attisdropped||
1951+
strcmp(attname,NameStr(att->attname))!=0)
19541952
{
1955-
for (new_attno=0;new_attno<newnatts;new_attno++)
1956-
{
1957-
att=TupleDescAttr(new_tupdesc,new_attno);
1958-
if (!att->attisdropped&&
1959-
strcmp(attname,NameStr(att->attname))==0)
1960-
break;
1961-
}
1962-
if (new_attno >=newnatts)
1953+
HeapTuplenewtup;
1954+
1955+
newtup=SearchSysCacheAttName(new_relid,attname);
1956+
if (!newtup)
19631957
elog(ERROR,"could not find inherited attribute \"%s\" of relation \"%s\"",
19641958
attname,RelationGetRelationName(newrelation));
1959+
new_attno= ((Form_pg_attribute)GETSTRUCT(newtup))->attnum-1;
1960+
ReleaseSysCache(newtup);
1961+
1962+
att=TupleDescAttr(new_tupdesc,new_attno);
19651963
}
19661964

19671965
/* Found it, check type and collation match */
@@ -1978,6 +1976,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
19781976
atttypmod,
19791977
attcollation,
19801978
0));
1979+
new_attno++;
19811980
}
19821981

19831982
*translated_vars=vars;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp