【一起oracle_fdw未下推导致PostgreSQL异常关闭的问题分析】

news/2024/7/9 20:34:54 标签: 数据库, postgresql

最近的一套PostgreSQL(12.6)数据库在进行UAT测试的时候,发现服务器空间爆满,导致了PostgreSQL异常关闭。问题发生后,现场的DBA让我配合做了如下的一些分析,这里去除敏感信息,分享给大家。

一、问题分析

问题发生的时候,现场的DBA其实经过检查发现了暴涨的源头是这个pgsql_tmp目录, 

而且现场的DBA在PostgreSQL异常关闭前,用strings去看pgsql_temp里面的文件,确认是对应的数据,而且根据文件的命名方式,通过pid查询到了产生临时文件的SQL,SQL是一个select语句,并且涉及到fdw远程表,这方便了我们后续对问题的分析。

 select * from pg_stat_activity where pid='24518';

通过查看这个SQL的执行计划,我们可以看到有两个sort环节,而且都是在PostgreSQL端执行的。

然后看一下涉及的sort列的表的情况,发现这几列都是字符类型的。要知道oracle_fdw的排序字段是字符类型的时候是不会不下推到oracle端的,但是数字和时间类型都是可以的,因此这个SQL的排序他会先把数据拿到PostgreSQL的内存里,即work_mem里去做这个sort操作。

下推:FDW采用一种称为 pushdown 的机制,它允许远程端执行 WHERE、ORDER BY 和 JOIN 子句。下推 WHERE 和 JOIN 减少了本地和远程服务器之间传输的数据量,避免了网络通信瓶颈。


到这里,我和现场DBA确认了下他们work_mem的大小,经过确认,他们work_mem的值为4MB,也就是默认值,对于这个SQL来说,work_mem明显太小了,这个参数是写入临时文件之前内部排序操作和散列表使用的内存量,超出后,就会溢出到磁盘写到pgsql_tmp下的临时文件里,当开始将临时文件写入磁盘时,显然会比内存慢得多,而且临时文件的太大也可能把空间填满。

其实可以在启用log_temp_files后,在PostgreSQL日志中搜索temporary file来查看是否溢出到了磁盘。如果看到了temporary file,就意味着可能需要增加work_mem了。
而且不容忽视的一点是:work_mem这个参数和max_connection是有联系的,假设你设置为10MB,则500个用户同时执行查询排序,很快就会使用5GB的实际内存。或者涉及复杂计算,涉及几张表的合并,就要用到几倍的work_mem。因此work_mem是不适宜设置的很大的,如果设置超出256MB,其实很容易因为瞬间的大并发操作导致OOM问题

此外,其实可以通过使用explain analyze 这个SQL去查看这个它执行所需要的内存大小,但生产的环境基本不允许我们随意explain analyze,因为它会实际执行SQL,如果是问题SQL,不仅可能影响数据库性能、严重甚至造成宕机。而且explain analyze命令跟insert、update、delete的操作更是会修改数据,这是我们绝对不能做的。

下边我在自己的测试环境给大家演示一下,work_mem对于执行计划的影响,我原本的work_mem值也是4MB没有修改:

可以看到,这个SQL的执行计划里,Sort Method部分是external merge Disk,代表了外部合并磁盘,也就是溢出到了磁盘,生成了临时文件。可以看到这个SQL的执行计划里Disk:25864KB,大概有25MB,那我work_mem的值改成128MB,会怎样呢 ,如下所示,相同的SQL,Sort Method部分变成了quicksort Memory ,此时sort的数据都是放在内存里的,而没有溢出磁盘。

二、结论

通过上面的分析,我们知道这次的问题,主要是出在了oracle_fdw处理SQL的sort操作的的时候字符类型不能下推,而且在PostgreSQL本地进行sort的时候,超出了work_mem的设置,导致溢出到磁盘,我们可以把work_mem的值稍微提升一点,但一定不要过大,否则业务的瞬间高并发很可能导致OOM。而且对于work_mem的大小我们肯定是要根据平时的业务以及并发量来综合评估的,基本确定了一个值不会去轻易改动,不能对于个别SQL进行调整,这样也不利于数据库的稳定性。因此,最好的方式还是结合业务看是否这条SQL能进行调整,修改sort的列的类型,或者调整写法让其能下推到oracle端执行,减少传输到PostgreSQL本地的数据量。除此之外我们也可以使用temp_file_limit这个参数对此类临时文件的大小做一个限制,避免数据目录的爆满。


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

相关文章

vue 动态数据 双层循环数据 点击事件错位

问题描述 点击id为1 的ItemA 却跳转到id为2的itemB。 问题解决 内层循环的key使用id&#xff0c;而不是index。此时的index无法区分开数据 <view class"item_j hand" v-for"(itemJ,index) in item.children" :key"itemJ.id" click"g…

C语言高级教程-C语言数组(五):二维(多维)数组初始化和基于数组的综合实例->帽子选购问题

C语言高级教程-C语言数组&#xff08;五&#xff09;&#xff1a;二维&#xff08;多维&#xff09;数组初始化和基于数组的综合实例->帽子选购问题一、本文的编译环境二、二维数组的初始化三、三维数组的初始化四、使用for循环求三维数组元素值的和4.1、for循环求数组元素值…

二叉树遍历原理 | 深度优先-广度优先 | 栈-队列

&#x1f497;wei_shuo的个人主页 &#x1f4ab;wei_shuo的学习社区 &#x1f310;Hello World &#xff01; 14天阅读挑战赛 文章目录二叉树遍历原理队列和栈区别深度优先遍历(DFS)前序遍历(根-左-右)中序遍历(左-根-右)后序遍历(左-右-根)广度优先遍历(BFS)逐层遍历(上-下 | …

git 远程分支与本地分支

前言 远程仓库上只有 1 个 master 分支。 复制远程仓库的地址。 3. 克隆远程仓库到本地。 一、 注意&#xff1a;本地的 head 和 master 文件都存在&#xff0c;但是 remote 的 master 信息是保存在文件 .git/packed-refs 中。 可以看到&#xff0c;当前 HEAD 指针指向本地仓…

驱动进化之路:设备树的引入及简明教程

驱动进化之路&#xff1a;设备树的引入及简明教程 设备树的基本概念和产生背景 问题1&#xff1a; 以LED为例&#xff0c;当要更换LED所用的GPIO引脚时&#xff0c;需要修改驱动程序源码&#xff0c;重新编译驱动&#xff0c;重新加载驱动。 问题2&#xff1a; 由于芯片种类繁…

Spring项目的创建和使用-----实现代码解耦和自动化(直接用bean)

1.Spring框架的发展史 1)最早的Spring项目:2018年的老框架Spring框架&#xff0c;基于maven项目&#xff0c;这种Spring运行方式没有比Servlet有很大的优势(不明显)&#xff0c;是需要用到Tomact来进行运行&#xff0c;也是需要到官方找jar包&#xff0c;引入依赖到pom.xml里面…

[做初中数学题做到打起来了]跟同事为了他小孩的数学题杠上了

目录1.前情提要2.蒙特卡洛方法3.尾声1.前情提要 这是2019年 NGA 论坛上的一个帖子&#xff1a; 帖子中提出了一个问题&#xff1a;4只小鸭子在一个大的圆形水池中&#xff0c;分别随机的出现在圆圈中的任意一点。4只鸭子出现在同一个半圆内的概率是多少? 这个问题当时分歧很大…

“购物返现积分兑换”——区块链思维的购物返利方式

商业运营模式只是一个让商家提高销售额的一种手段&#xff0c;不管线上还是线下都是一样的。 例如&#xff1a;买二送一、转介绍购优惠、新人促销价这些&#xff0c;这都是非常普遍的的营销商业运营模式&#xff0c;大部分每一个线下推广实体线店家都有用&#xff0c;这也是线…