postgresql-디스크 공간 부족 문제 탐색

22110 단어
문제 배경
가압 테스트 중 데이터 삽입 중 오류 발견: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, pgsqltmp가 차지하는 공간은 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. 일반적인 조회는 대량의 임시 파일을 소모하면 인덱스가 없어서
전재 대상:https://www.cnblogs.com/zhangfx01/p/10563558.html

좋은 웹페이지 즐겨찾기