1-- 2-- Test Statistics Collector 3-- 4-- Must be run after tenk2 has been created (by create_table), 5-- populated (by create_misc) and indexed (by create_index). 6-- 7-- conditio sine qua non 8SHOW track_counts; -- must be on 9 track_counts 10-------------- 11 on 12(1 row) 13 14-- ensure that both seqscan and indexscan plans are allowed 15SET enable_seqscan TO on; 16SET enable_indexscan TO on; 17-- for the moment, we don't want index-only scans here 18SET enable_indexonlyscan TO off; 19-- wait to let any prior tests finish dumping out stats; 20-- else our messages might get lost due to contention 21SELECT pg_sleep_for('2 seconds'); 22 pg_sleep_for 23-------------- 24 25(1 row) 26 27-- save counters 28CREATE TEMP TABLE prevstats AS 29SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch, 30 (b.heap_blks_read + b.heap_blks_hit) AS heap_blks, 31 (b.idx_blks_read + b.idx_blks_hit) AS idx_blks, 32 pg_stat_get_snapshot_timestamp() as snap_ts 33 FROM pg_catalog.pg_stat_user_tables AS t, 34 pg_catalog.pg_statio_user_tables AS b 35 WHERE t.relname='tenk2' AND b.relname='tenk2'; 36-- function to wait for counters to advance 37create function wait_for_stats() returns void as $$ 38declare 39 start_time timestamptz := clock_timestamp(); 40 updated1 bool; 41 updated2 bool; 42 updated3 bool; 43begin 44 -- we don't want to wait forever; loop will exit after 30 seconds 45 for i in 1 .. 300 loop 46 47 -- With parallel query, the seqscan and indexscan on tenk2 might be done 48 -- in parallel worker processes, which will send their stats counters 49 -- asynchronously to what our own session does. So we must check for 50 -- those counts to be registered separately from the update counts. 51 52 -- check to see if seqscan has been sensed 53 SELECT (st.seq_scan >= pr.seq_scan + 1) INTO updated1 54 FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr 55 WHERE st.relname='tenk2' AND cl.relname='tenk2'; 56 57 -- check to see if indexscan has been sensed 58 SELECT (st.idx_scan >= pr.idx_scan + 1) INTO updated2 59 FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr 60 WHERE st.relname='tenk2' AND cl.relname='tenk2'; 61 62 -- check to see if all updates have been sensed 63 SELECT (n_tup_ins > 0) INTO updated3 64 FROM pg_stat_user_tables WHERE relname='trunc_stats_test4'; 65 66 exit when updated1 and updated2 and updated3; 67 68 -- wait a little 69 perform pg_sleep(0.1); 70 71 -- reset stats snapshot so we can test again 72 perform pg_stat_clear_snapshot(); 73 74 end loop; 75 76 -- report time waited in postmaster log (where it won't change test output) 77 raise log 'wait_for_stats delayed % seconds', 78 extract(epoch from clock_timestamp() - start_time); 79end 80$$ language plpgsql; 81-- test effects of TRUNCATE on n_live_tup/n_dead_tup counters 82CREATE TABLE trunc_stats_test(id serial); 83CREATE TABLE trunc_stats_test1(id serial, stuff text); 84CREATE TABLE trunc_stats_test2(id serial); 85CREATE TABLE trunc_stats_test3(id serial, stuff text); 86CREATE TABLE trunc_stats_test4(id serial); 87-- check that n_live_tup is reset to 0 after truncate 88INSERT INTO trunc_stats_test DEFAULT VALUES; 89INSERT INTO trunc_stats_test DEFAULT VALUES; 90INSERT INTO trunc_stats_test DEFAULT VALUES; 91TRUNCATE trunc_stats_test; 92-- test involving a truncate in a transaction; 4 ins but only 1 live 93INSERT INTO trunc_stats_test1 DEFAULT VALUES; 94INSERT INTO trunc_stats_test1 DEFAULT VALUES; 95INSERT INTO trunc_stats_test1 DEFAULT VALUES; 96UPDATE trunc_stats_test1 SET id = id + 10 WHERE id IN (1, 2); 97DELETE FROM trunc_stats_test1 WHERE id = 3; 98BEGIN; 99UPDATE trunc_stats_test1 SET id = id + 100; 100TRUNCATE trunc_stats_test1; 101INSERT INTO trunc_stats_test1 DEFAULT VALUES; 102COMMIT; 103-- use a savepoint: 1 insert, 1 live 104BEGIN; 105INSERT INTO trunc_stats_test2 DEFAULT VALUES; 106INSERT INTO trunc_stats_test2 DEFAULT VALUES; 107SAVEPOINT p1; 108INSERT INTO trunc_stats_test2 DEFAULT VALUES; 109TRUNCATE trunc_stats_test2; 110INSERT INTO trunc_stats_test2 DEFAULT VALUES; 111RELEASE SAVEPOINT p1; 112COMMIT; 113-- rollback a savepoint: this should count 4 inserts and have 2 114-- live tuples after commit (and 2 dead ones due to aborted subxact) 115BEGIN; 116INSERT INTO trunc_stats_test3 DEFAULT VALUES; 117INSERT INTO trunc_stats_test3 DEFAULT VALUES; 118SAVEPOINT p1; 119INSERT INTO trunc_stats_test3 DEFAULT VALUES; 120INSERT INTO trunc_stats_test3 DEFAULT VALUES; 121TRUNCATE trunc_stats_test3; 122INSERT INTO trunc_stats_test3 DEFAULT VALUES; 123ROLLBACK TO SAVEPOINT p1; 124COMMIT; 125-- rollback a truncate: this should count 2 inserts and produce 2 dead tuples 126BEGIN; 127INSERT INTO trunc_stats_test4 DEFAULT VALUES; 128INSERT INTO trunc_stats_test4 DEFAULT VALUES; 129TRUNCATE trunc_stats_test4; 130INSERT INTO trunc_stats_test4 DEFAULT VALUES; 131ROLLBACK; 132-- do a seqscan 133SELECT count(*) FROM tenk2; 134 count 135------- 136 10000 137(1 row) 138 139-- do an indexscan 140SELECT count(*) FROM tenk2 WHERE unique1 = 1; 141 count 142------- 143 1 144(1 row) 145 146-- force the rate-limiting logic in pgstat_report_stat() to time out 147-- and send a message 148SELECT pg_sleep(1.0); 149 pg_sleep 150---------- 151 152(1 row) 153 154-- wait for stats collector to update 155SELECT wait_for_stats(); 156 wait_for_stats 157---------------- 158 159(1 row) 160 161-- check effects 162SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup 163 FROM pg_stat_user_tables 164 WHERE relname like 'trunc_stats_test%' order by relname; 165 relname | n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup 166-------------------+-----------+-----------+-----------+------------+------------ 167 trunc_stats_test | 3 | 0 | 0 | 0 | 0 168 trunc_stats_test1 | 4 | 2 | 1 | 1 | 0 169 trunc_stats_test2 | 1 | 0 | 0 | 1 | 0 170 trunc_stats_test3 | 4 | 0 | 0 | 2 | 2 171 trunc_stats_test4 | 2 | 0 | 0 | 0 | 2 172(5 rows) 173 174SELECT st.seq_scan >= pr.seq_scan + 1, 175 st.seq_tup_read >= pr.seq_tup_read + cl.reltuples, 176 st.idx_scan >= pr.idx_scan + 1, 177 st.idx_tup_fetch >= pr.idx_tup_fetch + 1 178 FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr 179 WHERE st.relname='tenk2' AND cl.relname='tenk2'; 180 ?column? | ?column? | ?column? | ?column? 181----------+----------+----------+---------- 182 t | t | t | t 183(1 row) 184 185SELECT st.heap_blks_read + st.heap_blks_hit >= pr.heap_blks + cl.relpages, 186 st.idx_blks_read + st.idx_blks_hit >= pr.idx_blks + 1 187 FROM pg_statio_user_tables AS st, pg_class AS cl, prevstats AS pr 188 WHERE st.relname='tenk2' AND cl.relname='tenk2'; 189 ?column? | ?column? 190----------+---------- 191 t | t 192(1 row) 193 194SELECT pr.snap_ts < pg_stat_get_snapshot_timestamp() as snapshot_newer 195FROM prevstats AS pr; 196 snapshot_newer 197---------------- 198 t 199(1 row) 200 201DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4; 202-- End of Stats Test 203