问题背景

加压测试过程中发现插入数据过程中报错:could not write to hash-join temporary file: 设备上没有空间。但是查看服务器还有很多空闲空间,是什么导致这样的错误呢?

查看执行脚本

insert into db_zjgj.result_rule_cwjbxx_db_sacw_t_cw_cwjbxx 
select db_zjgj.uuid(),c_bh,'2E810338E4F2CEE0462E9A021A0E0816','财物-财物处置信息中,非先行处置类的处置信息,处置日期不能小于裁判生效日期','7B7DCB103239F5CBAB4106016DE258D1'
from db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx  where EXISTS (
SELECT
1
FROM
db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx
WHERE
db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh = db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_bh
AND db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx.d_czsj IS NOT NULL
)
AND EXISTS (
SELECT
1
FROM
db_zjgj.temp_ajjbxx_db_sacw_t_aj_ajjbxx AS ajjbxx
WHERE
db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh = ajjbxx.c_bh
AND ajjbxx.d_pjsxrq IS NOT NULL
)
AND EXISTS (
SELECT
1
FROM
db_zjgj.temp_ajjbxx_db_sacw_t_aj_ajjbxx AS ajjbxx,
db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx
WHERE
db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh = ajjbxx.c_bh
AND db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_bh = db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh
AND db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx.d_czsj < ajjbxx.d_pjsxrq
)
--查看执行计划
Hash Semi Join (cost=270531577.85..324240042.87 rows=113055 width=33)
Hash Cond: ((temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh)::text = (ajjbxx.c_bh)::text)
-> Hash Semi Join (cost=270527939.60..324202660.37 rows=113055 width=99)
      Hash Cond: (((temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh)::text = (temp_cwczxx_db_sacw_t_cw_cwczxx_1.c_cwbh)::text) AND ((temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh)::text = (ajjbxx_1.c_bh)::text))
      -> Hash Semi Join (cost=10073.78..43895.94 rows=225857 width=99)
            Hash Cond: ((temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_bh)::text = (temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh)::text)
            -> Seq Scan on temp_cwjbxx_db_sacw_t_cw_cwjbxx (cost=0.00..17784.08 rows=451208 width=66)
            -> Hash (cost=5485.57..5485.57 rows=225857 width=33)
                  -> Seq Scan on temp_cwczxx_db_sacw_t_cw_cwczxx (cost=0.00..5485.57 rows=225857 width=33)
                        Filter: (d_czsj IS NOT NULL)
      -> Hash (cost=169739766.32..169739766.32 rows=3771811900 width=66)
            -> Nested Loop (cost=0.00..169739766.32 rows=3771811900 width=66)
                   Join Filter: (temp_cwczxx_db_sacw_t_cw_cwczxx_1.d_czsj < ajjbxx_1.d_pjsxrq)
                  -> Seq Scan on temp_cwczxx_db_sacw_t_cw_cwczxx temp_cwczxx_db_sacw_t_cw_cwczxx_1 (cost=0.00..5485.57 rows=225857 width=41)
                  -> Materialize (cost=0.00..2870.50 rows=50100 width=41)
                        -> Seq Scan on temp_ajjbxx_db_sacw_t_aj_ajjbxx ajjbxx_1 (cost=0.00..2620.00 rows=50100 width=41)
-> Hash (cost=2620.00..2620.00 rows=50100 width=33)       -> Seq Scan on temp_ajjbxx_db_sacw_t_aj_ajjbxx ajjbxx (cost=0.00..2620.00 rows=50100 width=33)             Filter: (d_pjsxrq IS NOT NULL)

通过执行计划发现表连接使用了全表扫描以及nested loop连接。

查看表数据量和索引情况

--查看个表数据量
db_zjgj.temp_ajjbxx_db_sacw_t_aj_ajjbxx:50100
db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx:225857
db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx:451208

发现各表均无索引,且没有主键。(了解到这些表都是抽数过程中生成的,在抽数完成后均会删除)。

优化

--添加主键和逻辑外键索引
alter table db_zjgj.temp_ajjbxx_db_sacw_t_aj_ajjbxx add primary key(c_bh);
create index i_ajjbxx_d_pjsxrq on db_zjgj.temp_ajjbxx_db_sacw_t_aj_ajjbxx(d_pjsxrq);
alter table db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx add primary key(c_bh);
create index i_cwczxx_c_cwbh on db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx(c_cwbh);
create index i_cwczxx_d_czsj on db_zjgj.temp_cwczxx_db_sacw_t_cw_cwczxx(d_czsj);
alter table db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx add primary key(c_bh);
create index i_cwjbxx_c_ajbh on db_zjgj.temp_cwjbxx_db_sacw_t_cw_cwjbxx(c_ajbh);
--查看执行计划
Hash Semi Join (cost=13712.87..298118.93 rows=113055 width=33)
Hash Cond: ((temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh)::text = (ajjbxx.c_bh)::text)
-> Nested Loop Semi Join (cost=10074.62..260736.42 rows=113055 width=99)
       Join Filter: ((temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh)::text = (temp_cwczxx_db_sacw_t_cw_cwczxx_1.c_cwbh)::text)
      -> Hash Semi Join (cost=10073.78..43895.94 rows=225857 width=99)
            Hash Cond: ((temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_bh)::text = (temp_cwczxx_db_sacw_t_cw_cwczxx.c_cwbh)::text)
            -> Seq Scan on temp_cwjbxx_db_sacw_t_cw_cwjbxx (cost=0.00..17784.08 rows=451208 width=66)
            -> Hash (cost=5485.57..5485.57 rows=225857 width=33)
                  -> Seq Scan on temp_cwczxx_db_sacw_t_cw_cwczxx (cost=0.00..5485.57 rows=225857 width=33)
                        Filter: (d_czsj IS NOT NULL)
      -> Nested Loop (cost=0.83..0.95 rows=1 width=66)
             Join Filter: (temp_cwczxx_db_sacw_t_cw_cwczxx_1.d_czsj < ajjbxx_1.d_pjsxrq)
            -> Index Scan using temp_ajjbxx_db_sacw_t_aj_ajjbxx_pkey on temp_ajjbxx_db_sacw_t_aj_ajjbxx ajjbxx_1 (cost=0.41..0.45 rows=1 width=41)
                  Index Cond: ((c_bh)::text = (temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_ajbh)::text)
            -> Index Scan using i_cwczxx_c_cwbh on temp_cwczxx_db_sacw_t_cw_cwczxx temp_cwczxx_db_sacw_t_cw_cwczxx_1 (cost=0.42..0.48 rows=1 width=41)
                  Index Cond: ((c_cwbh)::text = (temp_cwjbxx_db_sacw_t_cw_cwjbxx.c_bh)::text)
-> Hash (cost=2620.00..2620.00 rows=50100 width=33)
      -> Seq Scan on temp_ajjbxx_db_sacw_t_aj_ajjbxx ajjbxx (cost=0.00..2620.00 rows=50100 width=33)
            Filter: (d_pjsxrq IS NOT NULL)

添加索引后cost降了下来,数据能够顺利插入,最终sql大概需要6s左右。

疑问

为什么查看服务器还有空闲空间,但是执行sql却报错磁盘空间不足呢。

--查看abase数据文件目录:/opt/thunisoft/abdata/3.6/abase1/base/pgsql_tmp
[thunisoft@localhost base]$ du -sh *|sort
19M pgsql_tmp
3.2G 408143
6.3G 410629
7.0M 13236
7.1M 1
7.2M 13241
7.2M 16444
--临时目录下面有许多个临时文件
[thunisoft@localhost pgsql_tmp]$ ls |wc -w
65551
--临时文件均已pg_sql_tmp23277开头
[thunisoft@localhost pgsql_tmp]$ ll
...
-rw-------. 1 thunisoft thunisoft       0 Aug 27 14:24 pgsql_tmp23277.9998
-rw-------. 1 thunisoft thunisoft       0 Aug 27 14:24 pgsql_tmp23277.9999
...

--23277标识进程号,从pg_log日志文件中可以找到该进程为当前正在执行sql

可以看出临时目录下面有许多文件,大小为0,pgsql_tmp所占用的空间为19M。

场景还原

--磁盘空间使用情况
[thunisoft@localhost base]$ df -lh
Filesystem                   Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   18G   12G  4.6G  73% /
tmpfs                         5.9G  4.8K  5.9G   1% /dev/shm
/dev/sda1                     485M   33M  427M   8% /boot

--删除刚刚所建的索引,重新执行该sql,发现pgsql_tmp会不断地增大
[thunisoft@localhost base]$ du -sh *|sort
1.6G pgsql_tmp
3.2G 408143
6.3G 410629
7.0M 13236
7.1M 1
7.2M 13241
7.2M 16444
--最终直至占满所有空间
[thunisoft@localhost base]$ df -lh
Filesystem                   Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-lv_root   18G   17G  254M  99% /
tmpfs                         5.9G  4.0K  5.9G   1% /dev/shm
/dev/sda1                     485M   33M  427M   8% /boot
--空间占满 报错后这些临时文件空间大部分被回收,但是文件还在,文件个数仍为65551
[thunisoft@localhost base]$ du -sh *|sort
19M pgsql_tmp
...
[thunisoft@localhost pgsql_tmp]$ ls |wc -w
65551

可以看出该sql执行时临时文件会不断的增大,直至占满空间报错,当sql报错后临时文件大部分被清空,磁盘空间又将得到释放,所以开始看到的磁盘空间并没有满,但是报错却是磁盘空间满了。

那些情况会生成这些临时文件

据了解查询要使用的内存超出work_mem的大小时(包括排序,DISTINCT,MERGE JOIN,HASH JOIN,笛卡尔积,哈希聚合,分组聚合,递归查询)等操作时会使用临时文件来存储中间过程的数据。如果频繁的进行上述操作,临时文件将会快速增长。只有重启能够解决该问题,重启后将清空所有临时文件。

--查询使用临时文件相关
--1.每个进程临时文件空间的限制,如果超过改值,查询将取消,默认无限制
#temp_file_limit = -1                   # limits per-process temp file space  
                                      # in kB, or -1 for no limit
--2.当临时文件使用量大于设置阈值时,记录日志,默认不记录
#log_temp_files = -1                   # log temporary files equal or larger  
                                      # than the specified size in kilobytes;
# -1 disables, 0 logs all temp files
--3.当超过work_mem时使用临时文件                                      
#work_mem (integer)

结语

1.回到最开始的sql,这些临时表可以在数据插入表后建立索引,然后再执行最后的抽数,这样效率会高一点,嵌套循环耗费cpu,磁盘io,以及临时文件占用高

2.abase为了提高执行效率一些操作会使用内存代替临时存储,当内存不足时就会使用临时文件存储中间数据。

3.可酌情设置temp_file_limit 为磁盘空间的10%,当临时文件占用磁盘过高,自动取消该查询,记录查询语句

4.一般查询如果耗费大量的临时文件,有可能是没有索引导致

postgresql-磁盘空间不足问题排查的更多相关文章

  1. Linux磁盘空间满了的排查与解决思路

    block正常满 (磁盘实际不足)inode 满 大量的小文件block 满 文件没有被彻底删除(硬链接数0 进程调用数不为0) 解放方法: 1 查看df -h 磁盘使用量根据占用量大小逐步逐步排查 ...

  2. linux 磁盘空间满了,排查记录

    先贴命令:du -m --max-depth=1或du -h --max-depth=1du:用于统计linux中文件或目录所占磁盘空间的大小du参数######-m:以M为单位展示查询结果-h:以K ...

  3. How to get the free disk space in PostgreSQL (PostgreSQL获取磁盘空间)

    Get the current free disk space in PostgreSQL PostgreSQL获取磁盘空间 from eshizhan Here has a simple way t ...

  4. linux硬件资源问题排查:cpu负载、内存使用情况、磁盘空间、磁盘IO

    在使用过程中之前正常的功能,突然无法使用,性能变慢,通常都是资源消耗问题,资源消耗可以从以下几个方面去排查.对于已经安装硬件资源监控软件(zabbix)的环境,直接使用硬件资源监控软件(zabbix) ...

  5. 云服务器 ECS Linux 磁盘空间满(含 innode 满)问题排查方法

    问题描述 在云服务器 ECS Linux 系统内创建文件时,出现类似如下空间不足提示: No space left on device … 问题原因 导致该问题的可能原因包括: 磁盘分区空间使用率达到 ...

  6. PostgreSQL表空间、模式、表、用户/角色之间的关系

    PostgreSQL表空间.模式.表.用户/角色之间的关系是本文我们主要要介绍的内容,表空间,数据库,模式,表,用户,角色之间的关系到底是怎样的呢?接下来我们就开始介绍这一过程. 实验出角色与用户的关 ...

  7. linux磁盘空间用满的处理方法

    linux下空间满可能有两种情况 可以通过命令 df -h  查看磁盘空间占用,实际上是查看磁盘块占用的文件(block) df -i  查看索引节点的占用(Inodes) 磁盘块和索引节点其中之一满 ...

  8. linux命令----查看磁盘空间

    今天用“web发布平台”发布测试的服务,两个节点中发现有一个节点没有发布成功,压测TPS始终上不去,排查后发现只有一个节点在打日志,另一个节点的服务进程都没有在运行,由此断定应该是没有发布成功,有点坑 ...

  9. jenkins log文件突然占满磁盘空间

    今天早上同事反应jenkins构建job发生异常,于是登录机器查看发现磁盘空间已满.进一步排查之后发现jenkins的catalina.out文件已占满磁盘空间. 用tail看了下日志后面都是关于DN ...

  10. linux磁盘空间占满问题快速定位并解决

    经常会遇到这样的场景:测试环境磁盘跑满了,导致系统不能正常运行!此时就需要查看是哪个目录或者文件占用了空间.常使用如下几个命令进行排查:df, lsof,du. 通常的解决步骤如下:1. df -h ...

随机推荐

  1. VirtualBox 安装Mac OS

    2019年3月2日14:17:27 今日打开自己的Virtual box提示 被召者 RC: REGDB_E_CLASSNOTREG (0x80040154) https://blog.csdn.ne ...

  2. toastr简单用法及修改垂直居中

    toastr是一个基于Jquery简单.漂亮的消息提示插件,使用简单.方便,可以根据设置的超时时间自动消失. 1.使用很简单,首选引入toastr的js.css文件html <script sr ...

  3. React createRef:引用

    一 代码 import React, { Component } from 'react'; class Box extends Component { render() { return <b ...

  4. FortiGate上架前准备

    1.收集信息 1.网络拓扑信息(了解网络拓扑信息有助于网络方案的规划) 2.环境信息(了解部署位置.部署模式.最大吞吐.最大用户数有助于对设备性能的评估) 3.客户需求,对FortiGate部署的功能 ...

  5. Springboot学习04-默认错误页面加载机制源码分析

    Springboot学习04-默认错误页面加载机制源码分析 前沿 希望通过本文的学习,对错误页面的加载机制有这更神的理解 正文 1-Springboot错误页面展示 2-Springboot默认错误处 ...

  6. [leetcode]77. Combinations组合

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. Example: I ...

  7. CentOS No package nginx available.

    CentOS No package nginx available. yum install epel-release 如果不行 https://blog.csdn.net/u012965373/ar ...

  8. CentOS Linux下VNC Server远程桌面配置详解

    http://www.ha97.com/4634.html PS:偶以前基本不用Linux的远程图形桌面,前几天有开发的同事配置CentOS的vnc有问题,找我解决,就顺便记录总结一下,这个总结是比较 ...

  9. NC 6系总账凭证联查原始单据

    单据联查凭证可以找个如收款结算单的仿写一个. 而总账凭证联查单据则需要实现联查单据的类,重新写一个类.并把类注册进数据库. 最终效果: public class QuerySellcarryBillS ...

  10. ABP框架系列之二十:(Dependency-Injection-依赖注入)

    What is Dependency Injection If you already know Dependency Injection concept, Constructor and Prope ...