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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙实战多媒体运用:【音频组件】

音频组件用于实现音频相关的功能,包括音频播放,录制,音量管理和设备管理。 图 1 音频组件架构图 基本概念 采样 采样是指将连续时域上的模拟信号按照一定的时间间隔采样,获取到离散时域上离散信号的过程。 采样率 采样率为每…

macos m1 arm芯片 使用jpype报错 FileNotFoundError: [Errno 2] JVM DLL not found

startJVM(jpype.getDefaultJVMPath()) 报错 Traceback (most recent call last):File "/Users/thomas990p/PycharmProjects/tuya/volcano-biz-scripts/WenKongFa/FinalCode/java2python/CallJavaAPI.py", line 12, in <module>startJVM(jpype.getDefaultJVMPa…

寻找两个正序数组的中位数[困难]

优质博文IT-BLOG-CN 一、题目 给定两个大小分别为m和n的正序&#xff08;从小到大&#xff09;数组nums1和nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为O(log (mn)) 。 示例 1&#xff1a; 输入&#xff1a;nums1 [1,3], nums2 [2] 输出&…

【漏洞复现】帮管客 CRM jiliyu SQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

用 Axios 提升前端异步请求的效率

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

代码随想录 -- 栈和队列

文章目录 栈实现队列描述题解 用队列实现栈描述题解 有效的括号描述题解 删除字符串中的所有相邻重复项描述题解 逆波兰表达式求值描述题解 滑动窗口最大值描述题解&#xff1a;暴力题解&#xff1a;单调队列 前 K 个高频元素描述题解 栈实现队列 题目链接 描述 使用两个栈实…

WPF开源的一款免费、开箱即用的翻译、OCR工具

前言 今天大姚给大家分享一款由WPF开源的、免费的&#xff08;MIT License&#xff09;、即开即用、即用即走的翻译、OCR工具&#xff1a;STranslate。 WPF介绍 WPF 是一个强大的桌面应用程序框架&#xff0c;用于构建具有丰富用户界面的 Windows 应用。它提供了灵活的布局、…

TCP包头、TCP为什么安全可靠、UDP和TCP的区别、http协议

我要成为嵌入式高手之3月8日Linux高编第十八天&#xff01;&#xff01; __________________________________________________ 学习笔记 TPC包头 1、序号 发送端发送数据包的编号 2、确认号 已经确认接收到的数据的编号&#xff0c;只有当ACK为1时&#xff0c;该位才有用 …

sentinel prometheus指标收集及资源规则正则表达式实现

sentinel 支持 prometheus 收集指标 实现原理 在 sentinel-extension 模块下&#xff0c;新增 sentinel-prometheus-metric-exporter 模块。依赖Prometheus 提供的 simpleclient 和 simpleclient_httpserver 来实现 exporter。 依赖 simpleclient 主要是为了实现自定义Collect…

关于手机是否支持h264的问题的解决方案

目录 现象 原理 修改内容 现象 开始以为是手机不支持h264的编码 。机器人chatgpt一通乱扯。 后来检查了下手机&#xff0c;明显是有h264嘛。 终于搞定&#xff0c;不枉凌晨三点起来思考 原理 WebRTC 默认使用的视频编码器是VP8和VP9&#xff0c;WebRTC内置了这两种编码器…

flink重温笔记(十二): flink 高级特性和新特性(1)——End-to-End Exactly-Once(端到端精确一致性语义)

Flink学习笔记 前言&#xff1a;今天是学习 flink 的第 12 天啦&#xff01;学习了 flink 高级特性和新特性之 End-to-End Exactly-Once&#xff08;端到端精确一致性语义&#xff09;&#xff0c;主要是解决大数据领域数据从数据源到数据落点的一致性&#xff0c;不会容易造成…

计算机组成原理之机器:存储器之辅助存储器

计算机组成原理之机器&#xff1a;存储器之辅助存储器 笔记来源&#xff1a;哈尔滨工业大学计算机组成原理&#xff08;哈工大刘宏伟&#xff09; Chapter3&#xff1a;存储器之辅助存储器 3.1 概述 3.2 磁记录原理 通不同方向电流时磁化方向不同&#xff0c;由此区分写入…

逆向分析 FSViewer 并写出注册机

逆向分析 FSViewer 并写出注册机 FSViewer是一款老牌的图片管理查看编辑软件, 个人使用免费, 商用收费 本文将逆向分析FSViewer 7.5版本的注册算法并编写注册机 0. 前言 最近在整理之前的资料, 发现了一篇几年前刚学逆向那会儿写的文章, 是跟着看雪一位大牛的文章做的, 但逆向…

基于yolov5的番茄检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的小番茄检测系统&#xff0c;系统既能够实现图像检测&#xff0c;也可以进行视屏和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的番茄检测系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目&…

Vue 项目性能优化指南:提升应用速度与效率

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

【前端】-初始前端以及html的学习

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你 …

(未解决)macOS matplotlib 中文是方框

reference&#xff1a; Mac OS系统下实现python matplotlib包绘图显示中文(亲测有效)_mac plt 中文值-CSDN博客 module ‘matplotlib.font_manager‘ has no attribute ‘_rebuild‘解决方法_font_manager未解析-CSDN博客 # 问题描述&#xff08;笑死 显而易见 # solve 找到…

CleanMyMac X4.15.0专为macOS设计的清理和优化工具

CleanMyMac X 是一款专为 macOS 设计的清理和优化工具。其基本功能和特点主要包括&#xff1a; 系统清理&#xff1a;CleanMyMac X 可以扫描并清除 macOS 系统中的垃圾文件&#xff0c;如缓存、日志、无用的语言文件等&#xff0c;从而释放硬盘空间并提高系统性能。应用程序管…

贪心算法(greedy algorithm,又称贪婪算法)详解(附例题)

目录 基本思想一&#xff09;概念二&#xff09;找出全局最优解的要求三&#xff09;求解时应考虑的问题四&#xff09;基本步骤五&#xff09;贪心策略选择六&#xff09;实际应用 1.零钱找回问题2.背包问题3.哈夫曼编码4.单源路径中的Djikstra算法5.最小生成树Prim算法 基本…

备考银行科技岗刷题笔记(持续更新版)

银行考试计算机部分复习 IEEE 802.11的帧格式 1.1 IEEE 802.11是什么&#xff1f; 802.11是国际电工电子工程学会&#xff08;IEEE&#xff09;为无线局域网络制定的标准。目前在802.11的基础上开发出了802.11a、802.11b、802.11g、802.11n、802.11ac。并且为了保证802.11更…