mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
REINDEX CONCURRENTLY
This adds the CONCURRENTLY option to the REINDEX command. A REINDEX CONCURRENTLY on a specific index creates a new index (like CREATE INDEX CONCURRENTLY), then renames the old index away and the new index in place and adjusts the dependencies, and then drops the old index (like DROP INDEX CONCURRENTLY). The REINDEX command also has the capability to run its other variants (TABLE, DATABASE) with the CONCURRENTLY option (but not SYSTEM). The reindexdb command gets the --concurrently option. Author: Michael Paquier, Andreas Karlsson, Peter Eisentraut Reviewed-by: Andres Freund, Fujii Masao, Jim Nasby, Sergei Kornilov Discussion: https://www.postgresql.org/message-id/flat/60052986-956b-4478-45ed-8bd119e9b9cf%402ndquadrant.com#74948a1044c56c5e817a5050f554ddee
This commit is contained in:
78
src/test/isolation/expected/reindex-concurrently.out
Normal file
78
src/test/isolation/expected/reindex-concurrently.out
Normal file
@ -0,0 +1,78 @@
|
||||
Parsed test spec with 3 sessions
|
||||
|
||||
starting permutation: reindex sel1 upd2 ins2 del2 end1 end2
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab;
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step end1: COMMIT;
|
||||
step end2: COMMIT;
|
||||
|
||||
starting permutation: sel1 reindex upd2 ins2 del2 end1 end2
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab; <waiting ...>
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step end1: COMMIT;
|
||||
step end2: COMMIT;
|
||||
step reindex: <... completed>
|
||||
|
||||
starting permutation: sel1 upd2 reindex ins2 del2 end1 end2
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab; <waiting ...>
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step end1: COMMIT;
|
||||
step end2: COMMIT;
|
||||
step reindex: <... completed>
|
||||
|
||||
starting permutation: sel1 upd2 ins2 reindex del2 end1 end2
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab; <waiting ...>
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step end1: COMMIT;
|
||||
step end2: COMMIT;
|
||||
step reindex: <... completed>
|
||||
|
||||
starting permutation: sel1 upd2 ins2 del2 reindex end1 end2
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab; <waiting ...>
|
||||
step end1: COMMIT;
|
||||
step end2: COMMIT;
|
||||
step reindex: <... completed>
|
||||
|
||||
starting permutation: sel1 upd2 ins2 del2 end1 reindex end2
|
||||
step sel1: SELECT data FROM reind_con_tab WHERE id = 3;
|
||||
data
|
||||
|
||||
aaaa
|
||||
step upd2: UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3;
|
||||
step ins2: INSERT INTO reind_con_tab(data) VALUES ('cccc');
|
||||
step del2: DELETE FROM reind_con_tab WHERE data = 'cccc';
|
||||
step end1: COMMIT;
|
||||
step reindex: REINDEX TABLE CONCURRENTLY reind_con_tab; <waiting ...>
|
||||
step end2: COMMIT;
|
||||
step reindex: <... completed>
|
@ -42,6 +42,7 @@ test: multixact-no-forget
|
||||
test: lock-committed-update
|
||||
test: lock-committed-keyupdate
|
||||
test: update-locked-tuple
|
||||
test: reindex-concurrently
|
||||
test: propagate-lock-delete
|
||||
test: tuplelock-conflict
|
||||
test: tuplelock-update
|
||||
|
40
src/test/isolation/specs/reindex-concurrently.spec
Normal file
40
src/test/isolation/specs/reindex-concurrently.spec
Normal file
@ -0,0 +1,40 @@
|
||||
# REINDEX CONCURRENTLY
|
||||
#
|
||||
# Ensure that concurrent operations work correctly when a REINDEX is performed
|
||||
# concurrently.
|
||||
|
||||
setup
|
||||
{
|
||||
CREATE TABLE reind_con_tab(id serial primary key, data text);
|
||||
INSERT INTO reind_con_tab(data) VALUES ('aa');
|
||||
INSERT INTO reind_con_tab(data) VALUES ('aaa');
|
||||
INSERT INTO reind_con_tab(data) VALUES ('aaaa');
|
||||
INSERT INTO reind_con_tab(data) VALUES ('aaaaa');
|
||||
}
|
||||
|
||||
teardown
|
||||
{
|
||||
DROP TABLE reind_con_tab;
|
||||
}
|
||||
|
||||
session "s1"
|
||||
setup { BEGIN; }
|
||||
step "sel1" { SELECT data FROM reind_con_tab WHERE id = 3; }
|
||||
step "end1" { COMMIT; }
|
||||
|
||||
session "s2"
|
||||
setup { BEGIN; }
|
||||
step "upd2" { UPDATE reind_con_tab SET data = 'bbbb' WHERE id = 3; }
|
||||
step "ins2" { INSERT INTO reind_con_tab(data) VALUES ('cccc'); }
|
||||
step "del2" { DELETE FROM reind_con_tab WHERE data = 'cccc'; }
|
||||
step "end2" { COMMIT; }
|
||||
|
||||
session "s3"
|
||||
step "reindex" { REINDEX TABLE CONCURRENTLY reind_con_tab; }
|
||||
|
||||
permutation "reindex" "sel1" "upd2" "ins2" "del2" "end1" "end2"
|
||||
permutation "sel1" "reindex" "upd2" "ins2" "del2" "end1" "end2"
|
||||
permutation "sel1" "upd2" "reindex" "ins2" "del2" "end1" "end2"
|
||||
permutation "sel1" "upd2" "ins2" "reindex" "del2" "end1" "end2"
|
||||
permutation "sel1" "upd2" "ins2" "del2" "reindex" "end1" "end2"
|
||||
permutation "sel1" "upd2" "ins2" "del2" "end1" "reindex" "end2"
|
@ -3250,6 +3250,101 @@ INFO: index "reindex_verbose_pkey" was reindexed
|
||||
\set VERBOSITY default
|
||||
DROP TABLE reindex_verbose;
|
||||
--
|
||||
-- REINDEX CONCURRENTLY
|
||||
--
|
||||
CREATE TABLE concur_reindex_tab (c1 int);
|
||||
-- REINDEX
|
||||
REINDEX TABLE concur_reindex_tab; -- notice
|
||||
NOTICE: table "concur_reindex_tab" has no indexes
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab; -- notice
|
||||
NOTICE: table "concur_reindex_tab" has no indexes
|
||||
ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index
|
||||
-- Normal index with integer column
|
||||
CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1);
|
||||
-- Normal index with text column
|
||||
CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2);
|
||||
-- UNIQUE index with expression
|
||||
CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1));
|
||||
-- Duplicate column names
|
||||
CREATE INDEX concur_reindex_ind4 ON concur_reindex_tab(c1, c1, c2);
|
||||
-- Create table for check on foreign key dependence switch with indexes swapped
|
||||
ALTER TABLE concur_reindex_tab ADD PRIMARY KEY USING INDEX concur_reindex_ind1;
|
||||
CREATE TABLE concur_reindex_tab2 (c1 int REFERENCES concur_reindex_tab);
|
||||
INSERT INTO concur_reindex_tab VALUES (1, 'a');
|
||||
INSERT INTO concur_reindex_tab VALUES (2, 'a');
|
||||
-- Reindex concurrently of exclusion constraint currently not supported
|
||||
CREATE TABLE concur_reindex_tab3 (c1 int, c2 int4range, EXCLUDE USING gist (c2 WITH &&));
|
||||
INSERT INTO concur_reindex_tab3 VALUES (3, '[1,2]');
|
||||
REINDEX INDEX CONCURRENTLY concur_reindex_tab3_c2_excl; -- error
|
||||
ERROR: concurrent index creation for exclusion constraints is not supported
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab3; -- succeeds with warning
|
||||
WARNING: cannot reindex concurrently exclusion constraint index "public.concur_reindex_tab3_c2_excl", skipping
|
||||
INSERT INTO concur_reindex_tab3 VALUES (4, '[2,4]');
|
||||
ERROR: conflicting key value violates exclusion constraint "concur_reindex_tab3_c2_excl"
|
||||
DETAIL: Key (c2)=([2,5)) conflicts with existing key (c2)=([1,3)).
|
||||
-- Check materialized views
|
||||
CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab;
|
||||
REINDEX INDEX CONCURRENTLY concur_reindex_ind1;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_matview;
|
||||
-- Check that comments are preserved
|
||||
CREATE TABLE testcomment (i int);
|
||||
CREATE INDEX testcomment_idx1 ON testcomment (i);
|
||||
COMMENT ON INDEX testcomment_idx1 IS 'test comment';
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
obj_description
|
||||
-----------------
|
||||
test comment
|
||||
(1 row)
|
||||
|
||||
REINDEX TABLE testcomment;
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
obj_description
|
||||
-----------------
|
||||
test comment
|
||||
(1 row)
|
||||
|
||||
REINDEX TABLE CONCURRENTLY testcomment ;
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
obj_description
|
||||
-----------------
|
||||
test comment
|
||||
(1 row)
|
||||
|
||||
DROP TABLE testcomment;
|
||||
-- Check errors
|
||||
-- Cannot run inside a transaction block
|
||||
BEGIN;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab;
|
||||
ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block
|
||||
COMMIT;
|
||||
REINDEX TABLE CONCURRENTLY pg_database; -- no shared relation
|
||||
ERROR: concurrent index creation on system catalog tables is not supported
|
||||
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relations
|
||||
ERROR: concurrent index creation on system catalog tables is not supported
|
||||
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
|
||||
ERROR: concurrent reindex of system catalogs is not supported
|
||||
-- Warns about catalog relations
|
||||
REINDEX SCHEMA CONCURRENTLY pg_catalog;
|
||||
WARNING: concurrent reindex is not supported for catalog relations, skipping all
|
||||
-- Check the relation status, there should not be invalid indexes
|
||||
\d concur_reindex_tab
|
||||
Table "public.concur_reindex_tab"
|
||||
Column | Type | Collation | Nullable | Default
|
||||
--------+---------+-----------+----------+---------
|
||||
c1 | integer | | not null |
|
||||
c2 | text | | |
|
||||
Indexes:
|
||||
"concur_reindex_ind1" PRIMARY KEY, btree (c1)
|
||||
"concur_reindex_ind3" UNIQUE, btree (abs(c1))
|
||||
"concur_reindex_ind2" btree (c2)
|
||||
"concur_reindex_ind4" btree (c1, c1, c2)
|
||||
Referenced by:
|
||||
TABLE "concur_reindex_tab2" CONSTRAINT "concur_reindex_tab2_c1_fkey" FOREIGN KEY (c1) REFERENCES concur_reindex_tab(c1)
|
||||
|
||||
DROP MATERIALIZED VIEW concur_reindex_matview;
|
||||
DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
|
||||
--
|
||||
-- REINDEX SCHEMA
|
||||
--
|
||||
REINDEX SCHEMA schema_to_reindex; -- failure, schema does not exist
|
||||
@ -3308,6 +3403,8 @@ BEGIN;
|
||||
REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
|
||||
ERROR: REINDEX SCHEMA cannot run inside a transaction block
|
||||
END;
|
||||
-- concurrently
|
||||
REINDEX SCHEMA CONCURRENTLY schema_to_reindex;
|
||||
-- Failure for unauthorized user
|
||||
CREATE ROLE regress_reindexuser NOLOGIN;
|
||||
SET SESSION ROLE regress_reindexuser;
|
||||
|
@ -1172,6 +1172,65 @@ REINDEX (VERBOSE) TABLE reindex_verbose;
|
||||
\set VERBOSITY default
|
||||
DROP TABLE reindex_verbose;
|
||||
|
||||
--
|
||||
-- REINDEX CONCURRENTLY
|
||||
--
|
||||
CREATE TABLE concur_reindex_tab (c1 int);
|
||||
-- REINDEX
|
||||
REINDEX TABLE concur_reindex_tab; -- notice
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab; -- notice
|
||||
ALTER TABLE concur_reindex_tab ADD COLUMN c2 text; -- add toast index
|
||||
-- Normal index with integer column
|
||||
CREATE UNIQUE INDEX concur_reindex_ind1 ON concur_reindex_tab(c1);
|
||||
-- Normal index with text column
|
||||
CREATE INDEX concur_reindex_ind2 ON concur_reindex_tab(c2);
|
||||
-- UNIQUE index with expression
|
||||
CREATE UNIQUE INDEX concur_reindex_ind3 ON concur_reindex_tab(abs(c1));
|
||||
-- Duplicate column names
|
||||
CREATE INDEX concur_reindex_ind4 ON concur_reindex_tab(c1, c1, c2);
|
||||
-- Create table for check on foreign key dependence switch with indexes swapped
|
||||
ALTER TABLE concur_reindex_tab ADD PRIMARY KEY USING INDEX concur_reindex_ind1;
|
||||
CREATE TABLE concur_reindex_tab2 (c1 int REFERENCES concur_reindex_tab);
|
||||
INSERT INTO concur_reindex_tab VALUES (1, 'a');
|
||||
INSERT INTO concur_reindex_tab VALUES (2, 'a');
|
||||
-- Reindex concurrently of exclusion constraint currently not supported
|
||||
CREATE TABLE concur_reindex_tab3 (c1 int, c2 int4range, EXCLUDE USING gist (c2 WITH &&));
|
||||
INSERT INTO concur_reindex_tab3 VALUES (3, '[1,2]');
|
||||
REINDEX INDEX CONCURRENTLY concur_reindex_tab3_c2_excl; -- error
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab3; -- succeeds with warning
|
||||
INSERT INTO concur_reindex_tab3 VALUES (4, '[2,4]');
|
||||
-- Check materialized views
|
||||
CREATE MATERIALIZED VIEW concur_reindex_matview AS SELECT * FROM concur_reindex_tab;
|
||||
REINDEX INDEX CONCURRENTLY concur_reindex_ind1;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_matview;
|
||||
-- Check that comments are preserved
|
||||
CREATE TABLE testcomment (i int);
|
||||
CREATE INDEX testcomment_idx1 ON testcomment (i);
|
||||
COMMENT ON INDEX testcomment_idx1 IS 'test comment';
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
REINDEX TABLE testcomment;
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
REINDEX TABLE CONCURRENTLY testcomment ;
|
||||
SELECT obj_description('testcomment_idx1'::regclass, 'pg_class');
|
||||
DROP TABLE testcomment;
|
||||
|
||||
-- Check errors
|
||||
-- Cannot run inside a transaction block
|
||||
BEGIN;
|
||||
REINDEX TABLE CONCURRENTLY concur_reindex_tab;
|
||||
COMMIT;
|
||||
REINDEX TABLE CONCURRENTLY pg_database; -- no shared relation
|
||||
REINDEX TABLE CONCURRENTLY pg_class; -- no catalog relations
|
||||
REINDEX SYSTEM CONCURRENTLY postgres; -- not allowed for SYSTEM
|
||||
-- Warns about catalog relations
|
||||
REINDEX SCHEMA CONCURRENTLY pg_catalog;
|
||||
|
||||
-- Check the relation status, there should not be invalid indexes
|
||||
\d concur_reindex_tab
|
||||
DROP MATERIALIZED VIEW concur_reindex_matview;
|
||||
DROP TABLE concur_reindex_tab, concur_reindex_tab2, concur_reindex_tab3;
|
||||
|
||||
--
|
||||
-- REINDEX SCHEMA
|
||||
--
|
||||
@ -1214,6 +1273,9 @@ BEGIN;
|
||||
REINDEX SCHEMA schema_to_reindex; -- failure, cannot run in a transaction
|
||||
END;
|
||||
|
||||
-- concurrently
|
||||
REINDEX SCHEMA CONCURRENTLY schema_to_reindex;
|
||||
|
||||
-- Failure for unauthorized user
|
||||
CREATE ROLE regress_reindexuser NOLOGIN;
|
||||
SET SESSION ROLE regress_reindexuser;
|
||||
|
Reference in New Issue
Block a user