-- This sample reproduces a bug of "sudden" flip of a server-prepared statement in PG 9.2+ -- In this particular case, backend selects very bad index even though bind values are the same and the table is analyzed -- Note: this example uses a single table to simplify the query. In real life, exactly the same issue happens when joining several tables. -- Tested in -- PostgreSQL 9.4.4 on x86_64-unknown-linux-gnu, compiled by gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-11), 64-bit -- PostgreSQL 9.5rc1 on x86_64-apple-darwin15.2.0, compiled by Apple LLVM version 7.0.0 (clang-700.1.76), 64-bit drop table plan_flipper; -- Create test table of 300 MiB -- skewed column has 2 rows for each value on average, and 1'000'000 rows for value 0. -- non_skewed column has always 10 rows for each value create table plan_flipper(id int, skewed int, non_skewed int, padding varchar); insert into plan_flipper(id, skewed, non_skewed, padding) select g.i as id, 0 as skewed, mod(g.i, 100000) as non_skewed, lpad(' ', 100, ' ') from generate_series(1,1000000) as g(i); insert into plan_flipper(id, skewed, non_skewed, padding) select g.i as id, g.i as skewed, mod(g.i, 100000) as non_skewed, lpad(' ', 100, ' ') from generate_series(1000001,2000000) as g(i); create index skewed__flipper ON plan_flipper(skewed); create index non_skewed__flipper ON plan_flipper(non_skewed); commit; vacuum analyze plan_flipper; deallocate flipper; prepare flipper(int, int) as select * from plan_flipper where skewed = $1 and non_skewed = $2; explain (ANALYZE, BUFFERS) execute flipper(0, 42); 9.4.4: 1st-5th executions (as expected, PG picks non_skewed index) "Index Scan using non_skewed__flipper on plan_flipper (cost=0.43..42.77 rows=10 width=113) (actual time=0.030..0.072 rows=10 loops=1)" " Index Cond: (non_skewed = 42)" " Filter: (skewed = 0)" " Rows Removed by Filter: 10" " Buffers: shared hit=20 read=3" "Execution time: 0.094 ms" 6th execution (backend picks skewed index): "Index Scan using skewed__flipper on plan_flipper (cost=0.43..6.77 rows=1 width=113) (actual time=0.067..355.867 rows=10 loops=1)" " Index Cond: (skewed = $1)" " Filter: (non_skewed = $2)" " Rows Removed by Filter: 999990" " Buffers: shared hit=18182 read=2735" "Execution time: 355.901 ms" 9.5rc1: 1st "Bitmap Heap Scan on plan_flipper (cost=4.58..83.47 rows=10 width=113) (actual time=0.033..0.088 rows=10 loops=1)" " Recheck Cond: (non_skewed = 42)" " Filter: (skewed = 0)" " Rows Removed by Filter: 10" " Heap Blocks: exact=20" " Buffers: shared hit=8 read=15" " -> Bitmap Index Scan on non_skewed__flipper (cost=0.00..4.58 rows=20 width=0) (actual time=0.021..0.021 rows=20 loops=1)" " Index Cond: (non_skewed = 42)" " Buffers: shared read=3" "Execution time: 0.106 ms" 2nd "Bitmap Heap Scan on plan_flipper (cost=4.58..83.47 rows=10 width=113) (actual time=0.018..0.035 rows=10 loops=1)" " Recheck Cond: (non_skewed = 42)" " Filter: (skewed = 0)" " Rows Removed by Filter: 10" " Heap Blocks: exact=20" " Buffers: shared hit=23" " -> Bitmap Index Scan on non_skewed__flipper (cost=0.00..4.58 rows=20 width=0) (actual time=0.012..0.012 rows=20 loops=1)" " Index Cond: (non_skewed = 42)" " Buffers: shared hit=3" "Execution time: 0.053 ms" 6th "Index Scan using skewed__flipper on plan_flipper (cost=0.43..10.79 rows=1 width=113) (actual time=0.062..260.546 rows=10 loops=1)" " Index Cond: (skewed = $1)" " Filter: (non_skewed = $2)" " Rows Removed by Filter: 999990" " Buffers: shared hit=10 read=20907 written=13966" "Execution time: 260.577 ms"