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

Commita435674

Browse files
committed
Use in-place updates for pg_restore_relation_stats().
This matches the behavior of vac_update_relstats(), which is importantto avoid bloating pg_class.Author: Corey HuinkerDiscussion:https://postgr.es/m/CADkLM=fc3je+ufv3gsHqjjSSf+t8674RXpuXW62EL55MUEQd-g@mail.gmail.com
1 parent8ede501 commita435674

File tree

4 files changed

+235
-71
lines changed

4 files changed

+235
-71
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30175,6 +30175,14 @@ postgres=# SELECT '0/0'::pg_lsn + pd.segment_number * ps.setting::int + :offset
3017530175
function is to maintain a consistent function signature to avoid
3017630176
errors when restoring statistics from previous versions.
3017730177
</para>
30178+
<para>
30179+
To match the behavior of <xref linkend="sql-vacuum"/> and <xref
30180+
linkend="sql-analyze"/> when updating relation statistics,
30181+
<function>pg_restore_relation_stats()</function> does not follow MVCC
30182+
transactional semantics (see <xref linkend="mvcc"/>). New relation
30183+
statistics may be durable even if the transaction aborts, and the
30184+
changes are not isolated from other transactions.
30185+
</para>
3017830186
<para>
3017930187
Arguments are passed as pairs of <replaceable>argname</replaceable>
3018030188
and <replaceable>argvalue</replaceable>, where

‎src/backend/statistics/relation_stats.c

Lines changed: 129 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include"access/heapam.h"
2121
#include"catalog/indexing.h"
2222
#include"statistics/stat_utils.h"
23+
#include"utils/fmgroids.h"
2324
#include"utils/fmgrprotos.h"
2425
#include"utils/syscache.h"
2526

@@ -50,59 +51,28 @@ static struct StatsArgInfo relarginfo[] =
5051
[NUM_RELATION_STATS_ARGS]= {0}
5152
};
5253

53-
staticboolrelation_statistics_update(FunctionCallInfofcinfo,intelevel);
54+
staticboolrelation_statistics_update(FunctionCallInfofcinfo,intelevel,
55+
boolinplace);
5456

5557
/*
5658
* Internal function for modifying statistics for a relation.
5759
*/
5860
staticbool
59-
relation_statistics_update(FunctionCallInfofcinfo,intelevel)
61+
relation_statistics_update(FunctionCallInfofcinfo,intelevel,boolinplace)
6062
{
6163
Oidreloid;
6264
Relationcrel;
63-
HeapTuplectup;
64-
Form_pg_classpgcform;
65-
intreplaces[3]= {0};
66-
Datumvalues[3]= {0};
67-
boolnulls[3]= {0};
68-
intncols=0;
69-
TupleDesctupdesc;
65+
int32relpages=DEFAULT_RELPAGES;
66+
boolupdate_relpages= false;
67+
floatreltuples=DEFAULT_RELTUPLES;
68+
boolupdate_reltuples= false;
69+
int32relallvisible=DEFAULT_RELALLVISIBLE;
70+
boolupdate_relallvisible= false;
7071
boolresult= true;
7172

72-
stats_check_required_arg(fcinfo,relarginfo,RELATION_ARG);
73-
reloid=PG_GETARG_OID(RELATION_ARG);
74-
75-
if (RecoveryInProgress())
76-
ereport(ERROR,
77-
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
78-
errmsg("recovery is in progress"),
79-
errhint("Statistics cannot be modified during recovery.")));
80-
81-
stats_lock_check_privileges(reloid);
82-
83-
/*
84-
* Take RowExclusiveLock on pg_class, consistent with
85-
* vac_update_relstats().
86-
*/
87-
crel=table_open(RelationRelationId,RowExclusiveLock);
88-
89-
tupdesc=RelationGetDescr(crel);
90-
ctup=SearchSysCacheCopy1(RELOID,ObjectIdGetDatum(reloid));
91-
if (!HeapTupleIsValid(ctup))
92-
{
93-
ereport(elevel,
94-
(errcode(ERRCODE_OBJECT_IN_USE),
95-
errmsg("pg_class entry for relid %u not found",reloid)));
96-
table_close(crel,RowExclusiveLock);
97-
return false;
98-
}
99-
100-
pgcform= (Form_pg_class)GETSTRUCT(ctup);
101-
102-
/* relpages */
10373
if (!PG_ARGISNULL(RELPAGES_ARG))
10474
{
105-
int32relpages=PG_GETARG_INT32(RELPAGES_ARG);
75+
relpages=PG_GETARG_INT32(RELPAGES_ARG);
10676

10777
/*
10878
* Partitioned tables may have relpages=-1. Note: for relations with
@@ -116,17 +86,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
11686
errmsg("relpages cannot be < -1")));
11787
result= false;
11888
}
119-
elseif (relpages!=pgcform->relpages)
120-
{
121-
replaces[ncols]=Anum_pg_class_relpages;
122-
values[ncols]=Int32GetDatum(relpages);
123-
ncols++;
124-
}
89+
else
90+
update_relpages= true;
12591
}
12692

12793
if (!PG_ARGISNULL(RELTUPLES_ARG))
12894
{
129-
floatreltuples=PG_GETARG_FLOAT4(RELTUPLES_ARG);
95+
reltuples=PG_GETARG_FLOAT4(RELTUPLES_ARG);
13096

13197
if (reltuples<-1.0)
13298
{
@@ -135,18 +101,13 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
135101
errmsg("reltuples cannot be < -1.0")));
136102
result= false;
137103
}
138-
elseif (reltuples!=pgcform->reltuples)
139-
{
140-
replaces[ncols]=Anum_pg_class_reltuples;
141-
values[ncols]=Float4GetDatum(reltuples);
142-
ncols++;
143-
}
144-
104+
else
105+
update_reltuples= true;
145106
}
146107

147108
if (!PG_ARGISNULL(RELALLVISIBLE_ARG))
148109
{
149-
int32relallvisible=PG_GETARG_INT32(RELALLVISIBLE_ARG);
110+
relallvisible=PG_GETARG_INT32(RELALLVISIBLE_ARG);
150111

151112
if (relallvisible<0)
152113
{
@@ -155,23 +116,120 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
155116
errmsg("relallvisible cannot be < 0")));
156117
result= false;
157118
}
158-
elseif (relallvisible!=pgcform->relallvisible)
119+
else
120+
update_relallvisible= true;
121+
}
122+
123+
stats_check_required_arg(fcinfo,relarginfo,RELATION_ARG);
124+
reloid=PG_GETARG_OID(RELATION_ARG);
125+
126+
if (RecoveryInProgress())
127+
ereport(ERROR,
128+
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
129+
errmsg("recovery is in progress"),
130+
errhint("Statistics cannot be modified during recovery.")));
131+
132+
stats_lock_check_privileges(reloid);
133+
134+
/*
135+
* Take RowExclusiveLock on pg_class, consistent with
136+
* vac_update_relstats().
137+
*/
138+
crel=table_open(RelationRelationId,RowExclusiveLock);
139+
140+
if (inplace)
141+
{
142+
HeapTuplectup=NULL;
143+
ScanKeyDatakey[1];
144+
Form_pg_classpgcform;
145+
void*inplace_state=NULL;
146+
booldirty= false;
147+
148+
ScanKeyInit(&key[0],Anum_pg_class_oid,BTEqualStrategyNumber,F_OIDEQ,
149+
ObjectIdGetDatum(reloid));
150+
systable_inplace_update_begin(crel,ClassOidIndexId, true,NULL,1,key,
151+
&ctup,&inplace_state);
152+
if (!HeapTupleIsValid(ctup))
153+
elog(ERROR,"pg_class entry for relid %u vanished while updating statistics",
154+
reloid);
155+
pgcform= (Form_pg_class)GETSTRUCT(ctup);
156+
157+
if (update_relpages&&pgcform->relpages!=relpages)
159158
{
160-
replaces[ncols]=Anum_pg_class_relallvisible;
161-
values[ncols]=Int32GetDatum(relallvisible);
162-
ncols++;
159+
pgcform->relpages=relpages;
160+
dirty= true;
163161
}
164-
}
162+
if (update_reltuples&&pgcform->reltuples!=reltuples)
163+
{
164+
pgcform->reltuples=reltuples;
165+
dirty= true;
166+
}
167+
if (update_relallvisible&&pgcform->relallvisible!=relallvisible)
168+
{
169+
pgcform->relallvisible=relallvisible;
170+
dirty= true;
171+
}
172+
173+
if (dirty)
174+
systable_inplace_update_finish(inplace_state,ctup);
175+
else
176+
systable_inplace_update_cancel(inplace_state);
165177

166-
/* only update pg_class if there is a meaningful change */
167-
if (ncols>0)
178+
heap_freetuple(ctup);
179+
}
180+
else
168181
{
169-
HeapTuplenewtup;
182+
TupleDesctupdesc=RelationGetDescr(crel);
183+
HeapTuplectup;
184+
Form_pg_classpgcform;
185+
intreplaces[3]= {0};
186+
Datumvalues[3]= {0};
187+
boolnulls[3]= {0};
188+
intnreplaces=0;
189+
190+
ctup=SearchSysCache1(RELOID,ObjectIdGetDatum(reloid));
191+
if (!HeapTupleIsValid(ctup))
192+
{
193+
ereport(elevel,
194+
(errcode(ERRCODE_OBJECT_IN_USE),
195+
errmsg("pg_class entry for relid %u not found",reloid)));
196+
table_close(crel,RowExclusiveLock);
197+
return false;
198+
}
199+
pgcform= (Form_pg_class)GETSTRUCT(ctup);
200+
201+
if (update_relpages&&relpages!=pgcform->relpages)
202+
{
203+
replaces[nreplaces]=Anum_pg_class_relpages;
204+
values[nreplaces]=Int32GetDatum(relpages);
205+
nreplaces++;
206+
}
207+
208+
if (update_reltuples&&reltuples!=pgcform->reltuples)
209+
{
210+
replaces[nreplaces]=Anum_pg_class_reltuples;
211+
values[nreplaces]=Float4GetDatum(reltuples);
212+
nreplaces++;
213+
}
214+
215+
if (update_relallvisible&&relallvisible!=pgcform->relallvisible)
216+
{
217+
replaces[nreplaces]=Anum_pg_class_relallvisible;
218+
values[nreplaces]=Int32GetDatum(relallvisible);
219+
nreplaces++;
220+
}
221+
222+
if (nreplaces>0)
223+
{
224+
HeapTuplenewtup;
225+
226+
newtup=heap_modify_tuple_by_cols(ctup,tupdesc,nreplaces,
227+
replaces,values,nulls);
228+
CatalogTupleUpdate(crel,&newtup->t_self,newtup);
229+
heap_freetuple(newtup);
230+
}
170231

171-
newtup=heap_modify_tuple_by_cols(ctup,tupdesc,ncols,replaces,values,
172-
nulls);
173-
CatalogTupleUpdate(crel,&newtup->t_self,newtup);
174-
heap_freetuple(newtup);
232+
ReleaseSysCache(ctup);
175233
}
176234

177235
/* release the lock, consistent with vac_update_relstats() */
@@ -188,7 +246,7 @@ relation_statistics_update(FunctionCallInfo fcinfo, int elevel)
188246
Datum
189247
pg_set_relation_stats(PG_FUNCTION_ARGS)
190248
{
191-
relation_statistics_update(fcinfo,ERROR);
249+
relation_statistics_update(fcinfo,ERROR, false);
192250
PG_RETURN_VOID();
193251
}
194252

@@ -212,7 +270,7 @@ pg_clear_relation_stats(PG_FUNCTION_ARGS)
212270
newfcinfo->args[3].value=DEFAULT_RELALLVISIBLE;
213271
newfcinfo->args[3].isnull= false;
214272

215-
relation_statistics_update(newfcinfo,ERROR);
273+
relation_statistics_update(newfcinfo,ERROR, false);
216274
PG_RETURN_VOID();
217275
}
218276

@@ -230,7 +288,7 @@ pg_restore_relation_stats(PG_FUNCTION_ARGS)
230288
relarginfo,WARNING))
231289
result= false;
232290

233-
if (!relation_statistics_update(positional_fcinfo,WARNING))
291+
if (!relation_statistics_update(positional_fcinfo,WARNING, true))
234292
result= false;
235293

236294
PG_RETURN_BOOL(result);

‎src/test/regress/expected/stats_import.out

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,47 @@ WHERE oid = 'stats_import.test'::regclass;
105105
18 | 401 | 5
106106
(1 row)
107107

108+
-- test MVCC behavior: changes do not persist after abort (in contrast
109+
-- to pg_restore_relation_stats(), which uses in-place updates).
110+
BEGIN;
111+
SELECT
112+
pg_catalog.pg_set_relation_stats(
113+
relation => 'stats_import.test'::regclass,
114+
relpages => NULL::integer,
115+
reltuples => 4000.0::real,
116+
relallvisible => 4::integer);
117+
pg_set_relation_stats
118+
-----------------------
119+
120+
(1 row)
121+
122+
ABORT;
123+
SELECT relpages, reltuples, relallvisible
124+
FROM pg_class
125+
WHERE oid = 'stats_import.test'::regclass;
126+
relpages | reltuples | relallvisible
127+
----------+-----------+---------------
128+
18 | 401 | 5
129+
(1 row)
130+
131+
BEGIN;
132+
SELECT
133+
pg_catalog.pg_clear_relation_stats(
134+
'stats_import.test'::regclass);
135+
pg_clear_relation_stats
136+
-------------------------
137+
138+
(1 row)
139+
140+
ABORT;
141+
SELECT relpages, reltuples, relallvisible
142+
FROM pg_class
143+
WHERE oid = 'stats_import.test'::regclass;
144+
relpages | reltuples | relallvisible
145+
----------+-----------+---------------
146+
18 | 401 | 5
147+
(1 row)
148+
108149
-- clear
109150
SELECT
110151
pg_catalog.pg_clear_relation_stats(
@@ -705,6 +746,25 @@ WHERE oid = 'stats_import.test'::regclass;
705746
(1 row)
706747

707748
-- ok: just relpages
749+
SELECT pg_restore_relation_stats(
750+
'relation', 'stats_import.test'::regclass,
751+
'version', 150000::integer,
752+
'relpages', '15'::integer);
753+
pg_restore_relation_stats
754+
---------------------------
755+
t
756+
(1 row)
757+
758+
SELECT relpages, reltuples, relallvisible
759+
FROM pg_class
760+
WHERE oid = 'stats_import.test'::regclass;
761+
relpages | reltuples | relallvisible
762+
----------+-----------+---------------
763+
15 | 400 | 4
764+
(1 row)
765+
766+
-- test non-MVCC behavior: new value should persist after abort
767+
BEGIN;
708768
SELECT pg_restore_relation_stats(
709769
'relation', 'stats_import.test'::regclass,
710770
'version', 150000::integer,
@@ -714,6 +774,7 @@ SELECT pg_restore_relation_stats(
714774
t
715775
(1 row)
716776

777+
ABORT;
717778
SELECT relpages, reltuples, relallvisible
718779
FROM pg_class
719780
WHERE oid = 'stats_import.test'::regclass;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp