Postgresql学习04-pg_hint_plan安装及使用、Sql优化小知识
一、环境
名称 | 版本 |
---|---|
操作系统 | Centos7.9 |
Postgresql | 14.4 |
pg_hint_plan | 1.4 |
二、下载链接
pg_hint_plan下载地址
三、pg_hint_plan用途
当判断数据库优化器生成的执行计划不是最优的时候,可以在不修改Sql的情况下(例如:等价改写、非等价改写)通过添加Hint,来影响执行计划的生成。
四、安装pg_hint_plan
Postgresql源码安装可以参考之前的博客分享:
《Postgresql学习01-PG14.2-Linux平台源码编译安装和配置开机自启》
[root@node0 pkg]# unzip pg_hint_plan-master.zip[root@node0 pkg]# source /home/postgres/.bashrc[root@node0 pkg]# cd pg_hint_plan-master/[root@node0 pg_hint_plan-master]# ll
总用量 280
-rw-r--r-- 1 root root 1593 1月 19 14:12 COPYRIGHT
-rw-r--r-- 1 root root 1295 1月 19 14:12 COPYRIGHT.postgresql
-rw-r--r-- 1 root root 55461 1月 19 14:12 core.c
drwxr-xr-x 2 root root 22 1月 19 14:12 data
drwxr-xr-x 2 root root 123 1月 19 14:12 doc
drwxr-xr-x 2 root root 297 1月 19 14:12 expected
drwxr-xr-x 2 root root 27 1月 19 14:12 input
-rw-r--r-- 1 root root 2033 1月 19 14:12 Makefile
-rw-r--r-- 1 root root 12313 1月 19 14:12 make_join_rel.c
-rw-r--r-- 1 root root 521 1月 19 14:12 normalize_query.h
drwxr-xr-x 2 root root 27 1月 19 14:12 output
-rw-r--r-- 1 root root 683 1月 19 14:12 pg_hint_plan--1.4.sql
-rw-r--r-- 1 root root 124735 1月 19 14:12 pg_hint_plan.c
-rw-r--r-- 1 root root 102 1月 19 14:12 pg_hint_plan.control
-rw-r--r-- 1 root root 8342 1月 19 14:12 pg_stat_statements.c
-rw-r--r-- 1 root root 35842 1月 19 14:12 README.md
drwxr-xr-x 2 root root 33 1月 19 14:12 SPECS
drwxr-xr-x 2 root root 314 1月 19 14:12 sql
-rwxr-xr-x 1 root root 9109 1月 19 14:12 update_copied_funcs.pl[root@node0 pg_hint_plan-master]# make
gcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wf
ormat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -fPIC -I. -I./ -I/opt/pg14-4/include/postgresql/server -I/opt/pg14-4/include/postgresql/internal -D_GNU_SOURCE -c -o pg_hint_plan.o pg_hint_plan.cgcc -std=gnu99 -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wf
ormat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -g -fPIC pg_hint_plan.o -L/opt/pg14-4/lib -Wl,--as-needed -Wl,-rpath,'/opt/pg14-4/lib',--enable-new-dtags -shared -o pg_hint_plan.so[root@node0 pg_hint_plan-master]# make install
/usr/bin/mkdir -p '/opt/pg14-4/share/postgresql/extension'
/usr/bin/mkdir -p '/opt/pg14-4/share/postgresql/extension'
/usr/bin/mkdir -p '/opt/pg14-4/lib/postgresql'
/usr/bin/install -c -m 644 .//pg_hint_plan.control '/opt/pg14-4/share/postgresql/extension/'
/usr/bin/install -c -m 644 .//pg_hint_plan--*.sql '/opt/pg14-4/share/postgresql/extension/'
/usr/bin/install -c -m 755 pg_hint_plan.so '/opt/pg14-4/lib/postgresql/'[root@node0 pg_hint_plan-master]# systemctl restart pg14-4.service[root@node0 pg14-4]# su - postgres
上一次登录:一 7月 18 15:19:03 CST 2022[postgres@node0 ~]$ psql
psql (14.4)
Type "help" for help.postgres=# create extension pg_hint_plan;
CREATE EXTENSIONpostgres=# load 'pg_hint_plan';
LOADpostgres=# select * from pg_available_extensions where name = 'pg_hint_plan';name | default_version | installed_version | comment
--------------+-----------------+-------------------+---------pg_hint_plan | 1.4 | 1.4 |
(1 row)postgres=# \d hint_plan.hintsTable "hint_plan.hints"Column | Type | Collation | Nullable | Default
-------------------+---------+-----------+----------+---------------------------------------------id | integer | | not null | nextval('hint_plan.hints_id_seq'::regclass)norm_query_string | text | | not null | application_name | text | | not null | hints | text | | not null |
Indexes:"hints_pkey" PRIMARY KEY, btree (id)"hints_norm_and_app" UNIQUE, btree (norm_query_string, application_name)
1、注意点
(1)必须执行create extension pg_hint_plan;,不然找不到hint_plan.hints表。
(2)上面的load ‘pg_hint_plan’;是临时生效,如果重启数据库,就不生效了,建议用下面这个方法可以永久生效,修改postgresql.conf中的shared_preload_libraries参数,修改完记得重启数据库。
shared_preload_libraries = 'pg_hint_plan'
五、支持的Hint介绍
1、扫描方法
Hint | 描述 |
---|---|
SeqScan(table) | 强制对表进行顺序扫描 |
TidScan(table) | 强制对表进行TID扫描。 |
IndexScan(table[ index…]) | 强制对表进行索引扫描。限制指定索引(如果有)。 |
IndexOnlyScan(table[ index…]) | 强制仅对表进行索引扫描。如果有,则限制为指定索引。如果索引扫描不可用,可以使用索引扫描。可用于PostgreSQL 9.2及更高版本。 |
BitmapScan(table[ index…]) | 强制对表进行位图扫描。如果有,恢复到指定的索引。 |
IndexScanRegexp(table[ POSIX Regexp…]) IndexOnlyScanRegexp(table[ POSIX Regexp…]) BitmapScanRegexp(table[ POSIX Regexp…]) | 强制索引扫描或仅索引扫描(适用于PostgreSQL 9.2及以后版本)或位图扫描表。限制为匹配指定POSIX正则表达式模式的索引 |
NoSeqScan(table) | 强制不对表进行顺序扫描。 |
NoTidScan(table) | 强制不对表进行TID扫描。 |
NoIndexScan(table) | 强制对表不做索引扫描,只做索引扫描(适用于PostgreSQL 9.2及以后版本)。 |
NoIndexOnlyScan(table) | 强制不在表上只做索引扫描。可用于PostgreSQL 9.2及更高版本。 |
NoBitmapScan(table) | 强制不对表进行位图扫描。 |
2、连接方法
Hint | 描述 |
---|---|
NestLoop(table table[ table…]) | 强制联接的嵌套循环由指定的表组成。 |
HashJoin(table table[ table…]) | 强制由指定表组成的连接的散列连接。 |
MergeJoin(table table[ table…])) | 强制合并联接,因为联接由指定的表组成。 |
NoNestLoop(table table[ table…])) | 对于由指定表组成的连接,强制不执行嵌套循环。 |
NoHashJoin(table table[ table…])) | 强制不执行散列连接,因为连接由指定的表组成。 |
NoMergeJoin(table table[ table…])) | 强制不进行合并连接,因为连接由指定的表组成。 |
3、连接顺序
Hint | 描述 |
---|---|
Leading(table table[ table…]) ) | 强制指定的连接顺序。 |
Leading(<join pair>) | 力按照指定的顺序和方向连接。连接对是一对用括号括起来的表和/或其他连接对,它们可以构成嵌套结构。 |
4、行号修正
Hint | 描述 |
---|---|
Rows(table table[ table…] correction)) ) | 纠正由指定表组成的连接的结果的行号。可用的校正方法有绝对(#)、加法(+)、减法(-)和乘法(*)。应该是strtod()可以读取的字符串。 |
5、并行查询的配置
Hint | 描述 |
---|---|
Parallel(table <# of workers> [soft|hard]) | 强制或禁止指定表的并行执行。<# of worker >是期望的并行工作者数量,其中0表示抑制并行执行。如果第三个参数是软参数(默认值),它只更改max_parallel_workers_per_gather,并将其他所有工作留给规划器。Hard意味着强制执行指定的工人数量。 |
6、GUC
Hint | 描述 |
---|---|
Set(GUC-param value) | 将规划器运行时的GUC参数设置为该值。 |
六、Sql执行计划操作符
操作符 | 描述 |
---|---|
Seq Scan | 顺序扫描也就是全表扫描 |
Index Scan | 索引扫描 |
Bitmap Index Scan | 位图索引扫描 |
Bitmap Heap Scan | 位图堆扫描 |
Subquery Scan | 子查询 |
Tid Scan | 行号扫描 |
Function Scan | 函数扫描 |
Nested Loop | 嵌套循环连接 |
Merge Join | 归并连接 |
Hash Join | 哈希连接 |
Sort | 排序运算 |
Unique | 唯一运算 |
Limit | 限制返回的行数 |
Aggregate | 聚合运算 |
Group | 分组运算 |
Append | 追加运算,union出现 |
Materialize | 子查询 |
SetOp | 交集INTERCECT、不包含EXCEPT出现 |
七、执行计划代价估算
1、准备测试环境
czg=# create table tenk1(id int,num int,name varchar(100),sex int);
CREATE TABLEczg=# insert into tenk1 select generate_series(1,20902),generate_series(1,20902),chr(generate_series(19968,40869)),random()::int;
INSERT 0 20902czg=# create table tenk2(id int,num int,name varchar(100),sex int);
CREATE TABLEczg=# insert into tenk2 select generate_series(1,20902),generate_series(1,20902),chr(generate_series(19968,40869)),random()::int;
INSERT 0 20902czg=# select * from tenk1 limit 10;id | num | name | sex
----+-----+------+-----1 | 1 | 一 | 12 | 2 | 丁 | 03 | 3 | 丂 | 04 | 4 | 七 | 15 | 5 | 丄 | 06 | 6 | 丅 | 17 | 7 | 丆 | 18 | 8 | 万 | 19 | 9 | 丈 | 010 | 10 | 三 | 0
(10 rows)
2、收集统计信息并查看
czg=# \x
Expanded display is on.czg=# ANALYZE VERBOSE TENK1;
INFO: analyzing "public.tenk1"
INFO: "tenk1": scanned 113 of 113 pages, containing 20902 live rows and 0 dead rows; 20902 rows in sample, 20902 estimated total rows
ANALYZEczg=# ANALYZE VERBOSE TENK2;
INFO: analyzing "public.tenk2"
INFO: "tenk2": scanned 113 of 113 pages, containing 20902 live rows and 0 dead rows; 20902 rows in sample, 20902 estimated total rows
ANALYZEczg=# select * from pg_stats where tablename = 'tenk1';
-[ RECORD 1 ]----------+-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
schemaname | public
tablename | tenk1
attname | name
inherited | f
null_frac | 0
avg_width | 4
n_distinct | -1
most_common_vals |
most_common_freqs |
histogram_bounds | {丆,炿,飊,蔜,鎊,夶,墂,桲,愺,蕆,嚫,叱,絀,鷀,髊,蜑,掋,苵,妬,莪,匥,蚡,縛,竿,舸,淈,敮,寒,佫,謼,镮,晦,积,瀱,笺,薑,嵥,聙,踙,屫
,瞰,郀,焜,壏,踜,蒞,聊,陵,髏,倫,麦,痗,緬,縸,詉,鎳,輫,匹,胓,脐,虔,锲,紌,悫,氄,繅,赏,冼,授,丝,膆,孡,洮,齠,駼,紈,踓,诬,稀,夏,鄕,卨,綇,袨,珚,眏,偞,义,
絪,巊,淤,籞,跃,醩,颭,蒖,址,譸,僎,耔,阼}
correlation | 0.016811712
most_common_elems |
most_common_elem_freqs |
elem_count_histogram |
-[ RECORD 2 ]----------+-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
schemaname | public
tablename | tenk1
attname | sex
inherited | f
null_frac | 0
avg_width | 4
n_distinct | 2
most_common_vals | {0,1}
most_common_freqs | {0.5002392,0.49976078}
histogram_bounds |
correlation | 0.493415
most_common_elems |
most_common_elem_freqs |
elem_count_histogram |
-[ RECORD 3 ]----------+-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
schemaname | public
tablename | tenk1
attname | id
inherited | f
null_frac | 0
avg_width | 4
n_distinct | -1
most_common_vals |
most_common_freqs |
histogram_bounds | {1,210,419,628,837,1046,1255,1464,1673,1882,2091,2300,2509,2718,2927,3136,3345,3554,3763,3972,4181,4390,4599,4808,5017,5
226,5435,5644,5853,6062,6271,6480,6689,6898,7107,7316,7525,7734,7943,8152,8361,8570,8779,8988,9197,9406,9615,9824,10033,10242,10451,10660,10869,1
1078,11287,11496,11705,11914,12123,12332,12541,12750,12959,13168,13377,13586,13795,14004,14213,14422,14631,14840,15049,15258,15467,15676,15885,16
094,16303,16512,16721,16930,17139,17348,17557,17766,17975,18184,18393,18602,18811,19020,19229,19438,19647,19856,20065,20274,20483,20692,20902}
correlation | 1
most_common_elems |
most_common_elem_freqs |
elem_count_histogram |
-[ RECORD 4 ]----------+-------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------
schemaname | public
tablename | tenk1
attname | num
inherited | f
null_frac | 0
avg_width | 4
n_distinct | -1
most_common_vals |
most_common_freqs |
histogram_bounds | {1,210,419,628,837,1046,1255,1464,1673,1882,2091,2300,2509,2718,2927,3136,3345,3554,3763,3972,4181,4390,4599,4808,5017,5
226,5435,5644,5853,6062,6271,6480,6689,6898,7107,7316,7525,7734,7943,8152,8361,8570,8779,8988,9197,9406,9615,9824,10033,10242,10451,10660,10869,1
1078,11287,11496,11705,11914,12123,12332,12541,12750,12959,13168,13377,13586,13795,14004,14213,14422,14631,14840,15049,15258,15467,15676,15885,16
094,16303,16512,16721,16930,17139,17348,17557,17766,17975,18184,18393,18602,18811,19020,19229,19438,19647,19856,20065,20274,20483,20692,20902}
correlation | 1
most_common_elems |
most_common_elem_freqs |
elem_count_histogram | czg=# SELECT relpages, reltuples FROM pg_class WHERE relname = 'tenk1';
-[ RECORD 1 ]----
relpages | 113
reltuples | 20902
3、查看系统参数
czg=# \x
Expanded display is off.
czg=# select name,setting from pg_settings where name like '%_cost';name | setting
-------------------------+---------cpu_index_tuple_cost | 0.005cpu_operator_cost | 0.0025cpu_tuple_cost | 0.01jit_above_cost | 100000jit_inline_above_cost | 500000jit_optimize_above_cost | 500000parallel_setup_cost | 1000parallel_tuple_cost | 0.1random_page_cost | 4seq_page_cost | 1
(10 rows)
4、Sql执行计划
czg=# EXPLAIN SELECT * FROM tenk1;QUERY PLAN
------------------------------------------------------------Seq Scan on tenk1 (cost=0.00..322.02 rows=20902 width=16)
(1 row)
5、代价估算公式
cost = (disk pages read * seq_page_cost) + (rows scanned * cpu_tuple_cost)= 113 * 1.0 + 20902 * 0.01= 113 + 209.02= 322.02
估算结果和和执行计划中的一样。
八、如何看执行计划
1、两表连接查询
czg=# set enable_hashjoin = off;
SETczg=# insert into tenk1 values(1,1,'一',1);
INSERT 0 1czg=# explain (analyze,verbose,buffers) select * from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = '一';QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------Nested Loop (cost=0.00..957.57 rows=1 width=32) (actual time=0.027..17.943 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sex, t2.id, t2.num, t2.name, t2.sexJoin Filter: (t1.id = t2.id)Rows Removed by Join Filter: 41802Buffers: shared hit=339-> Seq Scan on public.tenk1 t1 (cost=0.00..374.28 rows=1 width=16) (actual time=0.016..4.690 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sexFilter: ((t1.name)::text = '一'::text)Rows Removed by Filter: 20901Buffers: shared hit=113-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=16) (actual time=0.005..2.774 rows=20902 loops=2)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=226Planning Time: 0.157 msExecution Time: 17.974 ms
(15 rows)
操作符执行顺序为:
(1)先全表扫描tenk1表,根据name = '一’进行过滤,tenk1作为驱动表,驱动表滤出2条数据,过滤掉了20901条数据。
-> Seq Scan on public.tenk1 t1 (cost=0.00..374.28 rows=1 width=16) (actual time=0.016..4.690 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sexFilter: ((t1.name)::text = '一'::text)Rows Removed by Filter: 20901Buffers: shared hit=113
(2)再全表扫描tenk2表,tenk2作为被驱动表,loops=2,表示执行两次,总结为:驱动表滤出多少条数据,被驱动表执行多少次。
-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=16) (actual time=0.005..2.774 rows=20902 loops=2)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=226
(3)最后将两个表根据等值条件t1.id = t2.id进行嵌套循环连接。
Nested Loop (cost=0.00..957.57 rows=1 width=32) (actual time=0.027..17.943 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sex, t2.id, t2.num, t2.name, t2.sexJoin Filter: (t1.id = t2.id)Rows Removed by Join Filter: 41802Buffers: shared hit=339
2、多表连接查询
(1)准备测试环境
czg=# CREATE TABLE FLATING_T1(A1 INT,A2 INT);
CREATE TABLEczg=# CREATE TABLE FLATING_T2(B1 INT,B2 INT);
CREATE TABLEczg=# CREATE TABLE FLATING_T3(C1 INT,C2 INT);
CREATE TABLEczg=# INSERT INTO FLATING_T1 SELECT generate_series(1,10),generate_series(1,10);
INSERT 0 10czg=# INSERT INTO FLATING_T2 SELECT generate_series(1,100000),generate_series(1,100000);
INSERT 0 100000czg=# INSERT INTO FLATING_T3 SELECT generate_series(1,100000),generate_series(1,100000);
INSERT 0 100000czg=# ANALYZE VERBOSE FLATING_T1;
INFO: analyzing "public.flating_t1"
INFO: "flating_t1": scanned 1 of 1 pages, containing 10 live rows and 0 dead rows; 10 rows in sample, 10 estimated total rows
ANALYZEczg=# ANALYZE VERBOSE FLATING_T2;
INFO: analyzing "public.flating_t2"
INFO: "flating_t2": scanned 443 of 443 pages, containing 100000 live rows and 0 dead rows; 30000 rows in sample, 100000 estimated total rows
ANALYZEczg=# ANALYZE VERBOSE FLATING_T3;
INFO: analyzing "public.flating_t3"
INFO: "flating_t3": scanned 443 of 443 pages, containing 100000 live rows and 0 dead rows; 30000 rows in sample, 100000 estimated total rows
ANALYZE
(2)小实验
czg=# EXPLAIN SELECT COUNT(*) FROM FLATING_T1 LEFT JOIN FLATING_T2 CROSS JOIN FLATING_T3 ON A1=B1;QUERY PLAN
------------------------------------------------------------------------------------------Aggregate (cost=162515637.22..162515637.23 rows=1 width=8)-> Hash Right Join (cost=1.23..162513137.22 rows=1000000 width=0)Hash Cond: (flating_t2.b1 = flating_t1.a1)-> Nested Loop (cost=0.00..125003136.00 rows=10000000000 width=4)-> Seq Scan on flating_t2 (cost=0.00..1443.00 rows=100000 width=4)-> Materialize (cost=0.00..1943.00 rows=100000 width=0)-> Seq Scan on flating_t3 (cost=0.00..1443.00 rows=100000 width=0)-> Hash (cost=1.10..1.10 rows=10 width=4)-> Seq Scan on flating_t1 (cost=0.00..1.10 rows=10 width=4)
(9 rows)
操作符执行顺序为:
flating_t3 》Materialize 》flating_t2 》Nested Loop 》 flating_t1 》Hash 》Hash Right Join 》 Aggregate
flating_t3有10万条数,flating_t2有10万条数,进行交叉连接(也就是笛卡尔积连接)返回的结果是100亿,耗时在这里了,之后再和 flating_t1的10条数据进行左外连接。
(3)如何优化呢
等价改写的方式就可以出来啦。
我们先让 flating_t1和flating_t2进行左外连接得出10条数据,再和flating_t3进行交叉连接,得出最终的100万条数据。
czg=# explain
czg-# with a as (select * from FLATING_T1 LEFT JOIN FLATING_T2 ON A1=B1)
czg-# SELECT COUNT(*) FROM a,FLATING_T3;QUERY PLAN
------------------------------------------------------------------------------------------Aggregate (cost=18262.35..18262.36 rows=1 width=8)-> Nested Loop (cost=1.23..15762.35 rows=1000000 width=0)-> Seq Scan on flating_t3 (cost=0.00..1443.00 rows=100000 width=0)-> Materialize (cost=1.23..1819.37 rows=10 width=0)-> Hash Right Join (cost=1.23..1819.32 rows=10 width=0)Hash Cond: (flating_t2.b1 = flating_t1.a1)-> Seq Scan on flating_t2 (cost=0.00..1443.00 rows=100000 width=4)-> Hash (cost=1.10..1.10 rows=10 width=4)-> Seq Scan on flating_t1 (cost=0.00..1.10 rows=10 width=4)
(9 rows)czg=# with a as (select * from FLATING_T1 LEFT JOIN FLATING_T2 ON A1=B1)
SELECT COUNT(*) FROM a,FLATING_T3;count
---------1000000
(1 row)
九、通过Hint改变执行计划
1、原执行计划
czg=# set enable_hashjoin = on;
SETczg=# explain (analyze,verbose,buffers) select * from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = '一';QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------Hash Join (cost=374.29..774.70 rows=1 width=32) (actual time=4.817..11.239 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sex, t2.id, t2.num, t2.name, t2.sexHash Cond: (t2.id = t1.id)Buffers: shared hit=226-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=16) (actual time=0.012..2.577 rows=20902 loops=1)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=113-> Hash (cost=374.28..374.28 rows=1 width=16) (actual time=4.794..4.795 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sexBuckets: 1024 Batches: 1 Memory Usage: 9kBBuffers: shared hit=113-> Seq Scan on public.tenk1 t1 (cost=0.00..374.28 rows=1 width=16) (actual time=0.010..4.787 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sexFilter: ((t1.name)::text = '一'::text)Rows Removed by Filter: 20901Buffers: shared hit=113Planning Time: 0.199 msExecution Time: 11.274 ms
(18 rows)
2、Hint提示后的执行计划
czg=# explain (analyze,verbose,buffers) select /*+NestLoop(t2 t1)*/* from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = '一';QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------Nested Loop (cost=0.00..957.57 rows=1 width=32) (actual time=0.025..15.314 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sex, t2.id, t2.num, t2.name, t2.sexJoin Filter: (t1.id = t2.id)Rows Removed by Join Filter: 41802Buffers: shared hit=339-> Seq Scan on public.tenk1 t1 (cost=0.00..374.28 rows=1 width=16) (actual time=0.015..3.748 rows=2 loops=1)Output: t1.id, t1.num, t1.name, t1.sexFilter: ((t1.name)::text = '一'::text)Rows Removed by Filter: 20901Buffers: shared hit=113-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=16) (actual time=0.005..2.469 rows=20902 loops=2)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=226Planning Time: 0.153 msExecution Time: 15.344 ms
(15 rows)
3、固定执行计划
由于生产环境中有些应用是不可以修改代码的,及时是加Hint也不可以,pg_hint_plan支持固定执行计划,下面我们来看一下:
(1)hint_plan.hints表介绍
czg=# \d hint_plan.hintsTable "hint_plan.hints"Column | Type | Collation | Nullable | Default
-------------------+---------+-----------+----------+---------------------------------------------id | integer | | not null | nextval('hint_plan.hints_id_seq'::regclass)norm_query_string | text | | not null | application_name | text | | not null | hints | text | | not null |
Indexes:"hints_pkey" PRIMARY KEY, btree (id)"hints_norm_and_app" UNIQUE, btree (norm_query_string, application_name)
列名 | 含义 |
---|---|
id | 唯一标识,自动增长的,我们不用维护。 |
norm_query_string | 需要加Hint的Sql,查询中的常量必须替换为?。 |
application_name | 应用的名字,为空字符串的话,表示任何的会话都可以。 |
hints | 需要加的Hint。 |
(2)插入数据
czg=# insert into hint_plan.hints(norm_query_string,application_name,hints)
czg-# values ('explain (analyze,verbose,buffers) select from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = ?;','','NestLoop(t2 t1)');INSERT 0 1czg=# select * from hint_plan.hints;id | norm_query_string | application_name | hints ----+-------------------------------------------------------------------------------------------------------+------------------+------------
-----14 | explain (analyze,verbose,buffers) select from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = ?; | | NestLoop(t2t1)
(1 row)
(3)开启参数pg_hint_plan.enable_hint_table
默认参数pg_hint_plan.enable_hint_table是关闭的
czg=# show pg_hint_plan.enable_hint_table;pg_hint_plan.enable_hint_table
--------------------------------off
(1 row)
当前会话生效:
czg=# set pg_hint_plan.enable_hint_table=on;
SET
永久生效,修改完此参数记得重启数据库:
czg=# alter system set pg_hint_plan.enable_hint_table=on;
ALTER SYSTEM
(4)pg_hint_plan参数介绍
参数名 | 描述 |
---|---|
pg_hint_plan.enable_hint | True 为启动 .pg_hint_plan |
pg_hint_plan.enable_hint_table | True 为可以在表上加Hint |
pg_hint_plan.parse_messages | 指定提示解析错误的日志级别。有效值为.error ,warning ,notice ,info ,log ,debug |
pg_hint_plan.debug_print | 控制调试打印和详细信息。有效的值是off ,on ,detailed ,verbose |
pg_hint_plan.message_level | 指定调试打印的消息级别。有效值为error ,warning ,notice ,info ,log ,debug |
默认为:
czg=# show pg_hint_plan.enable_hint;pg_hint_plan.enable_hint
--------------------------on
(1 row)czg=# show pg_hint_plan.enable_hint_table;pg_hint_plan.enable_hint_table
--------------------------------off
(1 row)czg=# show pg_hint_plan.parse_messages;pg_hint_plan.parse_messages
-----------------------------info
(1 row)czg=# show pg_hint_plan.debug_print;pg_hint_plan.debug_print
--------------------------off
(1 row)czg=# show pg_hint_plan.message_level ;pg_hint_plan.message_level
----------------------------log
(1 row)
(5)查看计划是否固定
执行计划固定成功
czg=# explain (analyze,verbose,buffers) select from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = '一';QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------Nested Loop (cost=4.33..1910.93 rows=5 width=0) (actual time=0.051..33.639 rows=5 loops=1)Join Filter: (t1.id = t2.id)Rows Removed by Join Filter: 104505Buffers: shared hit=118-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=4) (actual time=0.008..2.858 rows=20902 loops=1)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=113-> Materialize (cost=4.33..21.27 rows=5 width=4) (actual time=0.000..0.000 rows=5 loops=20902)Output: t1.idBuffers: shared hit=5-> Bitmap Heap Scan on public.tenk1 t1 (cost=4.33..21.25 rows=5 width=4) (actual time=0.038..0.045 rows=5 loops=1)Output: t1.idRecheck Cond: ((t1.name)::text = '一'::text)Heap Blocks: exact=3Buffers: shared hit=5-> Bitmap Index Scan on tenk1_index (cost=0.00..4.32 rows=5 width=0) (actual time=0.032..0.032 rows=5 loops=1)Index Cond: ((t1.name)::text = '一'::text)Buffers: shared hit=2Query Identifier: 6941249274061524011Planning Time: 0.159 msExecution Time: 33.671 ms
(21 rows)
(6)注意点
hint_plan.hints表中的Sql必须和实际执行的Sql一模一样,如果多一个空格,计划就变了,如下:
czg=# explain (analyze,verbose,buffers) select from tenk1 t1, tenk2 t2 where t1.id = t2.id and t1.name = '一';QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------Hash Join (cost=21.31..526.27 rows=5 width=0) (actual time=0.062..7.982 rows=5 loops=1)Hash Cond: (t2.id = t1.id)Buffers: shared hit=118-> Seq Scan on public.tenk2 t2 (cost=0.00..322.02 rows=20902 width=4) (actual time=0.008..3.052 rows=20902 loops=1)Output: t2.id, t2.num, t2.name, t2.sexBuffers: shared hit=113-> Hash (cost=21.25..21.25 rows=5 width=4) (actual time=0.046..0.048 rows=5 loops=1)Output: t1.idBuckets: 1024 Batches: 1 Memory Usage: 9kBBuffers: shared hit=5-> Bitmap Heap Scan on public.tenk1 t1 (cost=4.33..21.25 rows=5 width=4) (actual time=0.029..0.037 rows=5 loops=1)Output: t1.idRecheck Cond: ((t1.name)::text = '一'::text)Heap Blocks: exact=3Buffers: shared hit=5-> Bitmap Index Scan on tenk1_index (cost=0.00..4.32 rows=5 width=0) (actual time=0.022..0.022 rows=5 loops=1)Index Cond: ((t1.name)::text = '一'::text)Buffers: shared hit=2Query Identifier: 6941249274061524011Planning Time: 0.144 msExecution Time: 8.017 ms
(21 rows)
还有一点hint_plan.hints表如果只存select后面的语句,不存explain,那我们在Psql中执行explain select语句,也是不能固定计划的,实际生产中使用这个固定计划的功能,就不能通过explain来确定计划是否固定,需要实际执行一下,通过快慢来判断是否生效。
Postgresql学习04-pg_hint_plan安装及使用、Sql优化小知识相关推荐
- 学习笔记之-MySql高级之sql优化
一 Mysql简介 概述 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle公司. M/SQL是一种关联数据库管理系统,将数据保存在不同的表中,而不是将所有数据 ...
- VC学习资料收集(12):VC小知识总结
VC小知识总结! (1) 如何通过代码获得应用程序主窗口的 指针? 主窗口的 指针保存在CWinThread::m_pMainWnd中,调用AfxGetMainWnd实现. AfxGetMainWnd ...
- ROS-语音控制-会说话的机器人(1)-ubuntu16.04上安装运行snowboy
ROS-语音控制-会说话的机器人(1)-ubuntu16.04上安装运行snowboy 参考ROS小课堂教程,再ubuntu16.04上安装运行snowboy,并解决问题 ROS小课堂安装snowbo ...
- 中秋节,送上一次非常有趣的SQL优化实战经历
点击上方"搜云库技术团队",选择"设为星标" 回复"1024"或"面试题"获取4T学习资料 补充:看到好多朋友后台留言说 ...
- DB2分页SQL优化(宝,我优化了分页,每分钟都想你的夜)
前言: 最近,项目中的一个 DB2分页查询很慢 ,组长将此分页的优化分派给了我:然后一顿优化(乱操作)后,将DB2分页查询耗时降到了比较满意的情况,[ 开森 ]: 然后马上将结果报告了组长,组长查看我 ...
- 一次DB2分页语句的优化,带你拨开分页SQL优化的外衣
一次DB2分页语句的优化,带你拨开分页SQL优化的外衣 1 前言: 最近,项目中的一个 DB2分页查询很慢 ,组长将此分页的优化分派给了我:然后一顿优化(乱操作)后,将DB2分页查询耗时降到了比较满意 ...
- PostgreSQL学习总结(1)—— PostgreSQL 入门简介与安装
PostgreSQL 是一个免费的对象-关系数据库服务器(ORDBMS),在灵活的BSD许可证下发行.PostgreSQL 开发者把它念作 post-gress-Q-L.PostgreSQL 的 Sl ...
- Ubuntu Server 20.04 LTS 安装配置 PostgreSQL
1 & 环境准备 上面一篇文章我们讲解了在 Windows 环境上面安装 PostgreSQL 的简单介绍,准备环境基本一样. ubuntu server 20.04 镜像下载地址 => ...
- Caffe学习笔记2--Ubuntu 14.04 64bit 安装Caffe(GPU版本)
0.检查配置 1. VMWare上运行的Ubuntu,并不能支持真实的GPU(除了特定版本的VMWare和特定的GPU,要求条件严格,所以我在VMWare上搭建好了Caffe环境后,又重新在Windo ...
最新文章
- Redis集群管理方式
- MySQL 为什么表的数据删除一般,表文件大小不变?
- mysql event scheduler机制 与 动态表名创建
- 【爬坑】Vim 文档加密 解密
- Safari浏览器不支持let声明的解决方式
- 北美KubeCon新风,正把K8S魔力带向边缘计算
- MySQL子查询作为列_mysql 列子查询
- Enterprise Library启用签名后发生 PublicKeyToken错误,HRESULT:0x80131040解决
- screen,client,page三种确定鼠标坐标的区别和原生JS事件写法,区别于Jquery的$.on(x,y);和$.click()...
- Lesson 3.1 - Python Core Data Types
- 水晶报表2008部署
- 平板电脑刷机加供电系统改造
- 使用Javascript动态添加和删除元素
- Qtum量子链QIP-5提案:在智能合约交易输出脚本上增加签名证明,允许用户以代付方式调用合约
- 显示器经典故障以及处理办法
- 活体检测Face Anti-spoofing前世今生:作者(Fisher Yu )
- 视频教程-C++QT5跨平台界面编程原理和实战大全-C/C++
- 使用了 23 的 Java 真的收费了吗?
- 订单23系统服务器,死亡搁浅寻物系统服务器任务内容介绍-死亡搁浅寻物系统服务器任务流程详情_牛游戏网...
- HTML3/CSS基础
热门文章
- 惊呆了,竟然可以用这种方式秒建Redis集群?
- MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk.问题解决
- 【分布族谱】正态分布和卡方分布的关系
- 使用node搭建后台管理系统(1)
- ssh -o 常用选项
- 一个n维井字棋的游戏
- PostgreSql优势是什么?
- SQL Server 2008 正式版下载地址+安装指南+序列号
- 基于FPGA的UART异步串行通信发送模块设计与实现
- 学习大数据的第29天——Linux指令的学习以及一些面试题