【MogDB】MogDB5.2.0重磅发布第八篇-支持PLSQL编译全局缓存

news2024/11/17 20:56:09

前言

在我之前的文章中有提过,原生PG对于重度存储过程的应用系统适配,具有一个致命缺陷,即原生PG中的plsql是会话级缓存,这意味着每个会话在第一次执行某个存储过程时,都需要对这个存储过程进行编译,并且将编译结果缓存到本会话,由此引发巨大的内存占用(应用连接池多连接)以及首次调用时的严重性能问题(应用短连接)。

测试

下面在openGauss 6.0.0版本中测试,使用匿名块构造了一个约两万行的存储过程,并且创建进了数据库,包含有循环、判断、DML、赋值、简单计算表达式,但实际这个存储过程begin后的第一行就是return,避免执行不同语句的时间干扰对性能的判断。

DECLARE
  v_sql CLOB := '';
  v_table_sql CLOB := '';
  v_line_count int:=20000;
BEGIN
  -- 生成建表语句
  v_table_sql := 'CREATE TABLE example_table (id NUMBER PRIMARY KEY, name VARCHAR2(100), value NUMBER);';
 execute immediate  v_table_sql;

  -- 初始化procedure创建语句
  v_sql := 'CREATE OR REPLACE PROCEDURE example_pro IS
      v_counter NUMBER := 0;
      v_sum NUMBER := 0;
    BEGIN
return;
  ';
  -- 代码翻倍
  FOR i IN 1..trunc(v_line_count/10) LOOP
    v_sql := v_sql || '  v_counter := v_counter + 1;
      v_sum := v_sum + ' || i || ';
      IF MOD(' || i || ', 2) = 0 THEN
        INSERT INTO example_table (id, name, value) VALUES (' || i || ', ''Even'', v_sum);
      ELSE
        INSERT INTO example_table (id, name, value) VALUES (' || i || ', ''Odd'', v_sum);
      END IF;
      FOR j IN 1..5 LOOP
        v_sum := v_sum + j;
      END LOOP;
    ';
  END LOOP;

  -- 结束procedure
  v_sql := v_sql || '  v_sum := v_sum / 50000;
      --DBMS_OUTPUT.PUT_LINE(''Average Sum: '' || v_sum);
  END ;
';
  -- 执行生成的procedure创建语句
  execute immediate v_sql;
END;
/

然后开启计时,比如PG/OG系数据库在自带命令行客户端中的方式为

\timing on

手动调用几次这个存储过程

call example_pro();

并且尝试更换会话去执行这个存储过程

[og600@kylinv10sp3-node1 ~]$ gsql -r
gsql ((openGauss 6.0.0 build aee4abd5) compiled at 2024-09-29 18:39:52 commit 0 last mr  )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

openGauss=# \timing on
Timing is on.
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1141.496 ms
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1.327 ms
openGauss=# \c postgres
Non-SSL connection (SSL connection is recommended when requiring high-security)
You are now connected to database "postgres" as user "og600".
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1150.205 ms
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1.399 ms
openGauss=#

可以看到每个会话首次执行与第二次执行的时长差异巨大。如果是个短连接的应用,执行一次就断开连接,执行十次需要十几秒,但是实际存储过程本身的执行时间可能才十几毫秒!

然后观察下首次执行这个存储过程前后,该会话的内存使用情况。

openGauss=# select  pg_size_pretty(sum(usedsize)) from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid();
 pg_size_pretty
----------------
 8900 kB
(1 row)

Time: 14.220 ms
openGauss=# select  contextname,totalsize,usedsize from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid() order by usedsize desc limit 10;
           contextname           | totalsize | usedsize
---------------------------------+-----------+----------
 LocalSysCacheShareMemoryContext |   5368400 |  4104592
 PLpgSQL function cache          |   2076184 |  2073416
 LocalSysCacheTopMemoryContext   |   1097888 |   650800
 ThreadTopMemoryContext          |    417288 |   400392
 DefaultTopMemoryContext         |    344608 |   270624
 CBBTopMemoryContext             |    243984 |   223904
 LocalSysCacheMyDBMemoryContext  |    253952 |   220584
 StorageTopMemoryContext         |    125744 |    91224
 Timezones                       |     83504 |    80736
 Type information cache          |     73232 |    70464
(10 rows)

Time: 21.794 ms
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1134.256 ms
openGauss=# call example_pro();
 example_pro
-------------

(1 row)

Time: 1.259 ms

openGauss=# select  pg_size_pretty(sum(usedsize)) from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid();
 pg_size_pretty
----------------
 25 MB
(1 row)

Time: 19.403 ms
openGauss=# select  contextname,totalsize,usedsize from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid() order by usedsize desc limit 10;
                contextname                | totalsize | usedsize
-------------------------------------------+-----------+----------
 PL/pgSQL function context_281474977359207 |  25173800 | 17169704
 LocalSysCacheShareMemoryContext           |   5368400 |  4104592
 PLpgSQL function cache                    |   2076184 |  2073416
 LocalSysCacheTopMemoryContext             |   1097888 |   650800
 ThreadTopMemoryContext                    |    466440 |   419720
 DefaultTopMemoryContext                   |    344608 |   270624
 CBBTopMemoryContext                       |    243984 |   223904
 LocalSysCacheMyDBMemoryContext            |    253952 |   223400
 OptimizerTopMemoryContext                 |    108200 |   102888
 StorageTopMemoryContext                   |    125744 |    91224
(10 rows)

Time: 14.663 ms

可以发现该会话多了一个PL/pgSQL function context_*的内存占用,差不多就是执行存储过程后,增加的17MB内存。
做个粗略的计算,假设某应用系统有200个这样的存储过程(约400万行plsql代码),连接池有200个并发,那么光存储过程就能把内存吃掉 17*200*200/1024 MB=660 GB
而且该例子中的存储过程还比较简单,没有复杂表达式,变量也少,也没有使用自定义类型,否则内存占用会更多,有些国产高配的1TB内存服务器都玩不转了。

很多大行核心系统都是千万级的PLSQL代码,而且并发数肯定也不止200个,所以这个问题必然是PG/OG系数据库要解决的一个核心问题。

MogDB 5.2.0的突破

根据以上的测试,可以发现该问题的核心在于,存储过程的编译产物是在当前会话里,不能被其他会话共享,因此解决这个问题的关键,就是让存储过程的编译产物放进共享内存。于是MogDB在5.2.0版本新增了特性–GLOBAL PLSQL CACHE(全局PLSQL缓存)。

1.相关参数

enable_global_plsql_cache
参数描述:控制是否启用global PL/SQL cache功能。
参数级别:该参数属于POSTMASTER类型参数。修改需要重启生效
取值范围:布尔型。
默认值: on 。即默认打开global PL/SQL cache。

plsql_global_cache_max_memory
参数描述:Global PL/SQL cache的内存大小限制,用于存放编译的PL/SQL function/package。当插入的内存的function/package大小大于此参数值时,会对global_cache做内存清理
参数级别:该参数属于SIGHUP类型参数。
取值范围:5MB - 1TB
默认值: 1GB

plsql_global_cache_clean_timeinterval
参数描述:清理global_cache的时间间隔。
参数级别:该参数属于SIGHUP类型参数。
取值范围:5分钟 - 36500天
默认值:30分钟

plsql_global_cache_clean_percent
参数描述:清理一次global_cache时,至少要清理的global_cache空间比例。
参数级别: 该参数属于SIGHUP类型参数。
取值范围:1 - 100
默认值:20(即至少清理20%)

2.相关函数

缓存信息查询函数
select * from plsql_global_cache_info();

字段说明

  • database : 该PL/SQL cache function/Package所在的database Oid。
  • xmin: 该PL/SQL cache function/Package 记录的xmin。
  • trigrel_oid: 对于PL/SQL cache trigger function,记录触发表的Oid。
  • collation: 该PL/SQL cache function/Package的collationOid
  • Namespace: 该PL/SQL cache function/Package 所在的schema Oid。
  • Oid: 该PL/SQL cache function/Package的Oid。
  • Name : 该PL/SQL cache function/Package的名称。
  • type_enum: 该PL/SQL cache 的类型:function/procedure/pkg_spec/pkg_body。
  • search_path: 该PL/SQL cache function/Package编译时的search_path。
  • valid:该PL/SQL cache function/Package 是否有效。当前该记录被删除或repalce后,该标记会设置为false,并且待ref_count为0后,清除该cache。
  • ref_count: 该PL/SQL cache function/Package的引用计数。
  • used_count:该PL/SQL cache function/Package的使用次数。
  • total_space:该PL/SQL cache function/Package 占用的空间大小,单位为字节。
  • inval_items:该PL/SQL cache function/Package依赖的其他object。
  • is_all_func_compiled:该字段为区分Package spec和body。当该字段为false时,表明该记录为pkg spec,不包含body。当该字段为true时,表面该记录为pkg body并包含pkg spec。
移除缓存函数

plsql_cache_clean
plsql_cache_drop_object

3.MogDB实测

[mogdb26200@kylinv10sp3-node1 ~]$ gsql -r -U system -W oracle -d testdb
gsql ((MogDB 5.2.0 build e0c9adc2) compiled at 2024-09-28 02:48:39 commit 0 last mr 1804 )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

testdb=> \timing on
Timing is on.
testdb=> select  pg_size_pretty(sum(usedsize)) from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid();
 pg_size_pretty
----------------
 9394 kB
(1 row)

Time: 20.083 ms
testdb=> select  contextname,totalsize,usedsize from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid() order by usedsize desc limit 10;
         contextname          | totalsize | usedsize
------------------------------+-----------+----------
 SessionCacheMemoryContext    |   3534048 |  2808640
 PLpgSQL function cache       |   2076184 |  2073416
 ThreadTopMemoryContext       |    587432 |   517960
 FunctionScan_22875809511168  |    532560 |   464656
 ExprContext                  |    516096 |   379232
 StorageTopMemoryContext      |    354384 |   328744
 global_session_memory_detail |    231224 |   227936
 session_memory_detail        |    231224 |   226112
 node_name                    |    223032 |   221184
 CBBTopMemoryContext          |    236736 |   217256
(10 rows)

Time: 24.702 ms
testdb=> call example_pro();
 example_pro
-------------

(1 row)

Time: 1.370 ms
testdb=> call example_pro();
 example_pro
-------------

(1 row)

Time: 1.072 ms
testdb=> select  pg_size_pretty(sum(usedsize)) from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid();
 pg_size_pretty
----------------
 9471 kB
(1 row)

Time: 24.194 ms
testdb=> select  contextname,totalsize,usedsize from dbe_perf.global_session_memory_detail where sessid ~pg_backend_pid() order by usedsize desc limit 10;
         contextname          | totalsize | usedsize
------------------------------+-----------+----------
 SessionCacheMemoryContext    |   3602144 |  2883952
 PLpgSQL function cache       |   2076184 |  2073416
 ThreadTopMemoryContext       |    587432 |   518504
 FunctionScan_22875809511168  |    532560 |   464656
 ExprContext                  |    516096 |   379232
 StorageTopMemoryContext      |    354384 |   329152
 global_session_memory_detail |    231224 |   227936
 session_memory_detail        |    231224 |   226112
 node_name                    |    223032 |   221184
 CBBTopMemoryContext          |    236736 |   217256
(10 rows)

Time: 23.035 ms
testdb=>

从这个测试结果可以看到,MogDB 5.2.0的会话内存占用,在首次调用存储过程后,并无显著增长,而且首次执行速度相比第二次执行速度,差异并不大。
我们再进行一次粗略计算,和前面的假设一样,某应用系统有200个这样的存储过程(约400万行plsql代码),连接池有200个并发,由于PLSQL编译结果共享了,不在单个会话内,所以存储过程的内存占用约为 17*200*1024 MB=3.3 GB 远低于无 global plsql cache时660GB占用!而且并发数越高,plsql代码量越大、越复杂,启用global plsql cache节省的内存越多!

全局PLSQL缓存还能干什么?

MogDB又做了一个创新。
对于重度存储过程使用的应用软件而言,尤其那种迭代开发了十几、甚至数十年的应用软件,代码内部存在不计其数的逻辑分支,软件升级后的回归测试,尤其在国产数据库替换时,很难保证所有的代码都被执行过,这个时候就需要有存储过程覆盖率这个功能。很多数据库产品设计plsql覆盖率这个功能只能支持单会话内统计,但真实的场景期望是不要按单个会话统计,而是应用多个连接真正把业务运行起来,所有场景都测完后,再去看这个覆盖率,从而对测试场景进行查漏补缺。
存储过程覆盖率简单来说可以理解为有个数据,里面有每个存储过程的每一行代码,并且有记录每一行是否有执行到,对多会话进行统计就必须要有个公共的区域来进行这个数据的统计。
既然做了全局PLSQL缓存,这不就是现成的公共区域么,而且plsql代码也已经有了,不需要再次获取。而且由于不是用表进行的统计,大大降低了并发时的锁冲突时间。
因此MogDB 5.2.0把存储过程覆盖率这个功能做到了全局PLSQL缓存内。
后面有时间再单独介绍这个功能。

总结

其实openGauss相比原生postgresql,在内存的优化上的确也做了不少工作,比如global plancache–全局计划缓存、global syscache–全局系统缓存(数据字典),而且将PG的进程模型改为线程模型,避免了这种内存上下文在进程间频繁交换导致的性能问题。MogDB 5.2.0实现了global plsql cache,并默认开启,这对于拥有重度存储过程代码的ORACLE应用迁移到国产数据库,具有非常深刻的意义。

  • 本文作者: DarkAthena
  • 本文链接: https://www.darkathena.top/archives/mogdb-5.2.0-support-plsql-global-cache
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处

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

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

相关文章

TensorFlow 2.0 环境配置

官方文档:CUDA Installation Guide for Windows 官方文档有坑,windows的安装指南直接复制了linux的指南内容:忽略这些离谱的信息即可。 可以从官方文档知悉,cuda依赖特定版本的C编译器。但是我懒得为了一个编译器就下载整个visua…

【计算机网络】【传输层】【习题】

计算机网络-传输层-习题 文章目录 10. 图 5-29 给出了 TCP 连接建立的三次握手与连接释放的四次握手过程。根据 TCP 协议的工作原理,请填写图 5-29 中 ①~⑧ 位置的序号值。答案技巧 注:本文基于《计算机网络》(第5版)吴功宜、吴英…

HarmonyOS本地存储-Preferences(用户首选项)的使用

一,用户首选项简述 ohos.data.preferences (用户首选项) 用户首选项为应用提供Key-Value键值型的数据处理能力,支持应用持久化轻量级数据,并对其修改和查询。 数据存储形式为键值对,键的类型为字符串型,值的存储数据…

基于Java Web 的家乡特色菜推荐系统

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

【售前方案】工业园区整体解决方案,智慧园区方案,智慧城市方案,智慧各类信息化方案(ppt原件)

基于云计算、物联网、移动通信计算的智慧园区集中运营管理平台是一个高度集成化、智能化的管理系统,它利用先进的技术手段对园区进行全方位的监控和管理。 软件资料清单列表部分文档清单:工作安排任务书,可行性分析报告,立项申请审…

Vue2+ElementUI:用计算属性实现搜索框功能

前言: 本文代码使用vue2element UI。 输入框搜索的功能,可以在前端通过计算属性过滤实现,也可以调用后端写好的接口。本文介绍的是通过计算属性对表格数据实时过滤,后附完整代码,代码中提供的是死数据,可…

CSS实现炫酷的水波纹效果

炫酷的水波纹效果 看好了&#xff0c;下面是我最后的波纹了 实现代码 HTML&#xff1a; <div class"container"></div> <script src"https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.js"></script>CSS: body{height: 1…

【会话文本nlp】对话文本解析库pyconverse使用教程版本报错、模型下载等问题解决超参数调试

前言&#xff1a; 此篇博客用于记录调用pyconverse库解析对话文本时遇到的问题与解决思路&#xff0c;以供大家参考。 文章目录 pycoverse介绍代码github链接问题解决1 [cannot import name ‘cached_download‘ from ‘huggingface_hub‘ 问题解决](https://blog.csdn.net/wei…

单元测试时报错找不到@SpringBootConfiguration

找到问题出现原因&#xff1a; 错误表示 Spring Boot 在运行测试时无法找到 SpringBootConfiguration 注解。 通常&#xff0c;SpringBootTest注解用于加载 Spring Boot 应用上下文&#xff0c;但它需要找到一个带有SpringBootConfiguration&#xff08;或者Configuration&am…

【数据结构】11.哈夫曼树哈夫曼编码

一、哈夫曼树的基本概念 哈夫曼&#xff08;Huffman&#xff09;树又称最优树&#xff0c;是一类带权路径长度最短的树&#xff0c;在实际中有广泛的用途。 路径&#xff1a; 从树中一个节点到另一个节点之间的分支构成这两个节点之间的路径。路径长度&#xff1a; 路径上的分…

AntD表单自定义组件

前言 表单可以说是前端最常见的一种组件&#xff0c;特别是在进行搜索的时候使用的最频繁&#xff0c;自定义表单组件&#xff0c;丰富了搜索框的类型&#xff0c;使数据展现的更灵活 内容讲解 1、官方介绍 AntD-Formhttps://ant.design/components/form-cn#form-demo-cust…

day-83 最少翻转次数使二进制矩阵回文 II

思路 关键在于1的个数要为4的倍数&#xff0c;首先镜像的四个位置肯定一定为4的倍数&#xff0c;如果行和列为奇数则需要单独考虑&#xff0c;如果行和列皆为奇数&#xff0c;那么中心的那个数一定为0 解题过程 再单独考虑如果行和列为奇数&#xff0c;具体参考灵神。如果diff…

Gitcode文件历史记录查看和还原

文件历史记录 文件历史记录用于记录代码文件的更改历史&#xff0c;它允许用户查看文件的不同版本&#xff0c;了解每个版本的修改内容、作者和提交消息。这对于跟踪文件演进、恢复错误更改、审查代码以及了解项目进展都非常有用。 文件历史记录功能提供了以下核心功能&#…

WebSocket协议在Java中的整合

1. 常见的消息推送方式 2.WebSocket API 3.基于WebSocket的实战&#xff08;实时聊天室&#xff09; 这里以解析后端代码为主&#xff0c;前端不作为重点&#xff0c;若想复现项目&#xff0c;请从作者的仓库中拉取代码 WebSocket-chatRoom: 基于WebSocket协议实现一个简单的…

http自动发送请求工具(自动化测试http请求)

点击下载《http自动发送请求工具(自动化测试http请求)》 前言 在现代软件开发过程中&#xff0c;HTTP 请求的自动化测试是确保应用程序稳定性和可靠性的关键环节。为了满足这一需求&#xff0c;我开发了一款功能强大且易于使用的自动化 HTTP 请求发送工具。该工具基于 C# 开发…

【小白可懂】微信小程序---课表渲染

结果展示&#xff1a;&#xff08;代码在最后&#xff09; WeChat_20241116174431 项目简介 在数字化校园建设的大背景下&#xff0c;为了更好地服务于在校师生&#xff0c;我们开发了一款基于微信小程序的课表管理系统。该系统采用了现代化的前端技术和优雅的设计风格&#x…

WinDefender Weaker

PPL Windows Vista / Server 2008引入 了受保护进程的概念&#xff0c;其目的不是保护您的数据或凭据。其最初目标是保护媒体内容并符合DRM &#xff08;数字版权管理&#xff09;要求。Microsoft开发了此机制&#xff0c;以便您的媒体播放器可以读取例如蓝光&#xff0c;同时…

LabVIEW前面板最大化显示与像素偏差分析 有源程序附件

LabVIEW前面板最大化显示与像素偏差分析 有源程序附件 LabVIEW前面板最大化显示与像素偏差分析 有源程序附件 - 北京瀚文网星科技有限公司 这个VI用于将LabVIEW程序的前面板最大化地显示在指定显示器上&#xff0c;实现步骤如下&#xff1a; 1. 获取所有显示器的信息 首先&…

【C++】深入理解 C++ 优先级队列、容器适配器与 deque:实现与应用解析

个人主页: 起名字真南的CSDN博客 个人专栏: 【数据结构初阶】 &#x1f4d8; 基础数据结构【C语言】 &#x1f4bb; C语言编程技巧【C】 &#x1f680; 进阶C【OJ题解】 &#x1f4dd; 题解精讲 目录 前言&#x1f4cc; 1. 优先级队列、容器适配器和 deque 概述✨1.1 什么是优…

LogViewer NLog, Log4Net, Log4j 文本日志可视化

LogViewer 下载 示例&#xff1a;NLog文本日志可视化软件&#xff0c;并且能够实时监听输出最新的日志 nlog.config 通过udp方式传输给LogViewer (udp://ip:port) <?xml version"1.0" encoding"utf-8" ?> <nlog xmlns"http://www.nlog-…