Improve nbtree unsatisfiable RowCompare detection.
[pgsql.git] / src / test / regress / expected / stats.out
bloba0317b7208e3e3cda48c4134132383503e24d392
1 --
2 -- Test cumulative stats system
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
8 SHOW track_counts;  -- must be on
9  track_counts 
10 --------------
11  on
12 (1 row)
14 -- ensure that both seqscan and indexscan plans are allowed
15 SET enable_seqscan TO on;
16 SET enable_indexscan TO on;
17 -- for the moment, we don't want index-only scans here
18 SET enable_indexonlyscan TO off;
19 -- not enabled by default, but we want to test it...
20 SET track_functions TO 'all';
21 -- record dboid for later use
22 SELECT oid AS dboid from pg_database where datname = current_database() \gset
23 -- save counters
24 BEGIN;
25 SET LOCAL stats_fetch_consistency = snapshot;
26 CREATE TABLE prevstats AS
27 SELECT t.seq_scan, t.seq_tup_read, t.idx_scan, t.idx_tup_fetch,
28        (b.heap_blks_read + b.heap_blks_hit) AS heap_blks,
29        (b.idx_blks_read + b.idx_blks_hit) AS idx_blks,
30        pg_stat_get_snapshot_timestamp() as snap_ts
31   FROM pg_catalog.pg_stat_user_tables AS t,
32        pg_catalog.pg_statio_user_tables AS b
33  WHERE t.relname='tenk2' AND b.relname='tenk2';
34 COMMIT;
35 -- test effects of TRUNCATE on n_live_tup/n_dead_tup counters
36 CREATE TABLE trunc_stats_test(id serial);
37 CREATE TABLE trunc_stats_test1(id serial, stuff text);
38 CREATE TABLE trunc_stats_test2(id serial);
39 CREATE TABLE trunc_stats_test3(id serial, stuff text);
40 CREATE TABLE trunc_stats_test4(id serial);
41 -- check that n_live_tup is reset to 0 after truncate
42 INSERT INTO trunc_stats_test DEFAULT VALUES;
43 INSERT INTO trunc_stats_test DEFAULT VALUES;
44 INSERT INTO trunc_stats_test DEFAULT VALUES;
45 TRUNCATE trunc_stats_test;
46 -- test involving a truncate in a transaction; 4 ins but only 1 live
47 INSERT INTO trunc_stats_test1 DEFAULT VALUES;
48 INSERT INTO trunc_stats_test1 DEFAULT VALUES;
49 INSERT INTO trunc_stats_test1 DEFAULT VALUES;
50 UPDATE trunc_stats_test1 SET id = id + 10 WHERE id IN (1, 2);
51 DELETE FROM trunc_stats_test1 WHERE id = 3;
52 BEGIN;
53 UPDATE trunc_stats_test1 SET id = id + 100;
54 TRUNCATE trunc_stats_test1;
55 INSERT INTO trunc_stats_test1 DEFAULT VALUES;
56 COMMIT;
57 -- use a savepoint: 1 insert, 1 live
58 BEGIN;
59 INSERT INTO trunc_stats_test2 DEFAULT VALUES;
60 INSERT INTO trunc_stats_test2 DEFAULT VALUES;
61 SAVEPOINT p1;
62 INSERT INTO trunc_stats_test2 DEFAULT VALUES;
63 TRUNCATE trunc_stats_test2;
64 INSERT INTO trunc_stats_test2 DEFAULT VALUES;
65 RELEASE SAVEPOINT p1;
66 COMMIT;
67 -- rollback a savepoint: this should count 4 inserts and have 2
68 -- live tuples after commit (and 2 dead ones due to aborted subxact)
69 BEGIN;
70 INSERT INTO trunc_stats_test3 DEFAULT VALUES;
71 INSERT INTO trunc_stats_test3 DEFAULT VALUES;
72 SAVEPOINT p1;
73 INSERT INTO trunc_stats_test3 DEFAULT VALUES;
74 INSERT INTO trunc_stats_test3 DEFAULT VALUES;
75 TRUNCATE trunc_stats_test3;
76 INSERT INTO trunc_stats_test3 DEFAULT VALUES;
77 ROLLBACK TO SAVEPOINT p1;
78 COMMIT;
79 -- rollback a truncate: this should count 2 inserts and produce 2 dead tuples
80 BEGIN;
81 INSERT INTO trunc_stats_test4 DEFAULT VALUES;
82 INSERT INTO trunc_stats_test4 DEFAULT VALUES;
83 TRUNCATE trunc_stats_test4;
84 INSERT INTO trunc_stats_test4 DEFAULT VALUES;
85 ROLLBACK;
86 -- do a seqscan
87 SELECT count(*) FROM tenk2;
88  count 
89 -------
90  10000
91 (1 row)
93 -- do an indexscan
94 -- make sure it is not a bitmap scan, which might skip fetching heap tuples
95 SET enable_bitmapscan TO off;
96 SELECT count(*) FROM tenk2 WHERE unique1 = 1;
97  count 
98 -------
99      1
100 (1 row)
102 RESET enable_bitmapscan;
103 -- ensure pending stats are flushed
104 SELECT pg_stat_force_next_flush();
105  pg_stat_force_next_flush 
106 --------------------------
108 (1 row)
110 -- check effects
111 BEGIN;
112 SET LOCAL stats_fetch_consistency = snapshot;
113 SELECT relname, n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup
114   FROM pg_stat_user_tables
115  WHERE relname like 'trunc_stats_test%' order by relname;
116       relname      | n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup 
117 -------------------+-----------+-----------+-----------+------------+------------
118  trunc_stats_test  |         3 |         0 |         0 |          0 |          0
119  trunc_stats_test1 |         4 |         2 |         1 |          1 |          0
120  trunc_stats_test2 |         1 |         0 |         0 |          1 |          0
121  trunc_stats_test3 |         4 |         0 |         0 |          2 |          2
122  trunc_stats_test4 |         2 |         0 |         0 |          0 |          2
123 (5 rows)
125 SELECT st.seq_scan >= pr.seq_scan + 1,
126        st.seq_tup_read >= pr.seq_tup_read + cl.reltuples,
127        st.idx_scan >= pr.idx_scan + 1,
128        st.idx_tup_fetch >= pr.idx_tup_fetch + 1
129   FROM pg_stat_user_tables AS st, pg_class AS cl, prevstats AS pr
130  WHERE st.relname='tenk2' AND cl.relname='tenk2';
131  ?column? | ?column? | ?column? | ?column? 
132 ----------+----------+----------+----------
133  t        | t        | t        | t
134 (1 row)
136 SELECT st.heap_blks_read + st.heap_blks_hit >= pr.heap_blks + cl.relpages,
137        st.idx_blks_read + st.idx_blks_hit >= pr.idx_blks + 1
138   FROM pg_statio_user_tables AS st, pg_class AS cl, prevstats AS pr
139  WHERE st.relname='tenk2' AND cl.relname='tenk2';
140  ?column? | ?column? 
141 ----------+----------
142  t        | t
143 (1 row)
145 SELECT pr.snap_ts < pg_stat_get_snapshot_timestamp() as snapshot_newer
146 FROM prevstats AS pr;
147  snapshot_newer 
148 ----------------
150 (1 row)
152 COMMIT;
153 ----
154 -- Basic tests for track_functions
156 CREATE FUNCTION stats_test_func1() RETURNS VOID LANGUAGE plpgsql AS $$BEGIN END;$$;
157 SELECT 'stats_test_func1()'::regprocedure::oid AS stats_test_func1_oid \gset
158 CREATE FUNCTION stats_test_func2() RETURNS VOID LANGUAGE plpgsql AS $$BEGIN END;$$;
159 SELECT 'stats_test_func2()'::regprocedure::oid AS stats_test_func2_oid \gset
160 -- test that stats are accumulated
161 BEGIN;
162 SET LOCAL stats_fetch_consistency = none;
163 SELECT pg_stat_get_function_calls(:stats_test_func1_oid);
164  pg_stat_get_function_calls 
165 ----------------------------
166                            
167 (1 row)
169 SELECT pg_stat_get_xact_function_calls(:stats_test_func1_oid);
170  pg_stat_get_xact_function_calls 
171 ---------------------------------
172                                 
173 (1 row)
175 SELECT stats_test_func1();
176  stats_test_func1 
177 ------------------
179 (1 row)
181 SELECT pg_stat_get_xact_function_calls(:stats_test_func1_oid);
182  pg_stat_get_xact_function_calls 
183 ---------------------------------
184                                1
185 (1 row)
187 SELECT stats_test_func1();
188  stats_test_func1 
189 ------------------
191 (1 row)
193 SELECT pg_stat_get_xact_function_calls(:stats_test_func1_oid);
194  pg_stat_get_xact_function_calls 
195 ---------------------------------
196                                2
197 (1 row)
199 SELECT pg_stat_get_function_calls(:stats_test_func1_oid);
200  pg_stat_get_function_calls 
201 ----------------------------
202                           0
203 (1 row)
205 COMMIT;
206 -- Verify that function stats are not transactional
207 -- rolled back savepoint in committing transaction
208 BEGIN;
209 SELECT stats_test_func2();
210  stats_test_func2 
211 ------------------
213 (1 row)
215 SAVEPOINT foo;
216 SELECT stats_test_func2();
217  stats_test_func2 
218 ------------------
220 (1 row)
222 ROLLBACK TO SAVEPOINT foo;
223 SELECT pg_stat_get_xact_function_calls(:stats_test_func2_oid);
224  pg_stat_get_xact_function_calls 
225 ---------------------------------
226                                2
227 (1 row)
229 SELECT stats_test_func2();
230  stats_test_func2 
231 ------------------
233 (1 row)
235 COMMIT;
236 -- rolled back transaction
237 BEGIN;
238 SELECT stats_test_func2();
239  stats_test_func2 
240 ------------------
242 (1 row)
244 ROLLBACK;
245 SELECT pg_stat_force_next_flush();
246  pg_stat_force_next_flush 
247 --------------------------
249 (1 row)
251 -- check collected stats
252 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid;
253      funcname     | calls 
254 ------------------+-------
255  stats_test_func1 |     2
256 (1 row)
258 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func2_oid;
259      funcname     | calls 
260 ------------------+-------
261  stats_test_func2 |     4
262 (1 row)
264 -- check that a rolled back drop function stats leaves stats alive
265 BEGIN;
266 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid;
267      funcname     | calls 
268 ------------------+-------
269  stats_test_func1 |     2
270 (1 row)
272 DROP FUNCTION stats_test_func1();
273 -- shouldn't be visible via view
274 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid;
275  funcname | calls 
276 ----------+-------
277 (0 rows)
279 -- but still via oid access
280 SELECT pg_stat_get_function_calls(:stats_test_func1_oid);
281  pg_stat_get_function_calls 
282 ----------------------------
283                           2
284 (1 row)
286 ROLLBACK;
287 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid;
288      funcname     | calls 
289 ------------------+-------
290  stats_test_func1 |     2
291 (1 row)
293 SELECT pg_stat_get_function_calls(:stats_test_func1_oid);
294  pg_stat_get_function_calls 
295 ----------------------------
296                           2
297 (1 row)
299 -- check that function dropped in main transaction leaves no stats behind
300 BEGIN;
301 DROP FUNCTION stats_test_func1();
302 COMMIT;
303 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func1_oid;
304  funcname | calls 
305 ----------+-------
306 (0 rows)
308 SELECT pg_stat_get_function_calls(:stats_test_func1_oid);
309  pg_stat_get_function_calls 
310 ----------------------------
311                            
312 (1 row)
314 -- check that function dropped in a subtransaction leaves no stats behind
315 BEGIN;
316 SELECT stats_test_func2();
317  stats_test_func2 
318 ------------------
320 (1 row)
322 SAVEPOINT a;
323 SELECT stats_test_func2();
324  stats_test_func2 
325 ------------------
327 (1 row)
329 SAVEPOINT b;
330 DROP FUNCTION stats_test_func2();
331 COMMIT;
332 SELECT funcname, calls FROM pg_stat_user_functions WHERE funcid = :stats_test_func2_oid;
333  funcname | calls 
334 ----------+-------
335 (0 rows)
337 SELECT pg_stat_get_function_calls(:stats_test_func2_oid);
338  pg_stat_get_function_calls 
339 ----------------------------
340                            
341 (1 row)
343 -- Check that stats for relations are dropped. For that we need to access stats
344 -- by oid after the DROP TABLE. Save oids.
345 CREATE TABLE drop_stats_test();
346 INSERT INTO drop_stats_test DEFAULT VALUES;
347 SELECT 'drop_stats_test'::regclass::oid AS drop_stats_test_oid \gset
348 CREATE TABLE drop_stats_test_xact();
349 INSERT INTO drop_stats_test_xact DEFAULT VALUES;
350 SELECT 'drop_stats_test_xact'::regclass::oid AS drop_stats_test_xact_oid \gset
351 CREATE TABLE drop_stats_test_subxact();
352 INSERT INTO drop_stats_test_subxact DEFAULT VALUES;
353 SELECT 'drop_stats_test_subxact'::regclass::oid AS drop_stats_test_subxact_oid \gset
354 SELECT pg_stat_force_next_flush();
355  pg_stat_force_next_flush 
356 --------------------------
358 (1 row)
360 SELECT pg_stat_get_live_tuples(:drop_stats_test_oid);
361  pg_stat_get_live_tuples 
362 -------------------------
363                        1
364 (1 row)
366 DROP TABLE drop_stats_test;
367 SELECT pg_stat_get_live_tuples(:drop_stats_test_oid);
368  pg_stat_get_live_tuples 
369 -------------------------
370                        0
371 (1 row)
373 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_oid);
374  pg_stat_get_xact_tuples_inserted 
375 ----------------------------------
376                                 0
377 (1 row)
379 -- check that rollback protects against having stats dropped and that local
380 -- modifications don't pose a problem
381 SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid);
382  pg_stat_get_live_tuples 
383 -------------------------
384                        1
385 (1 row)
387 SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid);
388  pg_stat_get_tuples_inserted 
389 -----------------------------
390                            1
391 (1 row)
393 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid);
394  pg_stat_get_xact_tuples_inserted 
395 ----------------------------------
396                                 0
397 (1 row)
399 BEGIN;
400 INSERT INTO drop_stats_test_xact DEFAULT VALUES;
401 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid);
402  pg_stat_get_xact_tuples_inserted 
403 ----------------------------------
404                                 1
405 (1 row)
407 DROP TABLE drop_stats_test_xact;
408 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid);
409  pg_stat_get_xact_tuples_inserted 
410 ----------------------------------
411                                 0
412 (1 row)
414 ROLLBACK;
415 SELECT pg_stat_force_next_flush();
416  pg_stat_force_next_flush 
417 --------------------------
419 (1 row)
421 SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid);
422  pg_stat_get_live_tuples 
423 -------------------------
424                        1
425 (1 row)
427 SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid);
428  pg_stat_get_tuples_inserted 
429 -----------------------------
430                            2
431 (1 row)
433 -- transactional drop
434 SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid);
435  pg_stat_get_live_tuples 
436 -------------------------
437                        1
438 (1 row)
440 SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid);
441  pg_stat_get_tuples_inserted 
442 -----------------------------
443                            2
444 (1 row)
446 BEGIN;
447 INSERT INTO drop_stats_test_xact DEFAULT VALUES;
448 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid);
449  pg_stat_get_xact_tuples_inserted 
450 ----------------------------------
451                                 1
452 (1 row)
454 DROP TABLE drop_stats_test_xact;
455 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_xact_oid);
456  pg_stat_get_xact_tuples_inserted 
457 ----------------------------------
458                                 0
459 (1 row)
461 COMMIT;
462 SELECT pg_stat_force_next_flush();
463  pg_stat_force_next_flush 
464 --------------------------
466 (1 row)
468 SELECT pg_stat_get_live_tuples(:drop_stats_test_xact_oid);
469  pg_stat_get_live_tuples 
470 -------------------------
471                        0
472 (1 row)
474 SELECT pg_stat_get_tuples_inserted(:drop_stats_test_xact_oid);
475  pg_stat_get_tuples_inserted 
476 -----------------------------
477                            0
478 (1 row)
480 -- savepoint rollback (2 levels)
481 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
482  pg_stat_get_live_tuples 
483 -------------------------
484                        1
485 (1 row)
487 BEGIN;
488 INSERT INTO drop_stats_test_subxact DEFAULT VALUES;
489 SAVEPOINT sp1;
490 INSERT INTO drop_stats_test_subxact DEFAULT VALUES;
491 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid);
492  pg_stat_get_xact_tuples_inserted 
493 ----------------------------------
494                                 2
495 (1 row)
497 SAVEPOINT sp2;
498 DROP TABLE drop_stats_test_subxact;
499 ROLLBACK TO SAVEPOINT sp2;
500 SELECT pg_stat_get_xact_tuples_inserted(:drop_stats_test_subxact_oid);
501  pg_stat_get_xact_tuples_inserted 
502 ----------------------------------
503                                 2
504 (1 row)
506 COMMIT;
507 SELECT pg_stat_force_next_flush();
508  pg_stat_force_next_flush 
509 --------------------------
511 (1 row)
513 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
514  pg_stat_get_live_tuples 
515 -------------------------
516                        3
517 (1 row)
519 -- savepoint rolback (1 level)
520 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
521  pg_stat_get_live_tuples 
522 -------------------------
523                        3
524 (1 row)
526 BEGIN;
527 SAVEPOINT sp1;
528 DROP TABLE drop_stats_test_subxact;
529 SAVEPOINT sp2;
530 ROLLBACK TO SAVEPOINT sp1;
531 COMMIT;
532 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
533  pg_stat_get_live_tuples 
534 -------------------------
535                        3
536 (1 row)
538 -- and now actually drop
539 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
540  pg_stat_get_live_tuples 
541 -------------------------
542                        3
543 (1 row)
545 BEGIN;
546 SAVEPOINT sp1;
547 DROP TABLE drop_stats_test_subxact;
548 SAVEPOINT sp2;
549 RELEASE SAVEPOINT sp1;
550 COMMIT;
551 SELECT pg_stat_get_live_tuples(:drop_stats_test_subxact_oid);
552  pg_stat_get_live_tuples 
553 -------------------------
554                        0
555 (1 row)
557 DROP TABLE trunc_stats_test, trunc_stats_test1, trunc_stats_test2, trunc_stats_test3, trunc_stats_test4;
558 DROP TABLE prevstats;
559 -----
560 -- Test that last_seq_scan, last_idx_scan are correctly maintained
562 -- Perform test using a temporary table. That way autovacuum etc won't
563 -- interfere. To be able to check that timestamps increase, we sleep for 100ms
564 -- between tests, assuming that there aren't systems with a coarser timestamp
565 -- granularity.
566 -----
567 BEGIN;
568 CREATE TEMPORARY TABLE test_last_scan(idx_col int primary key, noidx_col int);
569 INSERT INTO test_last_scan(idx_col, noidx_col) VALUES(1, 1);
570 SELECT pg_stat_force_next_flush();
571  pg_stat_force_next_flush 
572 --------------------------
574 (1 row)
576 SELECT last_seq_scan, last_idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass;
577  last_seq_scan | last_idx_scan 
578 ---------------+---------------
579                | 
580 (1 row)
582 COMMIT;
583 SELECT pg_stat_reset_single_table_counters('test_last_scan'::regclass);
584  pg_stat_reset_single_table_counters 
585 -------------------------------------
587 (1 row)
589 SELECT seq_scan, idx_scan FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass;
590  seq_scan | idx_scan 
591 ----------+----------
592         0 |        0
593 (1 row)
595 -- ensure we start out with exactly one index and sequential scan
596 BEGIN;
597 SET LOCAL enable_seqscan TO on;
598 SET LOCAL enable_indexscan TO on;
599 SET LOCAL enable_bitmapscan TO off;
600 EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE noidx_col = 1;
601             QUERY PLAN            
602 ----------------------------------
603  Aggregate
604    ->  Seq Scan on test_last_scan
605          Filter: (noidx_col = 1)
606 (3 rows)
608 SELECT count(*) FROM test_last_scan WHERE noidx_col = 1;
609  count 
610 -------
611      1
612 (1 row)
614 SET LOCAL enable_seqscan TO off;
615 EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
616                           QUERY PLAN                          
617 --------------------------------------------------------------
618  Aggregate
619    ->  Index Scan using test_last_scan_pkey on test_last_scan
620          Index Cond: (idx_col = 1)
621 (3 rows)
623 SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
624  count 
625 -------
626      1
627 (1 row)
629 SELECT pg_stat_force_next_flush();
630  pg_stat_force_next_flush 
631 --------------------------
633 (1 row)
635 COMMIT;
636 -- fetch timestamps from before the next test
637 SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx
638 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset
639 SELECT pg_sleep(0.1); -- assume a minimum timestamp granularity of 100ms
640  pg_sleep 
641 ----------
643 (1 row)
645 -- cause one sequential scan
646 BEGIN;
647 SET LOCAL enable_seqscan TO on;
648 SET LOCAL enable_indexscan TO off;
649 SET LOCAL enable_bitmapscan TO off;
650 EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE noidx_col = 1;
651             QUERY PLAN            
652 ----------------------------------
653  Aggregate
654    ->  Seq Scan on test_last_scan
655          Filter: (noidx_col = 1)
656 (3 rows)
658 SELECT count(*) FROM test_last_scan WHERE noidx_col = 1;
659  count 
660 -------
661      1
662 (1 row)
664 SELECT pg_stat_force_next_flush();
665  pg_stat_force_next_flush 
666 --------------------------
668 (1 row)
670 COMMIT;
671 -- check that just sequential scan stats were incremented
672 SELECT seq_scan, :'test_last_seq' < last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' = last_idx_scan AS idx_ok
673 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass;
674  seq_scan | seq_ok | idx_scan | idx_ok 
675 ----------+--------+----------+--------
676         2 | t      |        1 | t
677 (1 row)
679 -- fetch timestamps from before the next test
680 SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx
681 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset
682 SELECT pg_sleep(0.1);
683  pg_sleep 
684 ----------
686 (1 row)
688 -- cause one index scan
689 BEGIN;
690 SET LOCAL enable_seqscan TO off;
691 SET LOCAL enable_indexscan TO on;
692 SET LOCAL enable_bitmapscan TO off;
693 EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
694                           QUERY PLAN                          
695 --------------------------------------------------------------
696  Aggregate
697    ->  Index Scan using test_last_scan_pkey on test_last_scan
698          Index Cond: (idx_col = 1)
699 (3 rows)
701 SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
702  count 
703 -------
704      1
705 (1 row)
707 SELECT pg_stat_force_next_flush();
708  pg_stat_force_next_flush 
709 --------------------------
711 (1 row)
713 COMMIT;
714 -- check that just index scan stats were incremented
715 SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok
716 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass;
717  seq_scan | seq_ok | idx_scan | idx_ok 
718 ----------+--------+----------+--------
719         2 | t      |        2 | t
720 (1 row)
722 -- fetch timestamps from before the next test
723 SELECT last_seq_scan AS test_last_seq, last_idx_scan AS test_last_idx
724 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass \gset
725 SELECT pg_sleep(0.1);
726  pg_sleep 
727 ----------
729 (1 row)
731 -- cause one bitmap index scan
732 BEGIN;
733 SET LOCAL enable_seqscan TO off;
734 SET LOCAL enable_indexscan TO off;
735 SET LOCAL enable_bitmapscan TO on;
736 EXPLAIN (COSTS off) SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
737                       QUERY PLAN                      
738 ------------------------------------------------------
739  Aggregate
740    ->  Bitmap Heap Scan on test_last_scan
741          Recheck Cond: (idx_col = 1)
742          ->  Bitmap Index Scan on test_last_scan_pkey
743                Index Cond: (idx_col = 1)
744 (5 rows)
746 SELECT count(*) FROM test_last_scan WHERE idx_col = 1;
747  count 
748 -------
749      1
750 (1 row)
752 SELECT pg_stat_force_next_flush();
753  pg_stat_force_next_flush 
754 --------------------------
756 (1 row)
758 COMMIT;
759 -- check that just index scan stats were incremented
760 SELECT seq_scan, :'test_last_seq' = last_seq_scan AS seq_ok, idx_scan, :'test_last_idx' < last_idx_scan AS idx_ok
761 FROM pg_stat_all_tables WHERE relid = 'test_last_scan'::regclass;
762  seq_scan | seq_ok | idx_scan | idx_ok 
763 ----------+--------+----------+--------
764         2 | t      |        3 | t
765 (1 row)
767 -----
768 -- Test reset of some stats for shared table
769 -----
770 -- This updates the comment of the database currently in use in
771 -- pg_shdescription with a fake value, then sets it back to its
772 -- original value.
773 SELECT shobj_description(d.oid, 'pg_database') as description_before
774   FROM pg_database d WHERE datname = current_database() \gset
775 -- force some stats in pg_shdescription.
776 BEGIN;
777 SELECT current_database() as datname \gset
778 COMMENT ON DATABASE :"datname" IS 'This is a test comment';
779 SELECT pg_stat_force_next_flush();
780  pg_stat_force_next_flush 
781 --------------------------
783 (1 row)
785 COMMIT;
786 -- check that the stats are reset.
787 SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables
788   WHERE relid = 'pg_shdescription'::regclass;
789  has_data 
790 ----------
792 (1 row)
794 SELECT pg_stat_reset_single_table_counters('pg_shdescription'::regclass);
795  pg_stat_reset_single_table_counters 
796 -------------------------------------
798 (1 row)
800 SELECT (n_tup_ins + n_tup_upd) > 0 AS has_data FROM pg_stat_all_tables
801   WHERE relid = 'pg_shdescription'::regclass;
802  has_data 
803 ----------
805 (1 row)
807 -- set back comment
808 \if :{?description_before}
809   COMMENT ON DATABASE :"datname" IS :'description_before';
810 \else
811   COMMENT ON DATABASE :"datname" IS NULL;
812 \endif
813 -----
814 -- Test that various stats views are being properly populated
815 -----
816 -- Test that sessions is incremented when a new session is started in pg_stat_database
817 SELECT sessions AS db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
819 SELECT pg_stat_force_next_flush();
820  pg_stat_force_next_flush 
821 --------------------------
823 (1 row)
825 SELECT sessions > :db_stat_sessions FROM pg_stat_database WHERE datname = (SELECT current_database());
826  ?column? 
827 ----------
829 (1 row)
831 -- Test pg_stat_checkpointer checkpointer-related stats, together with pg_stat_wal
832 SELECT num_requested AS rqst_ckpts_before FROM pg_stat_checkpointer \gset
833 -- Test pg_stat_wal (and make a temp table so our temp schema exists)
834 SELECT wal_bytes AS wal_bytes_before FROM pg_stat_wal \gset
835 CREATE TEMP TABLE test_stats_temp AS SELECT 17;
836 DROP TABLE test_stats_temp;
837 -- Checkpoint twice: The checkpointer reports stats after reporting completion
838 -- of the checkpoint. But after a second checkpoint we'll see at least the
839 -- results of the first.
840 CHECKPOINT;
841 CHECKPOINT;
842 SELECT num_requested > :rqst_ckpts_before FROM pg_stat_checkpointer;
843  ?column? 
844 ----------
846 (1 row)
848 SELECT wal_bytes > :wal_bytes_before FROM pg_stat_wal;
849  ?column? 
850 ----------
852 (1 row)
854 -- Test pg_stat_get_backend_idset() and some allied functions.
855 -- In particular, verify that their notion of backend ID matches
856 -- our temp schema index.
857 SELECT (current_schemas(true))[1] = ('pg_temp_' || beid::text) AS match
858 FROM pg_stat_get_backend_idset() beid
859 WHERE pg_stat_get_backend_pid(beid) = pg_backend_pid();
860  match 
861 -------
863 (1 row)
865 -----
866 -- Test that resetting stats works for reset timestamp
867 -----
868 -- Test that reset_slru with a specified SLRU works.
869 SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'commit_timestamp' \gset
870 SELECT stats_reset AS slru_notify_reset_ts FROM pg_stat_slru WHERE name = 'notify' \gset
871 SELECT pg_stat_reset_slru('commit_timestamp');
872  pg_stat_reset_slru 
873 --------------------
875 (1 row)
877 SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'commit_timestamp';
878  ?column? 
879 ----------
881 (1 row)
883 SELECT stats_reset AS slru_commit_ts_reset_ts FROM pg_stat_slru WHERE name = 'commit_timestamp' \gset
884 -- Test that multiple SLRUs are reset when no specific SLRU provided to reset function
885 SELECT pg_stat_reset_slru();
886  pg_stat_reset_slru 
887 --------------------
889 (1 row)
891 SELECT stats_reset > :'slru_commit_ts_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'commit_timestamp';
892  ?column? 
893 ----------
895 (1 row)
897 SELECT stats_reset > :'slru_notify_reset_ts'::timestamptz FROM pg_stat_slru WHERE name = 'notify';
898  ?column? 
899 ----------
901 (1 row)
903 -- Test that reset_shared with archiver specified as the stats type works
904 SELECT stats_reset AS archiver_reset_ts FROM pg_stat_archiver \gset
905 SELECT pg_stat_reset_shared('archiver');
906  pg_stat_reset_shared 
907 ----------------------
909 (1 row)
911 SELECT stats_reset > :'archiver_reset_ts'::timestamptz FROM pg_stat_archiver;
912  ?column? 
913 ----------
915 (1 row)
917 -- Test that reset_shared with bgwriter specified as the stats type works
918 SELECT stats_reset AS bgwriter_reset_ts FROM pg_stat_bgwriter \gset
919 SELECT pg_stat_reset_shared('bgwriter');
920  pg_stat_reset_shared 
921 ----------------------
923 (1 row)
925 SELECT stats_reset > :'bgwriter_reset_ts'::timestamptz FROM pg_stat_bgwriter;
926  ?column? 
927 ----------
929 (1 row)
931 -- Test that reset_shared with checkpointer specified as the stats type works
932 SELECT stats_reset AS checkpointer_reset_ts FROM pg_stat_checkpointer \gset
933 SELECT pg_stat_reset_shared('checkpointer');
934  pg_stat_reset_shared 
935 ----------------------
937 (1 row)
939 SELECT stats_reset > :'checkpointer_reset_ts'::timestamptz FROM pg_stat_checkpointer;
940  ?column? 
941 ----------
943 (1 row)
945 -- Test that reset_shared with recovery_prefetch specified as the stats type works
946 SELECT stats_reset AS recovery_prefetch_reset_ts FROM pg_stat_recovery_prefetch \gset
947 SELECT pg_stat_reset_shared('recovery_prefetch');
948  pg_stat_reset_shared 
949 ----------------------
951 (1 row)
953 SELECT stats_reset > :'recovery_prefetch_reset_ts'::timestamptz FROM pg_stat_recovery_prefetch;
954  ?column? 
955 ----------
957 (1 row)
959 -- Test that reset_shared with slru specified as the stats type works
960 SELECT max(stats_reset) AS slru_reset_ts FROM pg_stat_slru \gset
961 SELECT pg_stat_reset_shared('slru');
962  pg_stat_reset_shared 
963 ----------------------
965 (1 row)
967 SELECT max(stats_reset) > :'slru_reset_ts'::timestamptz FROM pg_stat_slru;
968  ?column? 
969 ----------
971 (1 row)
973 -- Test that reset_shared with wal specified as the stats type works
974 SELECT stats_reset AS wal_reset_ts FROM pg_stat_wal \gset
975 SELECT pg_stat_reset_shared('wal');
976  pg_stat_reset_shared 
977 ----------------------
979 (1 row)
981 SELECT stats_reset > :'wal_reset_ts'::timestamptz FROM pg_stat_wal;
982  ?column? 
983 ----------
985 (1 row)
987 -- Test error case for reset_shared with unknown stats type
988 SELECT pg_stat_reset_shared('unknown');
989 ERROR:  unrecognized reset target: "unknown"
990 HINT:  Target must be "archiver", "bgwriter", "checkpointer", "io", "recovery_prefetch", "slru", or "wal".
991 -- Test that reset works for pg_stat_database
992 -- Since pg_stat_database stats_reset starts out as NULL, reset it once first so we have something to compare it to
993 SELECT pg_stat_reset();
994  pg_stat_reset 
995 ---------------
997 (1 row)
999 SELECT stats_reset AS db_reset_ts FROM pg_stat_database WHERE datname = (SELECT current_database()) \gset
1000 SELECT pg_stat_reset();
1001  pg_stat_reset 
1002 ---------------
1004 (1 row)
1006 SELECT stats_reset > :'db_reset_ts'::timestamptz FROM pg_stat_database WHERE datname = (SELECT current_database());
1007  ?column? 
1008 ----------
1010 (1 row)
1012 ----
1013 -- pg_stat_get_snapshot_timestamp behavior
1014 ----
1015 BEGIN;
1016 SET LOCAL stats_fetch_consistency = snapshot;
1017 -- no snapshot yet, return NULL
1018 SELECT pg_stat_get_snapshot_timestamp();
1019  pg_stat_get_snapshot_timestamp 
1020 --------------------------------
1022 (1 row)
1024 -- any attempt at accessing stats will build snapshot
1025 SELECT pg_stat_get_function_calls(0);
1026  pg_stat_get_function_calls 
1027 ----------------------------
1028                            
1029 (1 row)
1031 SELECT pg_stat_get_snapshot_timestamp() >= NOW();
1032  ?column? 
1033 ----------
1035 (1 row)
1037 -- shows NULL again after clearing
1038 SELECT pg_stat_clear_snapshot();
1039  pg_stat_clear_snapshot 
1040 ------------------------
1042 (1 row)
1044 SELECT pg_stat_get_snapshot_timestamp();
1045  pg_stat_get_snapshot_timestamp 
1046 --------------------------------
1048 (1 row)
1050 COMMIT;
1051 ----
1052 -- Changing stats_fetch_consistency in a transaction.
1053 ----
1054 BEGIN;
1055 -- Stats filled under the cache mode
1056 SET LOCAL stats_fetch_consistency = cache;
1057 SELECT pg_stat_get_function_calls(0);
1058  pg_stat_get_function_calls 
1059 ----------------------------
1060                            
1061 (1 row)
1063 SELECT pg_stat_get_snapshot_timestamp() IS NOT NULL AS snapshot_ok;
1064  snapshot_ok 
1065 -------------
1067 (1 row)
1069 -- Success in accessing pre-existing snapshot data.
1070 SET LOCAL stats_fetch_consistency = snapshot;
1071 SELECT pg_stat_get_snapshot_timestamp() IS NOT NULL AS snapshot_ok;
1072  snapshot_ok 
1073 -------------
1075 (1 row)
1077 SELECT pg_stat_get_function_calls(0);
1078  pg_stat_get_function_calls 
1079 ----------------------------
1080                            
1081 (1 row)
1083 SELECT pg_stat_get_snapshot_timestamp() IS NOT NULL AS snapshot_ok;
1084  snapshot_ok 
1085 -------------
1087 (1 row)
1089 -- Snapshot cleared.
1090 SET LOCAL stats_fetch_consistency = none;
1091 SELECT pg_stat_get_snapshot_timestamp() IS NOT NULL AS snapshot_ok;
1092  snapshot_ok 
1093 -------------
1095 (1 row)
1097 SELECT pg_stat_get_function_calls(0);
1098  pg_stat_get_function_calls 
1099 ----------------------------
1100                            
1101 (1 row)
1103 SELECT pg_stat_get_snapshot_timestamp() IS NOT NULL AS snapshot_ok;
1104  snapshot_ok 
1105 -------------
1107 (1 row)
1109 ROLLBACK;
1110 ----
1111 -- pg_stat_have_stats behavior
1112 ----
1113 -- fixed-numbered stats exist
1114 SELECT pg_stat_have_stats('bgwriter', 0, 0);
1115  pg_stat_have_stats 
1116 --------------------
1118 (1 row)
1120 -- unknown stats kinds error out
1121 SELECT pg_stat_have_stats('zaphod', 0, 0);
1122 ERROR:  invalid statistics kind: "zaphod"
1123 -- db stats have objid 0
1124 SELECT pg_stat_have_stats('database', :dboid, 1);
1125  pg_stat_have_stats 
1126 --------------------
1128 (1 row)
1130 SELECT pg_stat_have_stats('database', :dboid, 0);
1131  pg_stat_have_stats 
1132 --------------------
1134 (1 row)
1136 -- pg_stat_have_stats returns true for committed index creation
1137 CREATE table stats_test_tab1 as select generate_series(1,10) a;
1138 CREATE index stats_test_idx1 on stats_test_tab1(a);
1139 SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
1140 SET enable_seqscan TO off;
1141 select a from stats_test_tab1 where a = 3;
1142  a 
1145 (1 row)
1147 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1148  pg_stat_have_stats 
1149 --------------------
1151 (1 row)
1153 -- pg_stat_have_stats returns false for dropped index with stats
1154 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1155  pg_stat_have_stats 
1156 --------------------
1158 (1 row)
1160 DROP index stats_test_idx1;
1161 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1162  pg_stat_have_stats 
1163 --------------------
1165 (1 row)
1167 -- pg_stat_have_stats returns false for rolled back index creation
1168 BEGIN;
1169 CREATE index stats_test_idx1 on stats_test_tab1(a);
1170 SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
1171 select a from stats_test_tab1 where a = 3;
1172  a 
1175 (1 row)
1177 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1178  pg_stat_have_stats 
1179 --------------------
1181 (1 row)
1183 ROLLBACK;
1184 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1185  pg_stat_have_stats 
1186 --------------------
1188 (1 row)
1190 -- pg_stat_have_stats returns true for reindex CONCURRENTLY
1191 CREATE index stats_test_idx1 on stats_test_tab1(a);
1192 SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
1193 select a from stats_test_tab1 where a = 3;
1194  a 
1197 (1 row)
1199 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1200  pg_stat_have_stats 
1201 --------------------
1203 (1 row)
1205 REINDEX index CONCURRENTLY stats_test_idx1;
1206 -- false for previous oid
1207 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1208  pg_stat_have_stats 
1209 --------------------
1211 (1 row)
1213 -- true for new oid
1214 SELECT 'stats_test_idx1'::regclass::oid AS stats_test_idx1_oid \gset
1215 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1216  pg_stat_have_stats 
1217 --------------------
1219 (1 row)
1221 -- pg_stat_have_stats returns true for a rolled back drop index with stats
1222 BEGIN;
1223 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1224  pg_stat_have_stats 
1225 --------------------
1227 (1 row)
1229 DROP index stats_test_idx1;
1230 ROLLBACK;
1231 SELECT pg_stat_have_stats('relation', :dboid, :stats_test_idx1_oid);
1232  pg_stat_have_stats 
1233 --------------------
1235 (1 row)
1237 -- put enable_seqscan back to on
1238 SET enable_seqscan TO on;
1239 -- ensure that stats accessors handle NULL input correctly
1240 SELECT pg_stat_get_replication_slot(NULL);
1241  pg_stat_get_replication_slot 
1242 ------------------------------
1244 (1 row)
1246 SELECT pg_stat_get_subscription_stats(NULL);
1247  pg_stat_get_subscription_stats 
1248 --------------------------------
1250 (1 row)
1252 -- Test that the following operations are tracked in pg_stat_io and in
1253 -- backend stats:
1254 -- - reads of target blocks into shared buffers
1255 -- - writes of shared buffers to permanent storage
1256 -- - extends of relations using shared buffers
1257 -- - fsyncs done to ensure the durability of data dirtying shared buffers
1258 -- - shared buffer hits
1259 -- There is no test for blocks evicted from shared buffers, because we cannot
1260 -- be sure of the state of shared buffers at the point the test is run.
1261 -- Create a regular table and insert some data to generate IOCONTEXT_NORMAL
1262 -- extends.
1263 SELECT pid AS checkpointer_pid FROM pg_stat_activity
1264   WHERE backend_type = 'checkpointer' \gset
1265 SELECT sum(extends) AS io_sum_shared_before_extends
1266   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
1267 SELECT sum(extends) AS my_io_sum_shared_before_extends
1268   FROM pg_stat_get_backend_io(pg_backend_pid())
1269   WHERE context = 'normal' AND object = 'relation' \gset
1270 SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1271   FROM pg_stat_io
1272   WHERE object = 'relation' \gset io_sum_shared_before_
1273 SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1274   FROM pg_stat_get_backend_io(pg_backend_pid())
1275   WHERE object = 'relation' \gset my_io_sum_shared_before_
1276 CREATE TABLE test_io_shared(a int);
1277 INSERT INTO test_io_shared SELECT i FROM generate_series(1,100)i;
1278 SELECT pg_stat_force_next_flush();
1279  pg_stat_force_next_flush 
1280 --------------------------
1282 (1 row)
1284 SELECT sum(extends) AS io_sum_shared_after_extends
1285   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
1286 SELECT :io_sum_shared_after_extends > :io_sum_shared_before_extends;
1287  ?column? 
1288 ----------
1290 (1 row)
1292 SELECT sum(extends) AS my_io_sum_shared_after_extends
1293   FROM pg_stat_get_backend_io(pg_backend_pid())
1294   WHERE context = 'normal' AND object = 'relation' \gset
1295 SELECT :my_io_sum_shared_after_extends > :my_io_sum_shared_before_extends;
1296  ?column? 
1297 ----------
1299 (1 row)
1301 -- After a checkpoint, there should be some additional IOCONTEXT_NORMAL writes
1302 -- and fsyncs in the global stats (usually not for the backend).
1303 -- See comment above for rationale for two explicit CHECKPOINTs.
1304 CHECKPOINT;
1305 CHECKPOINT;
1306 SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1307   FROM pg_stat_io
1308   WHERE object = 'relation' \gset io_sum_shared_after_
1309 SELECT :io_sum_shared_after_writes > :io_sum_shared_before_writes;
1310  ?column? 
1311 ----------
1313 (1 row)
1315 SELECT current_setting('fsync') = 'off'
1316   OR :io_sum_shared_after_fsyncs > :io_sum_shared_before_fsyncs;
1317  ?column? 
1318 ----------
1320 (1 row)
1322 SELECT sum(writes) AS writes, sum(fsyncs) AS fsyncs
1323   FROM pg_stat_get_backend_io(pg_backend_pid())
1324   WHERE object = 'relation' \gset my_io_sum_shared_after_
1325 SELECT :my_io_sum_shared_after_writes >= :my_io_sum_shared_before_writes;
1326  ?column? 
1327 ----------
1329 (1 row)
1331 SELECT current_setting('fsync') = 'off'
1332   OR :my_io_sum_shared_after_fsyncs >= :my_io_sum_shared_before_fsyncs;
1333  ?column? 
1334 ----------
1336 (1 row)
1338 -- Change the tablespace so that the table is rewritten directly, then SELECT
1339 -- from it to cause it to be read back into shared buffers.
1340 SELECT sum(reads) AS io_sum_shared_before_reads
1341   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
1342 -- Do this in a transaction to prevent spurious failures due to concurrent accesses to our newly
1343 -- rewritten table, e.g. by autovacuum.
1344 BEGIN;
1345 ALTER TABLE test_io_shared SET TABLESPACE regress_tblspace;
1346 -- SELECT from the table so that the data is read into shared buffers and
1347 -- context 'normal', object 'relation' reads are counted.
1348 SELECT COUNT(*) FROM test_io_shared;
1349  count 
1350 -------
1351    100
1352 (1 row)
1354 COMMIT;
1355 SELECT pg_stat_force_next_flush();
1356  pg_stat_force_next_flush 
1357 --------------------------
1359 (1 row)
1361 SELECT sum(reads) AS io_sum_shared_after_reads
1362   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation'  \gset
1363 SELECT :io_sum_shared_after_reads > :io_sum_shared_before_reads;
1364  ?column? 
1365 ----------
1367 (1 row)
1369 SELECT sum(hits) AS io_sum_shared_before_hits
1370   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
1371 -- Select from the table again to count hits.
1372 -- Ensure we generate hits by forcing a nested loop self-join with no
1373 -- materialize node. The outer side's buffer will stay pinned, preventing its
1374 -- eviction, while we loop through the inner side and generate hits.
1375 BEGIN;
1376 SET LOCAL enable_nestloop TO on; SET LOCAL enable_mergejoin TO off;
1377 SET LOCAL enable_hashjoin TO off; SET LOCAL enable_material TO off;
1378 -- ensure plan stays as we expect it to
1379 EXPLAIN (COSTS OFF) SELECT COUNT(*) FROM test_io_shared t1 INNER JOIN test_io_shared t2 USING (a);
1380                 QUERY PLAN                 
1381 -------------------------------------------
1382  Aggregate
1383    ->  Nested Loop
1384          Join Filter: (t1.a = t2.a)
1385          ->  Seq Scan on test_io_shared t1
1386          ->  Seq Scan on test_io_shared t2
1387 (5 rows)
1389 SELECT COUNT(*) FROM test_io_shared t1 INNER JOIN test_io_shared t2 USING (a);
1390  count 
1391 -------
1392    100
1393 (1 row)
1395 COMMIT;
1396 SELECT pg_stat_force_next_flush();
1397  pg_stat_force_next_flush 
1398 --------------------------
1400 (1 row)
1402 SELECT sum(hits) AS io_sum_shared_after_hits
1403   FROM pg_stat_io WHERE context = 'normal' AND object = 'relation' \gset
1404 SELECT :io_sum_shared_after_hits > :io_sum_shared_before_hits;
1405  ?column? 
1406 ----------
1408 (1 row)
1410 DROP TABLE test_io_shared;
1411 -- Test that the follow IOCONTEXT_LOCAL IOOps are tracked in pg_stat_io:
1412 -- - eviction of local buffers in order to reuse them
1413 -- - reads of temporary table blocks into local buffers
1414 -- - writes of local buffers to permanent storage
1415 -- - extends of temporary tables
1416 -- Set temp_buffers to its minimum so that we can trigger writes with fewer
1417 -- inserted tuples. Do so in a new session in case temporary tables have been
1418 -- accessed by previous tests in this session.
1420 SET temp_buffers TO 100;
1421 CREATE TEMPORARY TABLE test_io_local(a int, b TEXT);
1422 SELECT sum(extends) AS extends, sum(evictions) AS evictions, sum(writes) AS writes
1423   FROM pg_stat_io
1424   WHERE context = 'normal' AND object = 'temp relation' \gset io_sum_local_before_
1425 -- Insert tuples into the temporary table, generating extends in the stats.
1426 -- Insert enough values that we need to reuse and write out dirty local
1427 -- buffers, generating evictions and writes.
1428 INSERT INTO test_io_local SELECT generate_series(1, 5000) as id, repeat('a', 200);
1429 -- Ensure the table is large enough to exceed our temp_buffers setting.
1430 SELECT pg_relation_size('test_io_local') / current_setting('block_size')::int8 > 100;
1431  ?column? 
1432 ----------
1434 (1 row)
1436 SELECT sum(reads) AS io_sum_local_before_reads
1437   FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation' \gset
1438 -- Read in evicted buffers, generating reads.
1439 SELECT COUNT(*) FROM test_io_local;
1440  count 
1441 -------
1442   5000
1443 (1 row)
1445 SELECT pg_stat_force_next_flush();
1446  pg_stat_force_next_flush 
1447 --------------------------
1449 (1 row)
1451 SELECT sum(evictions) AS evictions,
1452        sum(reads) AS reads,
1453        sum(writes) AS writes,
1454        sum(extends) AS extends
1455   FROM pg_stat_io
1456   WHERE context = 'normal' AND object = 'temp relation'  \gset io_sum_local_after_
1457 SELECT :io_sum_local_after_evictions > :io_sum_local_before_evictions,
1458        :io_sum_local_after_reads > :io_sum_local_before_reads,
1459        :io_sum_local_after_writes > :io_sum_local_before_writes,
1460        :io_sum_local_after_extends > :io_sum_local_before_extends;
1461  ?column? | ?column? | ?column? | ?column? 
1462 ----------+----------+----------+----------
1463  t        | t        | t        | t
1464 (1 row)
1466 -- Change the tablespaces so that the temporary table is rewritten to other
1467 -- local buffers, exercising a different codepath than standard local buffer
1468 -- writes.
1469 ALTER TABLE test_io_local SET TABLESPACE regress_tblspace;
1470 SELECT pg_stat_force_next_flush();
1471  pg_stat_force_next_flush 
1472 --------------------------
1474 (1 row)
1476 SELECT sum(writes) AS io_sum_local_new_tblspc_writes
1477   FROM pg_stat_io WHERE context = 'normal' AND object = 'temp relation'  \gset
1478 SELECT :io_sum_local_new_tblspc_writes > :io_sum_local_after_writes;
1479  ?column? 
1480 ----------
1482 (1 row)
1484 RESET temp_buffers;
1485 -- Test that reuse of strategy buffers and reads of blocks into these reused
1486 -- buffers while VACUUMing are tracked in pg_stat_io. If there is sufficient
1487 -- demand for shared buffers from concurrent queries, some buffers may be
1488 -- pinned by other backends before they can be reused. In such cases, the
1489 -- backend will evict a buffer from outside the ring and add it to the
1490 -- ring. This is considered an eviction and not a reuse.
1491 -- Set wal_skip_threshold smaller than the expected size of
1492 -- test_io_vac_strategy so that, even if wal_level is minimal, VACUUM FULL will
1493 -- fsync the newly rewritten test_io_vac_strategy instead of writing it to WAL.
1494 -- Writing it to WAL will result in the newly written relation pages being in
1495 -- shared buffers -- preventing us from testing BAS_VACUUM BufferAccessStrategy
1496 -- reads.
1497 SET wal_skip_threshold = '1 kB';
1498 SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
1499   FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_before_
1500 CREATE TABLE test_io_vac_strategy(a int, b int) WITH (autovacuum_enabled = 'false');
1501 INSERT INTO test_io_vac_strategy SELECT i, i from generate_series(1, 4500)i;
1502 -- Ensure that the next VACUUM will need to perform IO by rewriting the table
1503 -- first with VACUUM (FULL).
1504 VACUUM (FULL) test_io_vac_strategy;
1505 -- Use the minimum BUFFER_USAGE_LIMIT to cause reuses or evictions with the
1506 -- smallest table possible.
1507 VACUUM (PARALLEL 0, BUFFER_USAGE_LIMIT 128) test_io_vac_strategy;
1508 SELECT pg_stat_force_next_flush();
1509  pg_stat_force_next_flush 
1510 --------------------------
1512 (1 row)
1514 SELECT sum(reuses) AS reuses, sum(reads) AS reads, sum(evictions) AS evictions
1515   FROM pg_stat_io WHERE context = 'vacuum' \gset io_sum_vac_strategy_after_
1516 SELECT :io_sum_vac_strategy_after_reads > :io_sum_vac_strategy_before_reads;
1517  ?column? 
1518 ----------
1520 (1 row)
1522 SELECT (:io_sum_vac_strategy_after_reuses + :io_sum_vac_strategy_after_evictions) >
1523   (:io_sum_vac_strategy_before_reuses + :io_sum_vac_strategy_before_evictions);
1524  ?column? 
1525 ----------
1527 (1 row)
1529 RESET wal_skip_threshold;
1530 -- Test that extends done by a CTAS, which uses a BAS_BULKWRITE
1531 -- BufferAccessStrategy, are tracked in pg_stat_io.
1532 SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_before
1533   FROM pg_stat_io WHERE context = 'bulkwrite' \gset
1534 CREATE TABLE test_io_bulkwrite_strategy AS SELECT i FROM generate_series(1,100)i;
1535 SELECT pg_stat_force_next_flush();
1536  pg_stat_force_next_flush 
1537 --------------------------
1539 (1 row)
1541 SELECT sum(extends) AS io_sum_bulkwrite_strategy_extends_after
1542   FROM pg_stat_io WHERE context = 'bulkwrite' \gset
1543 SELECT :io_sum_bulkwrite_strategy_extends_after > :io_sum_bulkwrite_strategy_extends_before;
1544  ?column? 
1545 ----------
1547 (1 row)
1549 -- Test IO stats reset
1550 SELECT pg_stat_have_stats('io', 0, 0);
1551  pg_stat_have_stats 
1552 --------------------
1554 (1 row)
1556 SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_pre_reset
1557   FROM pg_stat_io \gset
1558 SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_pre_reset
1559   FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
1560 SELECT pg_stat_reset_shared('io');
1561  pg_stat_reset_shared 
1562 ----------------------
1564 (1 row)
1566 SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS io_stats_post_reset
1567   FROM pg_stat_io \gset
1568 SELECT :io_stats_post_reset < :io_stats_pre_reset;
1569  ?column? 
1570 ----------
1572 (1 row)
1574 SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_reset
1575   FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
1576 -- pg_stat_reset_shared() did not reset backend IO stats
1577 SELECT :my_io_stats_pre_reset <= :my_io_stats_post_reset;
1578  ?column? 
1579 ----------
1581 (1 row)
1583 -- but pg_stat_reset_backend_stats() does
1584 SELECT pg_stat_reset_backend_stats(pg_backend_pid());
1585  pg_stat_reset_backend_stats 
1586 -----------------------------
1588 (1 row)
1590 SELECT sum(evictions) + sum(reuses) + sum(extends) + sum(fsyncs) + sum(reads) + sum(writes) + sum(writebacks) + sum(hits) AS my_io_stats_post_backend_reset
1591   FROM pg_stat_get_backend_io(pg_backend_pid()) \gset
1592 SELECT :my_io_stats_pre_reset > :my_io_stats_post_backend_reset;
1593  ?column? 
1594 ----------
1596 (1 row)
1598 -- Check invalid input for pg_stat_get_backend_io()
1599 SELECT pg_stat_get_backend_io(NULL);
1600  pg_stat_get_backend_io 
1601 ------------------------
1602 (0 rows)
1604 SELECT pg_stat_get_backend_io(0);
1605  pg_stat_get_backend_io 
1606 ------------------------
1607 (0 rows)
1609 -- Auxiliary processes return no data.
1610 SELECT pg_stat_get_backend_io(:checkpointer_pid);
1611  pg_stat_get_backend_io 
1612 ------------------------
1613 (0 rows)
1615 -- test BRIN index doesn't block HOT update
1616 CREATE TABLE brin_hot (
1617   id  integer PRIMARY KEY,
1618   val integer NOT NULL
1619 ) WITH (autovacuum_enabled = off, fillfactor = 70);
1620 INSERT INTO brin_hot SELECT *, 0 FROM generate_series(1, 235);
1621 CREATE INDEX val_brin ON brin_hot using brin(val);
1622 CREATE FUNCTION wait_for_hot_stats() RETURNS void AS $$
1623 DECLARE
1624   start_time timestamptz := clock_timestamp();
1625   updated bool;
1626 BEGIN
1627   -- we don't want to wait forever; loop will exit after 30 seconds
1628   FOR i IN 1 .. 300 LOOP
1629     SELECT (pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid) > 0) INTO updated;
1630     EXIT WHEN updated;
1632     -- wait a little
1633     PERFORM pg_sleep_for('100 milliseconds');
1634     -- reset stats snapshot so we can test again
1635     PERFORM pg_stat_clear_snapshot();
1636   END LOOP;
1637   -- report time waited in postmaster log (where it won't change test output)
1638   RAISE log 'wait_for_hot_stats delayed % seconds',
1639     EXTRACT(epoch FROM clock_timestamp() - start_time);
1641 $$ LANGUAGE plpgsql;
1642 UPDATE brin_hot SET val = -3 WHERE id = 42;
1643 -- We can't just call wait_for_hot_stats() at this point, because we only
1644 -- transmit stats when the session goes idle, and we probably didn't
1645 -- transmit the last couple of counts yet thanks to the rate-limiting logic
1646 -- in pgstat_report_stat().  But instead of waiting for the rate limiter's
1647 -- timeout to elapse, let's just start a new session.  The old one will
1648 -- then send its stats before dying.
1649 \c -
1650 SELECT wait_for_hot_stats();
1651  wait_for_hot_stats 
1652 --------------------
1654 (1 row)
1656 SELECT pg_stat_get_tuples_hot_updated('brin_hot'::regclass::oid);
1657  pg_stat_get_tuples_hot_updated 
1658 --------------------------------
1659                               1
1660 (1 row)
1662 DROP TABLE brin_hot;
1663 DROP FUNCTION wait_for_hot_stats();
1664 -- Test handling of index predicates - updating attributes in precicates
1665 -- should not block HOT when summarizing indexes are involved. We update
1666 -- a row that was not indexed due to the index predicate, and becomes
1667 -- indexable - the HOT-updated tuple is forwarded to the BRIN index.
1668 CREATE TABLE brin_hot_2 (a int, b int);
1669 INSERT INTO brin_hot_2 VALUES (1, 100);
1670 CREATE INDEX ON brin_hot_2 USING brin (b) WHERE a = 2;
1671 UPDATE brin_hot_2 SET a = 2;
1672 EXPLAIN (COSTS OFF) SELECT * FROM brin_hot_2 WHERE a = 2 AND b = 100;
1673             QUERY PLAN             
1674 -----------------------------------
1675  Seq Scan on brin_hot_2
1676    Filter: ((a = 2) AND (b = 100))
1677 (2 rows)
1679 SELECT COUNT(*) FROM brin_hot_2 WHERE a = 2 AND b = 100;
1680  count 
1681 -------
1682      1
1683 (1 row)
1685 SET enable_seqscan = off;
1686 EXPLAIN (COSTS OFF) SELECT * FROM brin_hot_2 WHERE a = 2 AND b = 100;
1687                  QUERY PLAN                  
1688 ---------------------------------------------
1689  Bitmap Heap Scan on brin_hot_2
1690    Recheck Cond: ((b = 100) AND (a = 2))
1691    ->  Bitmap Index Scan on brin_hot_2_b_idx
1692          Index Cond: (b = 100)
1693 (4 rows)
1695 SELECT COUNT(*) FROM brin_hot_2 WHERE a = 2 AND b = 100;
1696  count 
1697 -------
1698      1
1699 (1 row)
1701 DROP TABLE brin_hot_2;
1702 -- Test that updates to indexed columns are still propagated to the
1703 -- BRIN column.
1704 -- https://postgr.es/m/05ebcb44-f383-86e3-4f31-0a97a55634cf@enterprisedb.com
1705 CREATE TABLE brin_hot_3 (a int, filler text) WITH (fillfactor = 10);
1706 INSERT INTO brin_hot_3 SELECT 1, repeat(' ', 500) FROM generate_series(1, 20);
1707 CREATE INDEX ON brin_hot_3 USING brin (a) WITH (pages_per_range = 1);
1708 UPDATE brin_hot_3 SET a = 2;
1709 EXPLAIN (COSTS OFF) SELECT * FROM brin_hot_3 WHERE a = 2;
1710                  QUERY PLAN                  
1711 ---------------------------------------------
1712  Bitmap Heap Scan on brin_hot_3
1713    Recheck Cond: (a = 2)
1714    ->  Bitmap Index Scan on brin_hot_3_a_idx
1715          Index Cond: (a = 2)
1716 (4 rows)
1718 SELECT COUNT(*) FROM brin_hot_3 WHERE a = 2;
1719  count 
1720 -------
1721     20
1722 (1 row)
1724 DROP TABLE brin_hot_3;
1725 SET enable_seqscan = on;
1726 -- End of Stats Test