11# pg_rewrite
22
3- ` pg_rewrite ` aims to be a set of tools to perform maintenance tasks which
4- require a table to be rewritten (i.e. the table data to be copied to a new
5- storage) and which are expected to limit the access to the table as little as
6- possible.
3+ ` pg_rewrite ` is a tool to rewrite table (i.e. to copy its data to a new
4+ file). It allows both read and write access to the table during the rewriting.
75
8- # INSTALL
6+ Following are the most common reasons to rewrite a table:
7+
8+ 1 . Change data type of column(s)
9+
10+ Typically this is needed if the existing data type is running out of
11+ values. For example, you may need to change ` interger ` type to
12+ ` bigint ` . ` ALTER TABLE ` command can do that too, but it allows neither
13+ write nor read access to the table during the rewriting.
14+
15+ 2 . Partition the table
16+
17+ If you realize that your table is getting much bigger than expected and
18+ that partitioning would make your life easier, the next question may be
19+ how to copy the existing data to the new, partitioned table without
20+ stopping all the applications that run DML commands on the table. (When
21+ you decide to use partitioning, the amount of data to copy might already
22+ be significant, so the copying might need a while.)
23+
24+ 3 . Change order of columns
25+
26+ If you conclude that a different order of columns would save significant
27+ disk space (due to reduced paddding), the problem boils down to copying
28+ data to a new table like in 2). Again, you may need ` pg_rewrite ` to make
29+ the change smooth.
30+
31+ Note that the following use cases can be combined in a single rewrited.
32+
33+
34+ # INSTALLATION
935
1036Install PostgreSQL before proceeding. Make sure to have ` pg_config ` binary,
1137these are typically included in ` -dev ` and ` -devel ` packages. PostgreSQL server
@@ -14,6 +40,7 @@ version 13 or later is required.
1440``` bash
1541git clone https://github.com/cybertec-postgresql/pg_rewrite.git
1642cd pg_rewrite
43+ git checkout < the latest stable version>
1744make
1845make install
1946```
@@ -34,28 +61,28 @@ CREATE EXTENSION pg_rewrite;
3461
3562# USAGE
3663
37- Assuming you have a table defined like this:
64+ Assume you have a table defined like this
3865
3966```
4067CREATE TABLE measurement (
41- id serial ,
68+ id int ,
4269 city_id int not null,
4370 logdate date not null,
4471 peaktemp int,
45- unitsales int,
4672 PRIMARY KEY(id, logdate)
4773);
4874```
4975
50- You need to create a partitioned table having the same columns and data types:
76+ and you need to replace it with a partitioned table. At the same time, you
77+ want to change the data type of the ` id ` column to ` bigint ` .
78+
5179
5280```
5381CREATE TABLE measurement_aux (
54- id serial ,
82+ id bigint ,
5583 city_id int not null,
5684 logdate date not null,
5785 peaktemp int,
58- unitsales int,
5986 PRIMARY KEY(id, logdate)
6087) PARTITION BY RANGE (logdate);
6188```
@@ -73,37 +100,66 @@ CREATE TABLE measurement_y2006m03 PARTITION OF measurement_aux
73100-- ...
74101```
75102
76- * It's essential that both the source (` measurement ` ) and destination
103+ * It's essential that both the source (` measurement ` ) and target
77104(` measurement_aux ` ) table have an identity index. The easiest way to ensure
78105this is to create ` PRIMARY KEY ` or ` UNIQUE ` constraint. Also note that the key
79- (i.e. column list) of the identity index of the source and destination table
80- must be identical. The identity is needed to process data changes that
81- applications make while data is being copied from the source to the
82- destination table.*
83-
84- Also, unless you've set ` rewrite.check_constraints ` to ` false ` , make sure that
85- the destination table has all the constraints that the source table has.
106+ (i.e. column list) of the identity index of the source and target table must
107+ be identical. The identity is needed to process data changes that applications
108+ make while data is being copied from the source to the target table.*
86109
87- Then, in order to copy the data into the destination table, run the
88- ` partition_table ()` function and pass it both the source and destination table,
89- as well as a new table name for the source table. For example:
110+ Then, in order to copy the data into the target table, run the
111+ ` rewrite_table ()` function and pass it both the source and target table, as
112+ well as a new table name for the source table. For example:
90113
91114```
92- SELECT partition_table ('measurement', 'measurement_aux', 'measurement_old');
115+ SELECT rewrite_table ('measurement', 'measurement_aux', 'measurement_old');
93116```
94117
95- The call will copy data from ` measurement ` to ` measurement_aux ` , then it will
96- lock ` measurement ` exclusively and rename (1) ` measurement ` to
97- ` measurement_old ` , (2) ` measurement_aux ` to ` measurement ` . Thus ` measurement `
98- ends up to be the partitioned table, while ` measurement_old ` is the original,
99- non-partitioned table.
118+ The call will first copy all rows from ` measurement ` to ` measurement_aux ` . The
119+ it will apply to ` measurement_aux ` all the data changes (INSERT, UPDATE,
120+ DELETE) that took place in ` measurement ` during the copying. Next, it will
121+ lock ` measurement ` so that neither read nor write access is possible. Finally
122+ it will rename ` measurement ` to ` measurement_old ` and ` measurement_aux ` to
123+ ` measurement ` . Thus ` measurement ` ends up to be the partitioned table, while
124+ ` measurement_old ` is the original, non-partitioned table.
125+
126+ If a column of the target table has a different data type from the
127+ corresponding column of the source table, an implicit or assignment cast must
128+ exist between the two types.
129+
130+ # Constraints
131+
132+ The target table should obviously have the same constraints as the source
133+ table. It's recommended to handle constraints creation this way:
134+
135+ 1 . Add PRIMARY KEY, UNIQUE and EXCLUDE constraints of the source table to the
136+ target table before you call ` rewrite_table() ` . These are enforced during
137+ the rewriting, so any violation would make ` rewrite_table() ` fail
138+ (ROLLBACK). (The constraints must have been enforced in the source table,
139+ but it does not hurt to check them in the target table, especially if the
140+ column data type is being changed.)
141+
142+ 2 . Add NOT NULL constraints. ` rewrite_table() ` by-passes validation of these,
143+ but all the rows it inserts into the target table must have been validated
144+ in the source table. Even if the column data tape is different in the
145+ target table, the data type conversion should not turn non-NULL value to
146+ NULL or vice versa.
147+
148+ 3 . CHECK and FOREIGN KEY are created automatically by ` rewrite_table() ` when
149+ all the data changes have been applied to the target table. However, these
150+ constraints are created as NOT VALID, so you need to use the `ALTER TABLE
151+ ... VALIDATE CONSTRAINT ...` command to validate them.
152+
153+ Of course, the function could create the constraints immediately as valid,
154+ but that would imply blocking access to the table for significant time.
155+
100156
101157# Progress monitoring
102158
103- If ` partition_table ()` takes long time to finish, you might be interested in
104- the progress. The ` pg_rewrite_progress ` view shows all the pending calls of
105- the function in the current database. The ` src_table ` , ` dst_table ` and
106- ` src_table_new ` columns contain the arguments of the ` partition_table ()`
159+ If ` rewrite_table ()` takes long time to finish, you might be interested in the
160+ progress. The ` pg_rewrite_progress ` view shows all the pending calls of the
161+ function in the current database. The ` src_table ` , ` dst_table ` and
162+ ` src_table_new ` columns contain the arguments of the ` rewrite_table ()`
107163function. ` ins_initial ` is the number of tuples inserted into the new table
108164storage during the "initial load stage", i.e. the number of tuples present in
109165the table before the processing started. On the other hand, ` ins ` , ` upd ` and
@@ -113,44 +169,29 @@ incorporated into the partitioned table, otherwise they'd get lost.)
113169
114170# Limitations
115171
116- Please consider the following before you try to use the function:
117-
118- * Foreign table partitions are not supported.
119-
120- * It's not expected that the table that you try to partition is referenced by
121- any foreign key. The problem is that the destination table is initially
122- empty, so you won't be able to create the foreign keys that reference it.
172+ If the target table is partitioned, it's not allowed to have foreign
173+ tables as partitions.
123174
124175# Configuration
125176
126177Following is the description of the configuration variables that affect
127178behavior of the functions of this extension.
128179
129- * ` rewrite.check_constraints `
130-
131- Before copying of the data starts, it's checked whether the destination table
132- has the same constraints as the source table, and throws an ERROR if a
133- difference is found. The point is that due to (accidentally) missing
134- constraint on the destination table, data that violate constraints on the
135- source table would be allowed to appear in the destination table as soon as
136- the processing is finished. Even an extra constraint on the destination table
137- is a problem because the extension only assumes that all the data it copies do
138- satisfy constraints on the source table, however it does not validate them
139- against the additional constraints on the destination table.
140-
141- By setting ` rewrite.check_constraints ` to ` false ` , the user can turn off the
142- constraint checks. Please be very cautions before you do so.
143-
144- The default value is ` true ` .
145-
146180* ` rewrite.max_xlock_time `
147181
148182Although the table being processed is available for both read and write
149183operations by other transactions most of the time, an exclusive lock is needed
150- to finalize the processing (i.e. to process the remaining concurrent changes
151- and to rename the tables). If the extension function seems to block access to
152- tables too much, consider setting ` rewrite.max_xlock_time ` GUC parameter. For
153- example:
184+ to finalize the processing (i.e. to do the table renaming), which blocks both
185+ read and write access. This should take very short time that users should
186+ harly notice.
187+
188+ However, if a significant amount of changes took place in the source table
189+ while the extension was waiting for the (exclusive) lock, the outage might
190+ take proportionally longer time. The point is that those changes need to be
191+ propagated to the target table before the exclusive lock can be released.
192+
193+ If the extension function seems to block access to tables too much, consider
194+ setting ` rewrite.max_xlock_time ` GUC parameter. For example:
154195
155196```
156197SET rewrite.max_xlock_time TO 100;
@@ -169,21 +210,14 @@ it needs.
169210
170211# Concurrency
171212
172- 1 . The extension does not prevent other transactions from altering table at
173- certain stages of the processing. If a ` disruptive command ` (i.e. `ALTER
174- TABLE`) manages to commit before the processing could finish, the table
175- processing aborts and all changes done are rolled back.
213+ 1 . While the rewrite_table() function is executing, ` ALTER TABLE ` command on
214+ the same table should be blocked until the rewriting is done. However, in
215+ some cases the ` ALTER TABLE ` command and the rewrite_table() function might
216+ end up in a deadlock. Therefore it's recommended not to run ALTER TABLE on
217+ a table which is being rewritten.
176218
177- 2 . The functions of this extension allow for MVCC-unsafe behavior described in
219+ 2 . The ` rewrite_table() ` function allows for MVCC-unsafe behavior described in
178220 the first paragraph of [ mvcc-caveats] [ 1 ] .
179221
180- # Locking
181-
182- Since the table renaming requires an exclusive lock, applications won't be able
183- to access the table that you try to process for very short time. However, if a
184- significant amount of changes took place in the source table while the
185- extension was waiting for the lock, the outage will take proportionally longer
186- time. The point is that those changes need to be propagated to the destination
187- table before the exclusive lock can be released.
188222
189- [ 1 ] : https://www.postgresql.org/docs/13/static /mvcc-caveats.html
223+ [ 1 ] : https://www.postgresql.org/docs/current /mvcc-caveats.html
0 commit comments