循序渐进丨MogDB 数据库新特性之SQL PATCH绑定执行计划

news2024/9/22 10:07:01

1

SQL PATCH

熟悉 Oracle 的DBA都知道,生产系统出现性能问题时,往往是SQL走错了执行计划,紧急情况下,无法及时修改应用代码,DBA可以采用多种方式针对于某类SQL进行执行计划绑定,比如SQL Profile、SPM、SQL Plan Base等等。

MogDB 数据库5.0版本引入了SQL PATCH的特性,SQL PATCH能够在避免直接修改用户业务语句的前提下对查询执行的方式做一定调整。在发现查询语句的执行计划、执行方式未达预期的场景下,可以通过创建查询补丁的方式,使用Hint对查询计划进行调优或对特定的语句进行报错短路处理。

SQL PATCH主要设计给DBA、运维人员及其他需要对SQL进行调优的角色使用,用户通过其他运维视图或定位手段识别到业务语句存在计划不优导致的性能问题时,可以通过创建SQL PATCH对业务语句进行基于Hint的调优。目前支持行数、扫描方式、连接方式、连接顺序、PBE custom/generic计划选择、语句级参数设置、参数化路径的Hint。

特性约束

    • 仅支持针对Unique SQL ID打PATCH,如果存在Unique SQL ID冲突,用于Hint调优的SQL PATCH可能影响性能,但不影响语义正确性。

    • 仅支持不改变SQL语义的Hint作为PATCH,不支持SQL改写。

    • 不支持逻辑备份、恢复。

    • 不支持创建时校验PATCH合法性,如果PATCH的Hint存在语法或语义错误,不影响查询正确执行。

    • 仅初始用户、运维管理员、监控管理员、系统管理员用户有权限执行;库之间不共享,创建SQL PATCH时需要连接目标库。

    • 配置集中式备机可读时,需要指定主机执行SQL PATCH创建/修改/删除函数调用,备机执行报错。

    • SQL PATCH同步给备机存在一定延迟,待备机回放相关日志后PATCH生效。

    • 不支持对存储过程中的SQL语句生效,当前机制不会对存储过程内语句生成Unique SQL ID。

    • 用于规避的Abort Patch不建议在数据库中长期使用,只应该作为临时规避方法;遇到内核问题所导致的特定语句触发数据库服务不可用问题,需要尽快修改业务或升级内核版本解决问题;并且升级后由于Unique SQL ID生成方法可能变化,可能导致规避方法失效。

    • 当前,除DML语句之外,其他SQL语句(如CREATE TABLE等)的Unique SQL ID是对语句文本直接哈希生成的,所以对于此类语句,SQL PATCH对大小写、空格、换行等敏感,即不同的文本的语句,即使语义相对,仍然需要对应不同的SQL PATCH;对于DML,则同一个SQL PATCH可以对不同入参的语句生效,并且忽略大小写和空格。

依赖关系

需要开启enable_resource_track参数并且设置instr_unique_sql_count大于0。对于不同的语句,如果生成的Unique SQL ID冲突,会导致SQL PATCH错误地命中预期外的其他语句。其中用于调优的Hint PATCH副作用相对较小,Abort Patch需要谨慎使用。

2

实际案例

1、创建表

创建表t1和t2;

 
 
create table t1(name char(10),id int);
create table t2(name char(10),id int);

2、构造数据

 
 
INSERT INTO t1 (name, id)
SELECT 'data_'|| generate_series(1, 1000), generate_series(1, 1000);


INSERT INTO t2 (name, id)
SELECT 'data_'|| generate_series(1, 1000), generate_series(1, 1000);


CREATE INDEX idx_t1 ON t1 (id);
CREATE INDEX idx_t2 ON t2 (id);

3、获取unique_query_id

执行SQL并获取unique_query_id、执行计划:

 
 
set track_stmt_stat_level = 'L1,L1'; 


--track_stmt_stat_level解释:
该参数分为两部分:
--形式为'full sql stat level, slow sql stat level'。
--级别(L2 > L1 > L0),L1在L0的基础上记录了执行计划,L2在L1的基础上记录了锁的详细信息


select * from t1 a, t2 b where a.id = b.id;
   name    |  id  |    name    |  id  
------------+------+------------+------
 data_1     |    1 | data_1     |    1
 data_2     |    2 | data_2     |    2
 data_3     |    3 | data_3     |    3
 data_4     |    4 | data_4     |    4
 data_5     |    5 | data_5     |    5
 data_6     |    6 | data_6     |    6
 data_7     |    7 | data_7     |    7
 。。。。
(1000 row)

4、获取查看执行计划

走的全表扫描hash jion执行计划:

 
 
explain select * from t1 a, t2 b where a.id = b.id;
                                QUERY PLAN  
--------------------------------------------------------------------------
 Aggregate  (cost=60.75..60.76 rows=1 width=8)
   ->  Hash Join  (cost=28.50..58.25 rows=1000 width=0)
         Hash Cond: (a.id = b.id)
         ->  Seq Scan on t1 a  (cost=0.00..16.00 rows=1000 width=4)
         ->  Hash  (cost=16.00..16.00 rows=1000 width=4)
               ->  Seq Scan on t2 b  (cost=0.00..16.00 rows=1000 width=4)

5、查询unique_query_id

 
 
select unique_query_id,query,start_time from dbe_perf.statement_history  where query like '%from t1 a%';
 unique_query_id |                       query                        |          start_time           
-----------------+----------------------------------------------------+-------------------------------
      3366573496 | select * from t1 a, t2 b where a.id = b.id;        | 2024-01-19 10:08:56.994391+08


也可以通过statement_history查询执行计划
select start_time,query_plan  from dbe_perf.statement_history  where unique_query_id = 3366573496;
          start_time           |                                query_plan                                
-------------------------------+--------------------------------------------------------------------------
 2024-01-19 10:08:56.994391+08 | Datanode Name: dn_6001_6002                                        +
                               | Hash Join  (cost=28.50..58.25 rows=1000 width=30)                  +
                               |   Hash Cond: (a.id = b.id)                                         +
                               |   ->  Seq Scan on t1 a  (cost=0.00..16.00 rows=1000 width=15)      +
                               |   ->  Hash  (cost=16.00..16.00 rows=1000 width=15)                 +
                               |         ->  Seq Scan on t2 b  (cost=0.00..16.00 rows=1000 width=15)+
                               |                                                                    +

6、SQL PATCH绑定执行计划

 
 
call dbe_sql_util.create_hint_sql_patch('enmo patch',3366573496,'indexscan(a)');
 create_hint_sql_patch 
-----------------------
 t
(1 row)


--参数说明:
enmo patch --SQL PATCH name
3366573496 --unique_query_id
indexscan(a) --Hint文本

7、验证SQL PATCH

 
 

执行并检查新的执行计划是否生效:

select * from t1 a, t2 b where a.id = b.id;
   name    |  id  |    name    |  id  
------------+------+------------+------
 data_1     |    1 | data_1     |    1
 data_2     |    2 | data_2     |    2
 data_3     |    3 | data_3     |    3
 data_4     |    4 | data_4     |    4
 data_5     |    5 | data_5     |    5
 data_6     |    6 | data_6     |    6
 data_7     |    7 | data_7     |    7
 。。。。


explain select * from t1 a, t2 b where a.id = b.id;
NOTICE:  Plan influenced by SQL hint patch
                                  QUERY PLAN                                  
------------------------------------------------------------------------------
 Hash Join  (cost=28.50..86.50 rows=1000 width=30)
   Hash Cond: (a.id = b.id)
   ->  Index Scan using idx_t1 on t1 a  (cost=0.00..44.25 rows=1000 width=15) 
      --这里走了索引,表示SQL patch生效
   ->  Hash  (cost=16.00..16.00 rows=1000 width=15)
         ->  Seq Scan on t2 b  (cost=0.00..16.00 rows=1000 width=15)
(5 rows)

查看statement_history的执行计划:

select query_plan,to_char(start_time,'yyyymmdd-hh24:mi:ss') starttime
from dbe_perf.statement_history 
where unique_query_id = 3366573496
order by start_time;
 Datanode Name: dn_6001_6002                                                 +| 20240119-10:09:54
 Hash Join  (cost=28.50..86.50 rows=1000 width=30)                           +| 
   Hash Cond: (a.id = b.id)                                                  +| 
   ->  Index Scan using idx_t1 on t1 a  (cost=0.00..44.25 rows=1000 width=15)+| 
   ->  Hash  (cost=16.00..16.00 rows=1000 width=15)                          +| 
         ->  Seq Scan on t2 b  (cost=0.00..16.00 rows=1000 width=15)         +| 
                                                                             +| 
                                                                              |

查看数据库内已定义的SQL Patch:

select patch_name,unique_sql_id,enable,hint_string from gs_sql_patch;
 patch_name | unique_sql_id | enable | hint_string  
------------+---------------+--------+--------------
 enmo patch |    3366573496 | t      | indexscan(a)


show_sql_patch查看SQL PATCH内容
MogDB=# select  DBE_SQL_UTIL.show_sql_patch('enmo patch');
           show_sql_patch            
-------------------------------------
 (3366573496,t,f,"indexscan(a)")
(1 row)

8、Abort Patch

使用Abort PATCH对特定语句进行提前报错规避:

 
 
MogDB=# select * from dbe_sql_util.drop_sql_patch('enmo patch'); -- 删去enmo patch
 drop_sql_patch
----------------
 t
(1 row)
MogDB=# select * from dbe_sql_util.create_abort_sql_patch('patch2', 3366573496); -- 对该语句的Unique SQL ID创建Abort Patch
 create_abort_sql_patch
------------------------
 t
(1 row)


MogDB=# select * from t1 a, t2 b where a.id = b.id; -- 再次执行语句会提前报错
ERROR:  Statement 3366573496 canceled by abort patch patch2

9、关闭特定SQL Patch

 
 
disable enmo patch
call dbe_sql_util.disable_sql_patch('enmo patch');

执行SQL并检查执行计划是否恢复原始状态:

MogDB=# select  query_plan,to_char(start_time,'yyyymmdd-hh24:mi:ss') starttime
MogDB-#  from dbe_perf.statement_history 
MogDB-#  where  unique_query_id = 3366573496
MogDB-#  order by start_time;
                                query_plan                                |     starttime     
--------------------------------------------------------------------------+-------------------
 Datanode Name: dn_6001_6002                                             +| 20240119-13:24:52
 Nested Loop  (cost=0.00..340.00 rows=1000 width=30)                     +| 
   ->  Seq Scan on t1 a  (cost=0.00..16.00 rows=1000 width=15)           +| 
   ->  Index Scan using idx_t2 on t2 b  (cost=0.00..0.31 rows=1 width=15)+| 
         Index Cond: (id = a.id)                                         +| 
                                                                         +| 
                                                                          | 
 Datanode Name: dn_6001_6002                                             +| 20240119-13:31:49
 Hash Join  (cost=28.50..58.25 rows=1000 width=30)                       +| 
   Hash Cond: (a.id = b.id)                                              +| 
   ->  Seq Scan on t1 a  (cost=0.00..16.00 rows=1000 width=15)           +| 
   ->  Hash  (cost=16.00..16.00 rows=1000 width=15)                      +| 
         ->  Seq Scan on t2 b  (cost=0.00..16.00 rows=1000 width=15)     +| 
                                                                         +|

最新的执行计划已经还原成hash jion。

MogDB 数据库官方文档参考:

    • SQL PATCH特性描述:https://docs.mogdb.io/zh/mogdb/v5.0/sql-patch#特性描述

    • track_stmt_stat_level:https://docs.mogdb.io/zh/mogdb/v5.0/query#track_stmt_stat_level

关于作者

许玉晨,云和恩墨 MogDB 技术支持工程师,有12年左右的金融、保险、政府、地税、运营商等业务关键型系统的运维经验,曾担任公司异常恢复东区接口人,负责紧急异常恢复工作,目前负责国产化MogDB数据库的推广工作。

8d11367cc484ec24d340be1b5b3eacae.gif

数据驱动,成就未来,云和恩墨,不负所托!


云和恩墨创立于2011年,以“数据驱动,成就未来”为使命,是智能的数据技术提供商。我们致力于将数据技术带给每个行业、每个组织、每个人,构建数据驱动的智能未来。

云和恩墨在数据承载(分布式存储、数据持续保护)、管理(数据库基础软件、数据库云管平台、数据技术服务)、加工(应用开发质量管控、数据模型管控、数字化转型咨询)和应用(数据服务化管理平台、数据智能分析处理、隐私计算)等领域为各个组织提供可信赖的产品、服务和解决方案,围绕用户需求,持续为客户创造价值,激发数据潜能,为成就未来敏捷高效的数字世界而不懈努力。

cb4ee4c75b07a8aa336d301e56042a5c.gif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1503228.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

详解前端登录流程:实现原理与最佳实践

🤍 前端开发工程师、技术日更博主、已过CET6 🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 🍚 蓝桥云课签约作者、上架课程《Vue.js 和 E…

考研复习C语言初阶(3)

目录 一.函数是什么? 二.C语言中函数的分类 2.1库函数 2.2自定义函数 三.函数的参数 3.1实际参数(实参) 3.2 形式参数(形参) 四.函数的调用 4.1 传值调用 4.2 传址调用 五. 函数的嵌套调用和链式访问 5.1 嵌套调用 5…

使用Python编写简单学生管理系统

学完python基础,把学过的知识运用起来做一个简单的学生管理系统 1、需求分析 需求:进入系统显示系统功能界面,功能如下: ① 添加学员信息 ② 删除学员信息 ③ 修改学员信息 ④ 查询学员信息(只查询某个学员) ⑤ 遍历所有学…

专家院士共同参编的《数字空间共同体白皮书》正式启动

数字产业化、产业数字化,促进数字技术和实体经济深度融合,成为数字经济高质量发展的重要路径。数字空间与物理空间双向融合,用数字技术提升企业有限资源的有效配置,构建经济双空间增长模式,是形成企业新质生产力的关键…

JVM基本概念、命令、参数、GC日志总结

原文: 赵侠客 一、前言 NPE(NullPointerException)和OOM(OutofMemoryError)在JAVA程序员中扮演着重要的角色,它也是很多人始终摆脱不掉的梦魇,与NPE不同的是OOM一旦在生产环境中出现就意味着只靠代码已经无…

鸿蒙App语法/结构/注意

注意 默认情况下,应用只能访问有限的系统资源。其他资源权限处理https://developer.harmonyos.com/cn/docs/documentation/doc-guides-V3/accesstoken-overview-0000001544703857-V3 .1、权限申请使用流程 https://developer.harmonyos.com/cn/docs/documentatio…

【REST2SQL】12 REST2SQL增加Token生成和验证

【REST2SQL】01RDB关系型数据库REST初设计 【REST2SQL】02 GO连接Oracle数据库 【REST2SQL】03 GO读取JSON文件 【REST2SQL】04 REST2SQL第一版Oracle版实现 【REST2SQL】05 GO 操作 达梦 数据库 【REST2SQL】06 GO 跨包接口重构代码 【REST2SQL】07 GO 操作 Mysql 数据库 【RE…

poetry库:依赖管理和打包工具

这个工具是在群里看见别人说好用的,所以了解一下。 1.poetry初始 官网:https://python-poetry.org/ 项目仓库:https://github.com/python-poetry 或 https://github.com/python-poetry/poetry 教程:https://python-poetry.org/…

Day01-项目介绍及初始化-登录页面(test)

1.人力资源项目介绍 1.1 项目架构和解决方案 1.2 课程安排 1.3 课程具备能力 1.4 课程地址 vue-element-admin文档地址:链接演示地址: 链接人力资源项目演示地址: 链接 2. 拉取项目基础代码 拉取命令 $ git clone https://github.com/P…

河北专升本(C语言编程题)

一:基础算法原理 1. 冒泡排序 原理:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个。这个数就会从序列的最右边冒出来。 以从小到大排序为例,第一轮比较后,所有数中最大的…

【设计】基于web的会员管理系统

1、引言 设计结课作业,课程设计无处下手,网页要求的总数量太多?没有合适的模板?数据库,java,python,vue,html作业复杂工程量过大?毕设毫无头绪等等一系列问题。你想要解决的问题&am…

云计算项目九:K8S安装

K8S安装 Kube-master安装 按照如下配置准备云主机 防火墙相关配置:禁用selinux,禁用swap,且在firewalld-*。上传kubernetes.zip 到跳板机 配置yum仓库(跳板机) 跳板机主机配置k8s软件源服务端 [rootjs ~]# yum -y…

仿射变换下的点位纠偏

点位偏差一直是一个很头疼的问题,但是由于摄像头和实际环境的局限性,我们不得不面对这个问题。对此,使用判别的方式进行一个仿射变换,是一种非常有效的方式,下图中图1是基准图,图2是目标图,图3是…

使用CSS制作动态的环形图/饼图

使用纯 CSS Animation conic-gradient 实现一个环形图。 饼图的实现思路和环形图一样&#xff0c;去掉中间的圆形遮盖 after 伪类元素即可。 一、构建基础样式 构建圆形节点和中间的遮盖元素。 <style>body {background-color: rgb(130, 226, 255);}.circle {top: 16…

GIS之深度学习08:安装GPU环境下的pytorch

环境&#xff1a; cuda&#xff1a;12.1.1 cudnn&#xff1a;12.x pytorch&#xff1a;2.2.0 torchvision&#xff1a;0.17.0 Python&#xff1a;3.8 操作系统&#xff1a;win &#xff08;本文安装一半才发现pytorch与cuda未对应&#xff0c;重新安装了cuda后才开始的&a…

时间服务器

目录 软件介绍 软件安装 准备工作 设置当前时区 修改chronyd配置文件 设置允许哪个客户端可以访问该服务器 设置本地服务器时间为第10层级 时钟层&#xff1a; 实例:配置时间服务器客户端服务端 Serves Client 配置环境&#xff1a; systemctl命令 lsof 命令 语法 选项 lsof输…

JL15-80/11电流继电器 过电流瞬时动作 电磁式结构 80A 一开一闭

JL15电流继电器 系列型号 JL15-1.5/11电流继电器JL15-2.5/11电流继电器 JL15-5/11电流继电器JL15-10/11电流继电器 JL15-15/11电流继电器JL15-20/11电流继电器 JL15-30/11电流继电器JL15-40/11电流继电器 JL15-60/11电流继电器JL15-80/11电流继电器 JL15-100/11电流继电器JL15…

mac本地启动sentinel

启动Sentinel控制台 1&#xff09;下载sentinel控制台jar包 https://github.com/alibaba/Sentinel/releases/download/1.8.6/sentinel-dashboard-1.8.6.jar 2&#xff09;启动sentinel控制台 使用如下命令启动控制台&#xff1a; java -Dserver.port8080 -Dcsp.sentinel.d…

[清爽快捷] Ubuntu上多个版本的cuda切换

做到真正的一行代码搞定&#xff0c;只需要修改对应软链接&#xff0c;就可以轻松实现快捷切换cuda 查看已安装的cuda版本有哪些 一般如果我们都是使用默认位置安装cuda的话&#xff0c;那么其安装路径都是/usr/local。如果要查看该目录下已经安装有哪些版本的cuda&#xff0c…

腾讯面经学习笔记

&#x1f496; 前言 &#x1f469;‍&#x1f3eb; 参考地址 &#x1f496; 操作系统 1. 进程和线程的区别 本质区别 进程是操作系统资源分配的基本单位线程是任务调度和执行的基本单位 开销方面 每个进程都有独立的代码和数据空间&#xff08;程序上下文&#xff09;&#…