Sometimes the execution plan given by PG is not optimal for many reasons. When we need to manually specify the execution path, we can load the plug-in pg_hint_plan.
1 Install the plug-in
Preinstall Postgresql10.7
cd postgresql-10.7/contrib/ wget /ossc-db/pg_hint_plan/archive/REL10_1_3_3. tar xzvf pg_hint_plan-REL10_1_3_3. cd pg_hint_plan-REL10_1_3_3 make make install
Check the file
cd $PGHOME ls lib/pg_hint_plan.so lib/pg_hint_plan.so ls share/extension/ pg_hint_plan--1.3.0--1.3. pg_hint_plan--1.3.2--1.3. pg_hint_plan.control pg_hint_plan--1.3.1--1.3. pg_hint_plan--1.3. plpgsql--1. plpgsql--unpackaged--1.
2 Loading the plugin
2.1 The current session is loading
LOAD 'pg_hint_plan';
Note that this loading only takes effect on the current reply.
2.2 User and library level automatic loading
alter user postgres set session_preload_libraries='pg_hint_plan'; alter database postgres set session_preload_libraries='pg_hint_plan';
If the configuration is wrong, you won't even go to the database!
If the configuration is wrong, connect to the template1 library to execute
alter database postgres reset session_preload_libraries; alter user postgres reset session_preload_libraries;
2.3 cluster-level automatic loading
Modify inshared_preload_libraries=‘pg_hint_plan'
Restart the database
3 Check if it has been loaded
After pg_hint_plan is loaded, it cannot be seen in the extension, so you need to confirm whether the plug-in has been loaded.
show session_preload_libraries; session_preload_libraries --------------------------- pg_hint_plan
or
show shared_preload_libraries;
If loading is used, there is no need to check it.
4 Use plugins to customize execution plans
4.1 Initialize the test data
create table t1 (id int, t int, name varchar(255)); create table t2 (id int , salary int); create table t3 (id int , age int); insert into t1 values (1,200,'jack'); insert into t1 values (2,300,'tom'); insert into t1 values (3,400,'john'); insert into t2 values (1,40000); insert into t2 values (2,38000); insert into t2 values (3,18000); insert into t3 values (3,38); insert into t3 values (2,55); insert into t3 values (1,12); explain analyze select * from t1 left join t2 on = left join t3 on =; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------- Hash Right Join (cost=89.82..337.92 rows=17877 width=540) (actual time=0.053..0.059 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t3 (cost=0.00..32.60 rows=2260 width=8) (actual time=0.002..0.002 rows=3 loops=1) -> Hash (cost=70.05..70.05 rows=1582 width=532) (actual time=0.042..0.043 rows=3 loops=1) Buckets: 2048 Batches: 1 Memory Usage: 17kB -> Hash Right Join (cost=13.15..70.05 rows=1582 width=532) (actual time=0.034..0.039 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t2 (cost=0.00..32.60 rows=2260 width=8) (actual time=0.002..0.002 rows=3 loops=1) -> Hash (cost=11.40..11.40 rows=140 width=524) (actual time=0.017..0.017 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t1 (cost=0.00..11.40 rows=140 width=524) (actual time=0.010..0.011 rows=3 loops=1) Planning time: 0.154 ms Execution time: 0.133 ms
Create an index
create index idx_t1_id on t1(id); create index idx_t2_id on t2(id); create index idx_t3_id on t3(id); explain analyze select * from t1 left join t2 on = left join t3 on =; QUERY PLAN -------------------------------------------------------------------------------------------------------------- Hash Left Join (cost=2.14..3.25 rows=3 width=540) (actual time=0.045..0.047 rows=3 loops=1) Hash Cond: ( = ) -> Hash Left Join (cost=1.07..2.14 rows=3 width=532) (actual time=0.030..0.032 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t1 (cost=0.00..1.03 rows=3 width=524) (actual time=0.005..0.006 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.007..0.007 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.005..0.005 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t3 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.002 rows=3 loops=1) Planning time: 0.305 ms Execution time: 0.128 ms
4.2 Forced index scan
/*+ indexscan(t1 idx_d) /*+ indexscan(t1 idx_t1_id) explain (analyze,buffers) select * from t1 where id=2; QUERY PLAN ---------------------------------------------------------------------------------------------- Seq Scan on t1 (cost=0.00..1.04 rows=1 width=524) (actual time=0.011..0.013 rows=1 loops=1) Filter: (id = 2) Rows Removed by Filter: 2 Buffers: shared hit=1 Planning time: 0.058 ms Execution time: 0.028 ms explain (analyze,buffers) /*+ indexscan(t1) */select * from t1 where id=2; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using idx_t1_id on t1 (cost=0.13..8.15 rows=1 width=524) (actual time=0.044..0.046 rows=1 loops=1) Index Cond: (id = 2) Buffers: shared hit=1 read=1 Planning time: 0.145 ms Execution time: 0.072 ms explain (analyze,buffers) /*+ indexscan(t1 idx_t1_id) */select * from t1 where id=2; QUERY PLAN ---------------------------------------------------------------------------------------------------------------- Index Scan using idx_t1_id on t1 (cost=0.13..8.15 rows=1 width=524) (actual time=0.016..0.017 rows=1 loops=1) Index Cond: (id = 2) Buffers: shared hit=2 Planning time: 0.079 ms Execution time: 0.035 ms
4.3 Forced multi-condition combination
/*+ indexscan(t2) indexscan(t1 idx_t1_id) */ /*+ seqscan(t2) indexscan(t1 idx_t1_id) */ explain analyze SELECT * FROM t1 JOIN t2 ON ( = ); QUERY PLAN -------------------------------------------------------------------------------------------------------- Hash Join (cost=1.07..2.14 rows=3 width=532) (actual time=0.018..0.020 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t1 (cost=0.00..1.03 rows=3 width=524) (actual time=0.006..0.007 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.005..0.005 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.001..0.003 rows=3 loops=1) Planning time: 0.114 ms Execution time: 0.055 ms (8 rows)
Combining two conditions to go indexscan
/*+ indexscan(t2) indexscan(t1 idx_t1_id) */explain analyze SELECT * FROM t1 JOIN t2 ON ( = ); QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Merge Join (cost=0.26..24.40 rows=3 width=532) (actual time=0.047..0.053 rows=3 loops=1) Merge Cond: ( = ) -> Index Scan using idx_t1_id on t1 (cost=0.13..12.18 rows=3 width=524) (actual time=0.014..0.015 rows=3 loops=1) -> Index Scan using idx_t2_id on t2 (cost=0.13..12.18 rows=3 width=8) (actual time=0.026..0.028 rows=3 loops=1)
Combine two conditions to indexscan+seqscan
/*+ seqscan(t2) indexscan(t1 idx_t1_id) */explain analyze SELECT * FROM t1 JOIN t2 ON ( = ); QUERY PLAN ----------------------------------------------------------------------------------------------------------------------- Nested Loop (cost=0.13..13.35 rows=3 width=532) (actual time=0.025..0.032 rows=3 loops=1) Join Filter: ( = ) Rows Removed by Join Filter: 6 -> Index Scan using idx_t1_id on t1 (cost=0.13..12.18 rows=3 width=524) (actual time=0.016..0.018 rows=3 loops=1) -> Materialize (cost=0.00..1.04 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=3) -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.004..0.005 rows=3 loops=1)
4.4 Forced to specify the join method
/*+ NestLoop(t1 t2) MergeJoin(t1 t2 t3) Leading(t1 t2 t3) */ /*+ NestLoop(t1 t2 t3) MergeJoin(t2 t3) Leading(t1 (t2 t3)) */ explain analyze select * from t1 left join t2 on = left join t3 on =; QUERY PLAN -------------------------------------------------------------------------------------------------------------- Hash Left Join (cost=2.14..3.25 rows=3 width=540) (actual time=0.053..0.056 rows=3 loops=1) Hash Cond: ( = ) -> Hash Left Join (cost=1.07..2.14 rows=3 width=532) (actual time=0.036..0.038 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t1 (cost=0.00..1.03 rows=3 width=524) (actual time=0.007..0.007 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.009..0.009 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.006..0.006 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t3 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1)
Forced loop nested connection
/*+ NestLoop(t1 t2) MergeJoin(t1 t2 t3) Leading(t1 t2 t3) */ explain analyze select * from t1 left join t2 on = left join t3 on =; QUERY PLAN -------------------------------------------------------------------------------------------------------------------- Merge Left Join (cost=3.28..3.34 rows=3 width=540) (actual time=0.093..0.096 rows=3 loops=1) Merge Cond: ( = ) -> Sort (cost=2.23..2.23 rows=3 width=532) (actual time=0.077..0.078 rows=3 loops=1) Sort Key: Sort Method: quicksort Memory: 25kB -> Nested Loop Left Join (cost=0.00..2.20 rows=3 width=532) (actual time=0.015..0.020 rows=3 loops=1) Join Filter: ( = ) Rows Removed by Join Filter: 6 -> Seq Scan on t1 (cost=0.00..1.03 rows=3 width=524) (actual time=0.005..0.005 rows=3 loops=1) -> Materialize (cost=0.00..1.04 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=3) -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1) -> Sort (cost=1.05..1.06 rows=3 width=8) (actual time=0.012..0.013 rows=3 loops=1) Sort Key: Sort Method: quicksort Memory: 25kB -> Seq Scan on t3 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1)
Control the connection order
/*+ NestLoop(t1 t2 t3) MergeJoin(t2 t3) Leading(t1 (t2 t3)) */ explain analyze select * from t1 left join t2 on = left join t3 on =; QUERY PLAN -------------------------------------------------------------------------------------------------------------- Nested Loop Left Join (cost=1.07..3.31 rows=3 width=540) (actual time=0.036..0.041 rows=3 loops=1) Join Filter: ( = ) Rows Removed by Join Filter: 6 -> Hash Left Join (cost=1.07..2.14 rows=3 width=532) (actual time=0.030..0.032 rows=3 loops=1) Hash Cond: ( = ) -> Seq Scan on t1 (cost=0.00..1.03 rows=3 width=524) (actual time=0.008..0.009 rows=3 loops=1) -> Hash (cost=1.03..1.03 rows=3 width=8) (actual time=0.007..0.007 rows=3 loops=1) Buckets: 1024 Batches: 1 Memory Usage: 9kB -> Seq Scan on t2 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.004 rows=3 loops=1) -> Materialize (cost=0.00..1.04 rows=3 width=8) (actual time=0.001..0.002 rows=3 loops=3) -> Seq Scan on t3 (cost=0.00..1.03 rows=3 width=8) (actual time=0.002..0.003 rows=3 loops=1)
4.5 Control the cost of a single SQL
/*+ set(seq_page_cost 20.0) seqscan(t1) */ /*+ set(seq_page_cost 20.0) seqscan(t1) */explain analyze select * from t1 where id > 1; QUERY PLAN ----------------------------------------------------------------------------------------------- Seq Scan on t1 (cost=0.00..20.04 rows=1 width=524) (actual time=0.011..0.013 rows=2 loops=1) Filter: (id > 1) Rows Removed by Filter: 1
set seq_page_cost 200, note that the cost below has become 200.04
/*+ set(seq_page_cost 200.0) seqscan(t1) */explain analyze select * from t1 where id > 1; QUERY PLAN ------------------------------------------------------------------------------------------------ Seq Scan on t1 (cost=0.00..200.04 rows=1 width=524) (actual time=0.010..0.011 rows=2 loops=1) Filter: (id > 1) Rows Removed by Filter: 1
The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.