summaryrefslogtreecommitdiff
path: root/src/test/isolation
diff options
context:
space:
mode:
authorAndrew Gierth2017-03-16 22:28:03 +0000
committerAndrew Gierth2017-03-16 22:28:03 +0000
commit1914c5ea7daaaaba4420f65c991256af5d4a9813 (patch)
tree8f1b43d5a9ad32c4bec24bf24263a026c6f1f490 /src/test/isolation
parent80824ddda30154d56c9f40fe47dd1900d44ced32 (diff)
Avoid having vacuum set reltuples to 0 on non-empty relations in the
presence of page pins, which leads to serious estimation errors in the planner. This particularly affects small heavily-accessed tables, especially where locking (e.g. from FK constraints) forces frequent vacuums for mxid cleanup. Fix by keeping separate track of pages whose live tuples were actually counted vs. pages that were only scanned for freezing purposes. Thus, reltuples can only be set to 0 if all pages of the relation were actually counted. Backpatch to all supported versions. Per bug #14057 from Nicolas Baccelli, analyzed by me. Discussion: https://postgr.es/m/20160331103739.8956.94469@wrigleys.postgresql.org
Diffstat (limited to 'src/test/isolation')
-rw-r--r--src/test/isolation/expected/vacuum-reltuples.out62
-rw-r--r--src/test/isolation/isolation_schedule1
-rw-r--r--src/test/isolation/specs/vacuum-reltuples.spec45
3 files changed, 108 insertions, 0 deletions
diff --git a/src/test/isolation/expected/vacuum-reltuples.out b/src/test/isolation/expected/vacuum-reltuples.out
new file mode 100644
index 0000000000..ee3adf5805
--- /dev/null
+++ b/src/test/isolation/expected/vacuum-reltuples.out
@@ -0,0 +1,62 @@
+Parsed test spec with 2 sessions
+
+starting permutation: modify vac stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step vac:
+ vacuum smalltbl;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
+
+starting permutation: modify open fetch1 vac close stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step open:
+ begin;
+ declare c1 cursor for select * from smalltbl;
+
+step fetch1:
+ fetch next from c1;
+
+id
+
+2
+step vac:
+ vacuum smalltbl;
+
+step close:
+ commit;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
+
+starting permutation: modify vac stats
+step modify:
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+
+step vac:
+ vacuum smalltbl;
+
+step stats:
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+
+relpages reltuples
+
+1 20
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 2606a27624..8e404b7a35 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -56,4 +56,5 @@ test: alter-table-2
test: alter-table-3
test: create-trigger
test: async-notify
+test: vacuum-reltuples
test: timeouts
diff --git a/src/test/isolation/specs/vacuum-reltuples.spec b/src/test/isolation/specs/vacuum-reltuples.spec
new file mode 100644
index 0000000000..52bc405547
--- /dev/null
+++ b/src/test/isolation/specs/vacuum-reltuples.spec
@@ -0,0 +1,45 @@
+# Test for vacuum's handling of reltuples when pages are skipped due
+# to page pins. We absolutely need to avoid setting reltuples=0 in
+# such cases, since that interferes badly with planning.
+
+setup {
+ create table smalltbl
+ as select i as id from generate_series(1,20) i;
+ alter table smalltbl set (autovacuum_enabled = off);
+}
+setup {
+ vacuum analyze smalltbl;
+}
+
+teardown {
+ drop table smalltbl;
+}
+
+session "worker"
+step "open" {
+ begin;
+ declare c1 cursor for select * from smalltbl;
+}
+step "fetch1" {
+ fetch next from c1;
+}
+step "close" {
+ commit;
+}
+step "stats" {
+ select relpages, reltuples from pg_class
+ where oid='smalltbl'::regclass;
+}
+
+session "vacuumer"
+step "vac" {
+ vacuum smalltbl;
+}
+step "modify" {
+ insert into smalltbl select max(id)+1 from smalltbl;
+ delete from smalltbl where id in (select min(id) from smalltbl);
+}
+
+permutation "modify" "vac" "stats"
+permutation "modify" "open" "fetch1" "vac" "close" "stats"
+permutation "modify" "vac" "stats"