使用pg_hint_plan固定Postgresql执行计划

news/2024/7/9 22:53:53 标签: pg_hint_plan, schema, postgresql, 数据库, 换行

pg_hint_plan版本1.5:https://github.com/ossc-db/pg_hint_plan/blob/PG15/docs/hint_details.md
postgresql版本16

前言

pg_hint_plan的使用教程很多,本篇主要通过实例介绍一些使用时经常遇到的问题,例如:

  1. 表有schema怎么办?
  2. sql有换行匹配不上怎么办?
  3. sql模版太长拼不对怎么办?

2 安装

wget https://github.com/ossc-db/pg_hint_plan/archive/refs/tags/REL15_1_5_0.tar.gz

下载后解压到任意目录

tar xzvf REL15_1_5_0.tar.gz

cd pg_hint_plan-REL15_1_5_0/

## 事先配置环境变量,确认pg_config可以执行
pg_config

make
make install
  • 安装后最好修改配置参数shared_preload_libraries = 'pg_hint_plan'然后重启
  • 使用create extension pg_hint_plan;创建插件,以后就可以一直使用了。

可以查询到插件配置表示安装成功:

select name, setting from pg_settings where name ~ 'pg_hint_plan';
              name              | setting 
--------------------------------+---------
 pg_hint_plan.debug_print       | off
 pg_hint_plan.enable_hint       | on
 pg_hint_plan.enable_hint_table | off
 pg_hint_plan.hints_anywhere    | off
 pg_hint_plan.message_level     | log
 pg_hint_plan.parse_messages    | info

创建测试表

drop table student;
create table student(sno int primary key, sname varchar(10), ssex int);
insert into student select t.a, substring(md5(random()::text), 1, 5), t.a % 2 from generate_series(1, 100000) t(a);
create index idx1 on student(sname);
create index idx2 on student(sname, ssex);
vacuum analyze student;

create schema sch1;
drop table sch1.student;
create table sch1.student(sno int primary key, sname varchar(10), ssex int);
insert into sch1.student select t.a, substring(md5(random()::text), 1, 5), t.a % 2 from generate_series(1, 100000) t(a);
create index idx10 on sch1.student(sname);
create index idx20 on sch1.student(sname, ssex);
vacuum analyze sch1.student;

3 注释hint(可以改SQL的场景)

  • 必选参数:pg_hint_plan.enable_hint = on
  • 可选参数:打印调试信息,是否走hint了?
    • set pg_hint_plan.debug_print = ‘detailed’;
    • set client_min_messages to log;

schema_65">场景一:【无schema】【控制索引】

explain select * from student where sname = 'be12b';
                             QUERY PLAN                              
---------------------------------------------------------------------
 Index Scan using idx1 on student  (cost=0.29..8.31 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text



explain select /*+ IndexScan(student idx2) */ * from student where sname = 'be12b';
                             QUERY PLAN                              
---------------------------------------------------------------------
 Index Scan using idx2 on student  (cost=0.42..8.44 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text)

schema_82">场景二:【有schema】【控制索引】

注意:插件无法识别schema,只做表名的字符串匹配,所以有schema的SQL请直接忽略schma即可:

  • schema正确用法:/*+ IndexScan(student idx20) */
  • schema错误用法:/*+ IndexScan(sch1.student idx20) */
explain select * from sch1.student where sname = 'be12b';
                              QUERY PLAN                              
----------------------------------------------------------------------
 Index Scan using idx10 on student  (cost=0.29..8.31 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text)



explain select /*+ IndexScan(student idx20) */ * from sch1.student where sname = 'be12b';
                              QUERY PLAN                              
----------------------------------------------------------------------
 Index Scan using idx20 on student  (cost=0.42..8.44 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text)

4 hint种类

GroupFormatDescription
Scan methodSeqScan(table)Forces sequential scan on the table
TidScan(table)Forces TID scan on the table.
IndexScan(table[ index...])Forces index scan on the table. Restricts to specified indexes if any.
IndexOnlyScan(table[ index...])Forces index only scan on the table. Rstricts to specfied indexes if any. Index scan may be used if index only scan is not available. Available for PostgreSQL 9.2 and later.
BitmapScan(table[ index...])Forces bitmap scan on the table. Restoricts to specfied indexes if any.
IndexScanRegexp(table[ POSIX Regexp...]) IndexOnlyScanRegexp(table[ POSIX Regexp...]) BitmapScanRegexp(table[ POSIX Regexp...])Forces index scan or index only scan (For PostgreSQL 9.2 and later) or bitmap scan on the table. Restricts to indexes that matches the specified POSIX regular expression pattern
NoSeqScan(table)Forces not to do sequential scan on the table.
NoTidScan(table)Forces not to do TID scan on the table.
NoIndexScan(table)Forces not to do index scan and index only scan (For PostgreSQL 9.2 and later) on the table.
NoIndexOnlyScan(table)Forces not to do index only scan on the table. Available for PostgreSQL 9.2 and later.
NoBitmapScan(table)Forces not to do bitmap scan on the table.
Join methodNestLoop(table table[ table...])Forces nested loop for the joins consist of the specifiled tables.
HashJoin(table table[ table...])Forces hash join for the joins consist of the specifiled tables.
MergeJoin(table table[ table...])Forces merge join for the joins consist of the specifiled tables.
NoNestLoop(table table[ table...])Forces not to do nested loop for the joins consist of the specifiled tables.
NoHashJoin(table table[ table...])Forces not to do hash join for the joins consist of the specifiled tables.
NoMergeJoin(table table[ table...])Forces not to do merge join for the joins consist of the specifiled tables.
Join orderLeading(table table[ table...])Forces join order as specified.
Leading(<join pair>)Forces join order and directions as specified. A join pair is a pair of tables and/or other join pairs enclosed by parentheses, which can make a nested structure.
Behavior control on JoinMemoize(table table[ table...])Allow the topmost join of a join among the specified tables to memoize the inner result. (Note that this doesn’t enforce.)
NoMemoize(table table[ table...])Inhibit the topmost join of a join among the specified tables from memoizing the inner result.
Row number correctionRows(table table[ table...] correction)Corrects row number of a result of the joins consist of the specfied tables. The available correction methods are absolute (#), addition (+), subtract (-) and multiplication (*). should be a string that strtod() can read.
Parallel query configuration`Parallel(table <# of workers> [softhard])`
GUCSet(GUC-param value)Set the GUC parameter to the value while planner is running.

5 使用hint table(不能改SQL的场景)

必选参数:set pg_hint_plan.enable_hint_table to on;

如果不允许改SQL,pg_hint_plan插件也提供了另一种字符串匹配的方式来固定执行计划:将SQL模版和hint插入pg_hint_plan提供的表中,如果执行SQL与任意模版匹配,则执行相应的hint。

上述SQL模版拼写是不太容易处理的问题,因为插件要求SQL模版与执行的SQL需要严格匹配(空格、换行都要完全相同)。

下面用一个实例介绍如何快速构造一个可用的SQL模版。

实例

例如生产SQL(存在换行、空格)使用索引idx10,需要调整他的索引为idx20。

explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = 'be12b';

                              QUERY PLAN                              
----------------------------------------------------------------------
 Index Scan using idx10 on student  (cost=0.29..8.31 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text)

现在希望这条SQL走idx10索引,但是原SQL中有一些空格和换行

select name, setting from pg_settings where name ~ 'pg_hint_plan';
              name              | setting 
--------------------------------+---------
 pg_hint_plan.debug_print       | off
 pg_hint_plan.enable_hint       | on
 pg_hint_plan.enable_hint_table | off
 pg_hint_plan.hints_anywhere    | off
 pg_hint_plan.message_level     | log
 pg_hint_plan.parse_messages    | info

首先打开参数:

set pg_hint_plan.debug_print = 'detailed';
set pg_hint_plan.enable_hint_table = on;
set client_min_messages = log;

执行一次原始SQL

explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = 'be12b';

这里会看到三条日志

LOG:  pg_hint_plan[qno=0x7]: no match found in table:  application name = "psql", normalized_query="explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = ?;"

LOG:  hints in comment="(none)", query="explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = 'be12b';", debug_query_string="explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = 'be12b';"

LOG:  pg_hint_plan[qno=0x6]: planner: no valid hint

这里注意第一条日志中的normalized_query字段,内容就是已经模版化的SQL:

normalized_query="explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = ?;"

下面将内容原封不动的插入pg_hint_plan表中,并指定hint内容

技巧:使用 $$SQL文本$$ 代替 'SQL文本' 可以避免SQL内部存在标点符号需要转义的问题。PG中$$中的文本是不会转义的。

insert into hint_plan.hints (norm_query_string,application_name,hints) 
values(
$$explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = ?;$$,
'psql',
'IndexScan(student idx20)');   

这里在执行一次原始SQL,发现执行计划变化表示成功。

explain /* 123     */
select
 sno      ,
   sname  , 
      ssex
from sch1.student where sname = 'be12b';
                              QUERY PLAN                              
----------------------------------------------------------------------
 Index Scan using idx20 on student  (cost=0.42..8.44 rows=1 width=14)
   Index Cond: ((sname)::text = 'be12b'::text)

http://www.niftyadmin.cn/n/376046.html

相关文章

windows环境, nginx https配置

在 Windows 环境下配置 Nginx 的 HTTPS&#xff0c;需要以下步骤&#xff1a; 1. 安装 OpenSSL 首先需要安装 OpenSSL&#xff0c;可以从官网下载 Windows 版本的 OpenSSL&#xff0c;然后解压到某个目录下&#xff0c;比如 C:\OpenSSL-Win64。 2. 生成 SSL 证书和私钥 使用…

APP测试面试题快问快答(二)

1.请问App测试的主要内容包含&#xff1f; 功能测试&#xff1a; 业务逻辑正确性测试&#xff1a;依据产品文档->测试用例编写。 界面的测试 界面测试&#xff1a;依据产品UI设计文档&#xff08;高保真图&#xff0c;原型图&#xff09;。 升级&#xff0c;安装&#…

解锁Qt QListWidget的全部潜力——用最佳实践和技巧赢得用户的喜爱和赞誉!

文章目录 前言一、属性和方法添加列表项获取当前选中的列表项删除列表项列表显示模式交替背景色 二、信号与槽选中的行数变化item被点击 三、解决icon图标模式下图标不对称的问题1、设置属性2、面向结果的手动换行 总结 前言 在现代的GUI应用程序中&#xff0c;列表框是必不可…

uCOSii消息邮箱管理

uCOSii消息邮箱管理 (MESSAGE MAILBOX MANAGEMENT) 消息邮箱主要用于中断和任务之间进行邮件传递&#xff0c;或者是在任务与任务之间进行邮件交换。 1、消息邮箱管理重点需要了解下面几个函数 消息邮箱指针OSMboxCreate(消息邮箱数据块指针) 建立并初始化一个消息邮箱,在初…

matlab读二进制文件

matlab读二进制文件 1. 打开文件 fid fopen(文件名, 读取方式)fid 句柄值 小于0&#xff0c;表示打开失败&#xff0c;大于0表示打开成功 文件名 字符串&#xff0c;使用单引号 读写方式 r 只读方式打开文件&#xff0c;默认方式&#xff0c;该文件已存在 r 读写方式打开文…

MQ学习笔记--(SpringAMQP)

SpringAMQP–基本介绍 什么是SpringAMQP SpringAmqp的官方地址&#xff1a;https://spring.io/projects/spring-amqp AMQP&#xff1a;是用于在应用程序或之间传递业务消息的开放标准。该协议与语言和平台无关&#xff0c;更符合微服务中独立性的要求 Spring AMQP&#xff…

javaWeb ssh小区物业管理系统myeclipse开发mysql数据库MVC模式java编程计算机网页设计

一、源码特点 java ssh小区物业管理系统是一套完善的web设计系统&#xff08;系统采用ssh框架进行设计开发&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0…

Revit问题:创建牛腿柱和快速生成圈梁

一、Revit中如何用体量创建牛腿柱 牛腿&#xff1a;悬臂体系的挂梁与悬臂间必然出现搁置构造&#xff0c;通常就将悬臂端和挂梁端的局部构造&#xff0c;又称梁托。牛腿的作用是衔接悬臂梁与挂梁&#xff0c; 并传递来自挂梁的荷载。牛腿柱可以用于桥梁、厂房的搭建&#xff0c…