【数据库使用】 Plan management绑定计划用例

举报
超人来了 发表于 2025/10/25 17:32:44 2025/10/25
【摘要】 问题背景select current_database(), n.nspname,c.relname,0 from pg_class c , pg_namespace n where n.oid = c.relnamespace and (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"])) AND NOT pg_is...

问题背景

select current_database(), n.nspname,c.relname,0 from pg_class c , pg_namespace n where n.oid = c.relnamespace and (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"])) AND NOT pg_is_other_temp_schema(n.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES'::text)) and n.nspname = 'public' order by c.relname limit 20 offset 0;

语句执行慢,管理员用户很快,普通用户执行慢

发现是使用系统视图时,做了很多用or连接的权限判断:pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES'::text)

由于dabadmin用户pg_has_role总能返回true,因此or之后的条件无需继续判断;而普通用户的or条件需要逐一判断,如果数据库中表个数比较多,最终会导致普通用户比dbadmin需要更长的执行时间。

加hint, 走index + nestloop的优化后,时间从156秒优化到24秒。

/*+ nestloop(n c) leading((n c)) set global(enable_seqscan  off)*/

但是客户代码已上线,无法修改,无法加hint,使用管理员用户又不符合安全要求。

可通过配置,使用 Plan management功能进行计划绑定。即根据sql_hash,使语句和outline进行绑定。

版本要求:910及以上

Plan management特性基本原理:

在CN上,对每个sql生成的计划(除FQS计划或CN轻量化)进行遍历,将计划中的join算子、scan(table scan和index scan)算子、join和agg上的倾斜优化信息、join两端的stream算子以及表的关联顺序提取为outline(即一组hint,并将outline进行保存(dbms_om.sql_outline)。用户可通过topsql分析出哪个计划是优的,并将比较优的计划的outline绑定给该sql。绑定后,该sql再次生成计划时,会通过应用该hint来固定执行计划。

除FQS和CN强量化计划外,其他计划都会生成outline。

方法步骤

1.设置开启plan management

需要后台开启集群参数,无需重启
SET planmgmt_options='plan_save_mode_outline,enable_plan_baseline,plan_save_level_topsql';
SET enable_planmgmt_backend=on;

planmgmt_options中的plan_save_level_topsql可在配置完成功后去掉,避免sql_outline表过大,开启plan_save_level_topsql后,满足记录topsql条件的语句,都会往dbms_om.sql_outline表中记录相应的outline。

2.获取要绑定outline的sql_hash
可从topsql或执行计划中获取'sql_hash'

3.语句调优

获取需要绑定的OUTLINE,根据实际情况进行调优

加hint调优:/*+ nestloop(n c) leading((n c)) set global(enable_seqscan  off)*/
explain (verbose on, blockname on, outline on) select /*+ nestloop(n c) leading((n c)) set global(enable_seqscan  off)*/ current_database(), n.nspname,c.relname,0 from pg_class c , pg_namespace n where n.oid = c.relnamespace and (c.relkind = ANY (ARRAY['r'::"char", 'v'::"char", 'f'::"char"])) AND NOT pg_is_other_temp_schema(n.oid) AND (pg_has_role(c.relowner, 'USAGE'::text) OR has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER'::text) OR has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES'::text)) and n.nspname = 'public' order by c.relname limit 20 offset 0;

调优时,如果计划内容不够详细,可以set explain_perf_mode=normal;后打计划,可以看到更详细的计划,该参数默认为pretty。

4.获取OUTLINE

从dbms_om.sql_outline系统表获取OUTLINE,也可手动创建OUTLINE

查系统表:用优化后的sql_hash获取outline_name,

SELECT sql_hash, plan_hash, outline_name, outline FROM dbms_om.sql_outline where sql_hash like '%xxx%';

当系统表中记录的outline不满足诉求时,也可手动创建:

OUTLINE名称要以“outline_”开头,sql_hash需要与被绑定的语句保持一致,USING 后为OUTLINE的具体内容。

CREATE OUTLINE outline_name_1 FOR sql_7cd3bd7d2be865a0e315e3fdf29e2c0e USING '/*+
       begin_outline_data
        Leading[@"sel$1" n@"sel$1" c@"sel$1"]
        NestLoop(@"sel$1" n@"sel$1" c@"sel$1")
        IndexScan(@"sel$1" n@"sel$1" pg_namespace_nspname_index)
        IndexScan(@"sel$1" c@"sel$1" pg_class_relname_nsp_index)
       end_outline_data
   */
';

5.绑定outline

使用sql_hash,outline_name进行绑定
SELECT pgxc_bind_plan('sql_hash', 'outline_name_1');

6.验证

7.解绑

使用sql_hash解绑

SELECT pgxc_unbind_plan('sql_7cd3bd7d2be865a0e315e3fdf29e2c0e');

注:绑定OUTLINE后,手工写的hint有些会不生效,在进行hint调优时,建议解绑后再hint。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。