聊聊PostgreSql table和磁盘文件的映射关系

在postgresql中 Drop table会不会释放磁盘空间,今日以实操来见证

--2019-01-11 09:49:21 drop table 会不会释放空间
 create table tab_todrop(id int,cname varchar(50),remark text);
 insert into tab_todrop select generate_series(1,10000000),'wx good boy',md5('wx good boy');
 insert into tab_todrop select generate_series(1,10000000),'wx good boy',md5('wx good boy');
--查看表大小
qmstst=# select pg_size_pretty(pg_relation_size('tab_todrop'));
 pg_size_pretty
----------------
 2410 MB
(1 row)
qmstst=#

每张数据表放在datap*下。postgresql集群是通过hash分布到dataap*这种文件下。

[root@P1QMSTST01 ~]# df -h
Filesystem   Size Used Avail Use% Mounted on
/dev/mapper/rootvg-rootlv
      35G 4.8G 28G 15% /
tmpfs     63G  0 63G 0% /dev/shm
/dev/sda2    477M 33M 419M 8% /boot
/dev/sda1    500M 272K 500M 1% /boot/efi
/dev/mapper/rootvg-homelv
      4.8G 1.6G 3.1G 34% /home
/dev/mapper/rootvg-optlv
      20G 8.4G 11G 46% /opt
/dev/mapper/rootvg-tmplv
      4.8G 402M 4.2G 9% /tmp
/dev/mapper/rootvg-usrlv
      9.8G 3.6G 5.8G 39% /usr
/dev/mapper/rootvg-locallv
      52G 25G 25G 51% /usr/local
/dev/mapper/rootvg-varlv
      15G 5.2G 8.8G 37% /var
/dev/mapper/datavg-gpmasterlv
      100G 50G 51G 50% /gpmaster
/dev/mapper/datavg-datap1lv
      150G 43G 108G 29% /datap1
/dev/mapper/datavg-datap2lv
      150G 42G 109G 28% /datap2
/dev/mapper/datavg-datap3lv
      150G 42G 109G 28% /datap3
/dev/mapper/datavg-datap4lv
      150G 42G 109G 28% /datap4
/dev/mapper/datavg-datap5lv
      150G 43G 108G 29% /datap5
/dev/mapper/datavg-datap6lv
      150G 42G 108G 28% /datap6
/dev/mapper/rootvg-redislv

在dataap*下的base目录下存储的是数据表

select
relname, --表/视图/索引等的名字
relowner, --关系所有者
relfilenode --这个关系在磁盘上的文件的名称,如果没有则为0
from pg_class
where relname = 'tab_todrop';
qmstst=# select relname, relowner, relfilenode from pg_class where relname = 'tab_todrop';
 relname | relowner | relfilenode
------------+----------+-------------
 tab_todrop | 17088 | 15997062
(1 row)

ls -lh 17089/15997006*
-rw------- 1 gpadmin gpadmin 268M Jan 11 13:56 17089/15997006
[root@P1QMSTST01 base]# pwd
/datap2/gpseg1/base
[root@P1QMSTST01 base]#

drop table 后,base目录下的该文件就被删除了,因此可以断定 “在postgresql中drop table会释放空间”

补充:postgresql 的table、index物理存储

postgresql 是使用文件系统存储数据的,有时需要找表及索引对应的磁盘文件,就必须了解以下知识点。

非toast情况

zabbix=# create table tmp_t0(c0 varchar(100),c1 varchar(100), c2 varchar(100));
CREATE TABLE
zabbix=#
zabbix=# create index idx_tmp_t0 on tmp_t0(c0);
CREATE INDEX
zabbix=#
zabbix=# insert into tmp_t0 select id::varchar,md5(id::varchar),md5(md5(id::varchar)) from generate_series(1,100000) as id ;
INSERT 0 100000
zabbix=#
zabbix=# delete from tmp_t0 where c0 > '1';
DELETE 99999

查看表对应的操作系统文件.

zabbix=# select pg_relation_filenode('tmp_t0'),pg_relation_filepath('tmp_t0');
 pg_relation_filenode | pg_relation_filepath
----------------------+----------------------
  24583 | base/24579/24583
(1 row)

查看索引对应的操作系统文件.

zabbix=# select pg_relation_filenode('idx_tmp_t0'),pg_relation_filepath('idx_tmp_t0');
 pg_relation_filenode | pg_relation_filepath
----------------------+----------------------
  24588 | base/24579/24588
(1 row)

使用 pg_class 查看

zabbix=# select pc.oid,pc.relname,pc.relfilenode from pg_class pc where 1=1 and pc.relname in ('tmp_t0','idx_tmp_t0');
 oid | relname | relfilenode
-------+------------+-------------
 24583 | tmp_t0 | 24583
 24588 | idx_tmp_t0 | 24588
(2 rows)

操作系统查看

$ ls -l |grep -i 24583; ls -l |grep -i 24588;
-rw------- 1 postgres postgres 10117120 Sep 19 11:18 24583
-rw------- 1 postgres postgres 24576 Sep 19 11:18 24583_fsm
-rw------- 1 postgres postgres 8192 Sep 19 11:20 24583_vm
-rw------- 1 postgres postgres 2260992 Sep 19 11:25 24588

这个时候做个truncate操作

zabbix=# truncate table tmp_t0;
TRUNCATE table
zabbix=#
zabbix=# insert into tmp_t0 select id::varchar,md5(id::varchar),md5(md5(id::varchar)) from generate_series(1,100000) as id ;
INSERT 0 100000

依次查看

zabbix=# select pg_relation_filenode('tmp_t0'),pg_relation_filepath('tmp_t0');
 pg_relation_filenode | pg_relation_filepath
----------------------+----------------------
  24589 | base/24579/24589
(1 row)

zabbix=# select pg_relation_filenode('idx_tmp_t0'),pg_relation_filepath('idx_tmp_t0');
 pg_relation_filenode | pg_relation_filepath
----------------------+----------------------
  24590 | base/24579/24590
(1 row)
zabbix=# select pc.oid,pc.relname,pc.relfilenode from pg_class pc where 1=1 and pc.relname in ('tmp_t0','idx_tmp_t0');
 oid | relname | relfilenode
-------+------------+-------------
 24583 | tmp_t0 | 24589
 24588 | idx_tmp_t0 | 24590
(2 rows)

$ ls -l |grep -i 24583; ls -l |grep -i 24588;
-rw------- 1 postgres postgres 0 Sep 19 11:33 24583
-rw------- 1 postgres postgres 0 Sep 19 11:33 24588
$ ls -l |grep -i 24589; ls -l |grep -i 24590;
-rw------- 1 postgres postgres 10117120 Sep 19 11:35 24589
-rw------- 1 postgres postgres 24576 Sep 19 11:35 24589_fsm
-rw------- 1 postgres postgres 3932160 Sep 19 11:35 24590

之后再查看 old relfilenode 时已经消失不见了

$ ls -l |grep -i 24583; ls -l |grep -i 24588;
$ 

总结如下:

1、create table、create index 时,pg_class 的 oid 与 relfilenode 相同。

1、truncate table 后,table与index的oid均没有发生变化,但是 relfilenode 发生了变化。

toast 情况

插入4千万行数据,让tmp_t0在磁盘的大小大于1G

zabbix=# insert into tmp_t0 select id::varchar,md5(id::varchar),md5(md5(id::varchar)) from generate_series(1,40000000) as id ;
INSERT 0 40000000
zabbix=#
zabbix=# create index idx_tmp_t0_1 on tmp_t0(c1);
CREATE index
zabbix=# select pc.oid,pc.relname,pc.relfilenode from pg_class pc where 1=1 and pc.relname in ('tmp_t0','idx_tmp_t0','idx_tmp_t0_1');
 oid | relname | relfilenode
-------+--------------+-------------
 24583 | tmp_t0 | 24589
 24588 | idx_tmp_t0 | 24590
 24599 | idx_tmp_t0_1 | 24599
(3 rows)
$ ls -l |grep -i 24589; ls -l |grep -i 24590;ls -l|grep -i 24599;
-rw------- 1 postgres postgres 1073741824 Sep 19 12:15 24589
-rw------- 1 postgres postgres 1073741824 Sep 19 12:17 24589.1
-rw------- 1 postgres postgres 1073741824 Sep 19 12:19 24589.2
-rw------- 1 postgres postgres 1073741824 Sep 19 12:23 24589.3
-rw------- 1 postgres postgres 81788928 Sep 19 12:25 24589.4
-rw------- 1 postgres postgres 1097728 Sep 19 12:14 24589_fsm
-rw------- 1 postgres postgres 1073741824 Sep 19 12:14 24590
-rw------- 1 postgres postgres 332496896 Sep 19 12:14 24590.1
-rw------- 1 postgres postgres 1073741824 Sep 19 12:24 24599
-rw------- 1 postgres postgres 1073741824 Sep 19 12:24 24599.1
-rw------- 1 postgres postgres 220487680 Sep 19 12:24 24599.2

下面是查看表及索引对应的存储文件

select pt.schemaname||'.'||pt.tablename,pg_relation_filepath(pt.schemaname||'.'||pt.tablename),
 pg_table_size(pt.schemaname||'.'||pt.tablename),
 pg_relation_size(pt.schemaname||'.'||pt.tablename),
 pg_total_relation_size(pt.schemaname||'.'||pt.tablename),
 pi.schemaname||'.'||pi.indexname,pg_relation_filepath(pi.schemaname||'.'||pi.indexname),
 pg_relation_size(pi.schemaname||'.'||pi.indexname),--指定的单个索引
 pg_indexes_size(pi.schemaname||'.'||pi.tablename) --表上的所有索引
 from pg_tables pt
 left outer join pg_indexes pi
   on pt.schemaname||'.'||pt.tablename = pi.schemaname||'.'||pi.tablename
where 1=1
 and pt.schemaname='public'
 and pt.tablename='tmp_t0'
;

 ?column? | pg_relation_filepath | pg_table_size | pg_relation_size | pg_total_relation_size | ?column? | pg_relation_filepath | pg_relation_size | pg_indexes_size
---------------+----------------------+---------------+------------------+------------------------+---------------------+----------------------+------------------+-----------------
 public.tmp_t0 | base/24579/24589 | 4377853952 | 4376756224 |  8152064000 | public.idx_tmp_t0 | base/24579/24590 | 1406238720 | 3774210048
 public.tmp_t0 | base/24579/24589 | 4377853952 | 4376756224 |  8152064000 | public.idx_tmp_t0_1 | base/24579/24599 | 2367971328 | 3774210048
(2 rows)

参考文档:

表 9-83. 数据库对象尺寸函数

名称      返回类型  描述
pg_column_size(any)  int 存储一个特定值(可能压缩过)所需的字节数
pg_database_size(oid)    bigint 指定 OID 的数据库使用的磁盘空间
pg_database_size(name)    bigint 指定名称的数据库使用的磁盘空间
pg_indexes_size(regclass)   bigint 附加到指定表的索引所占的总磁盘空间
pg_relation_size(relation regclass, fork text) bigint 指定表或索引的指定分叉('main'、'fsm'、'vm'或'init')使用的磁盘空间
pg_relation_size(relation regclass)  bigint pg_relation_size(..., 'main')的简写
pg_size_bytes(text)    bigint 把人类可读格式的带有单位的尺寸转换成字节数
pg_size_pretty(bigint)    text  将表示成一个 64位整数的字节尺寸转换为带尺寸单位的人类可读格式
pg_size_pretty(numeric)   text  将表示成一个数字值的字节尺寸转换为带尺寸单位的人类可读格式
pg_table_size(regclass)   bigint 被指定表使用的磁盘空间,排除索引(但包括 TOAST、空闲空间映射和可见性映射)
pg_tablespace_size(oid)   bigint 指定 OID 的表空间使用的磁盘空间
pg_tablespace_size(name)   bigint 指定名称的表空间使用的磁盘空间
pg_total_relation_size(regclass)  bigint 指定表所用的总磁盘空间,包括所有的索引和TOAST数据

pg_column_size 显示用于存储任意独立数据值的空间。

pg_total_relation_size 接受一个表或 TOAST 表的 OID 或名称,并返回该表所使用的总磁盘空间,包括所有相关的索引。这个函数等价于pg_table_size + pg_indexes_size。

pg_table_size 接受一个表的 OID 或名称,并返回该表所需的磁盘空间,但是排除索引(TOAST 空间、空闲空间映射和可见性映射包含在内)

pg_indexes_size 接受一个表的 OID 或名称,并返回附加到该表的所有索引所使用的全部磁盘空间。

pg_database_size 和 pg_tablespace_size 接受一个数据库或表空间的 OID 或名称,并且返回它们所使用的全部磁盘空间。 要使用pg_database_size,你必须具有在指定数据库上的 CONNECT权限(默认会被授予)。要使用pg_tablespace_size, 你必须具有指定表空间上的CREATE权限,除非它是当前数据库的默认表空间。

pg_relation_size 接受一个表、索引或 TOAST 表的 OID 或者名称, 并且返回那个关系的一个分叉所占的磁盘空间的字节尺寸(注意对于大部分目的, 使用更高层的函数pg_total_relation_size或者pg_table_size 会更方便,它们会合计所有分叉的尺寸)。 如果只得到一个参数, 它会返回该关系的主数据分叉的尺寸。提供第二个参数可以指定要检查哪个分叉:

'main'返回该关系主数据分叉的尺寸。

'fsm'返回与该关系相关的空闲空间映射 (见第 65.3 节)的尺寸。

'vm'返回与该关系相关的可见性映射 (见第 65.4 节)的尺寸。

'init'返回与该关系相关的初始化分叉(如果有)的尺寸。

pg_size_pretty 可以用于把其它函数之一的结果格式化成一种人类易读的格式,可以根据情况使用 KB、MB、GB 或者 TB。

pg_size_bytes 可以被用来从人类可读格式的字符串得到其中所表示的字节数。 其输入可能带有的单位包括字节、kB、MB、GB 或者 TB, 并且对输入进行解析时是区分大小写的。如果没有指定单位,会假定单位为字节。

注意:

函数 pg_size_pretty 和 pg_size_bytes 所使用的单位 kB、MB、GB 和 TB 是用 2 的幂而不是 10 的幂来定义,因此 1kB 是 1024 字节, 1MB 是10242 = 1048576字节,以此类推

上述操作表和索引的函数接受一个 regclass 参数,它是该表或索引在 pg_class系统目录中的 OID。你不必手工去查找该 OID,因为 regclass数据类型的输入转换器会为你代劳。只写包围在单引号内的表名, 这样它看起来像一个文字常量。为了与普通SQL名称的处理相兼容, 该字符串将被转换为小写形式,除非其中在表名周围包含双引号。

如果一个 OID 不表示一个已有的对象并且被作为参数传递给了上述函数, 将会返回 NULL。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。如有错误或未考虑完全的地方,望不吝赐教。

(0)

相关推荐

  • 解决PostgreSQL日志信息占用磁盘过大的问题

    当PostgreSQL启用日志时,若postgresql.conf日志的相关参数还使用默认值的话磁盘很容易被撑爆.因此在启用了logging_collector参数时,需要对其它相关的参数进行调整. 系统默认参数如下 #log_destination = 'stderr' #日志格式,值为stderr, csvlog, syslog, and eventlog之一. logging_collector = on #启用日志 #log_directory = 'log' #日志文件存储目录 #lo

  • 基于PostgreSql 别名区分大小写的问题

    PostgreSql是区分大小写的 如果别名的大小不一致就会提示错误: SELECT * FROM ( SELECT cpi."product_item_id" "PRODUCT_ITEM_ID" FROM prd.up_product_item cpi ) a WHERE a.PRODUCT_ITEM_ID=1 一个很简单的子查询,但是会出错,虽然从语句上看大小写是一致的,但是内部查询中还是使用了小写.PostgreSql对于大写都需要加上双引号的,不然还是视作小

  • postgresql~*符号的含义及用法说明

    操作符 ~~ 等效于 LIKE, 而 ~~* 对应 ILIKE. 还有 !~~ 和 !~~* 操作符 分别代表 NOT LIKE 和 NOT ILIKE. 另外: ~ 匹配正则表达式,大小写相关 'thomas' ~ '.*thomas.*' ~*搜索 匹配正则表达式,大小写无关 'thomas' ~* '.*Thomas.*' !~ 不匹配正则表达式,大小写相关 'thomas' !~ '.*Thomas.*' !~* 不匹配正则表达式,大小写无关 'thomas' !~* '.*vadim.

  • 解析PostgreSQL中Oid和Relfilenode的映射问题

    作者李传成 中国PG分会认证专家,瀚高软件资深内核研发工程师 https://zhuanlan.zhihu.com/p/342466054 PostgreSQL中的表会有一个RelFileNode值指定这个表在磁盘上的文件名(外部表.分区表除外).一般情况下在pg_class表的relfilenode字段可以查出这个值,但是有一些特定表在relfilenode字段的查询结果是0,这个博客中将会探究这些特殊表relfilenode的内核处理. 正常表的Relfilenode 当我们创建一张普通表时

  • Postgresql 数据库转义字符操作

    产生问题 Postgresql数据库运行下面insert命令 insert into mapping_mac_brand(_id,mac,brand) values(777,'D86595','Toy\'s Myth Inc.') 提示下面的警告: Warning: nonstandard use of \' in a string literal HINT: Use '' to write quotes in strings or use the escape string syntax(E.

  • 聊聊PostgreSql table和磁盘文件的映射关系

    在postgresql中 Drop table会不会释放磁盘空间,今日以实操来见证 --2019-01-11 09:49:21 drop table 会不会释放空间 create table tab_todrop(id int,cname varchar(50),remark text); insert into tab_todrop select generate_series(1,10000000),'wx good boy',md5('wx good boy'); insert into

  • 浅谈hibernate中多表映射关系配置

    1.one-to-many 一对多关系的映射配置(在一的一方实体映射文件中配置) <!-- cascade属性:级联操作属性 save-update: 级联保存,保存客户时,级联保存客户关联的联系人 delete:级联删除,删除客户时,级联删除客户关联的联系人 all:级联保存+级联删除 --> <!-- inverse属性:设置是否不维护关联关系 true:不维护关联 false(默认值):维护关联 --> <!-- 一对多 --> <set name=&quo

  • Hibernate使用hbm.xml配置映射关系解析

    在使用hibernate时,经常需要配置与类对应的hbm.xml文件,并在其中指明数据库表的具体细节. 由于映射关系的配置比较繁琐,故总结了模板代码如下: 多对一: <many-to-one name="本类中的属性名" class="对方类" column="本类中的属性名+Id"></many-to-one> 一对多: <set name="本类中的属性名"> <key colum

  • MyBatis映射关系详解

    目录 数据库的配置 一.映射关系一对一 1.映射关系 1 对 1-基本介绍 2.映射关系 1 对 1-映射方式 3.应用实例 3.1方式一 方式二: 通过配置 XxxMapper.xml 的方式来实现下面的 1 对 1 的映射关系,实现级 联查询 , 通过 person 可以获取到对应的 identcard 信息 重点解析: 注解的方式实现 通过注解的方式来实现下面的 1 对 1 的映射关系,实现级联查询 , 通过 person 可以获取到 对应的 identcard 信息 在实际开发中还是 推

  • Java中具有映射关系的容器:数组和Map的区别说明

    映射就意味着有两部分: 存储映射关系的容器是数组和Map集合: 区别: (1)当映射关系中的一方是有序编号时,这个时候要想到数组这种结构: (2)Map不一定需要有序编号,它只能建立对象之间的关系: (3)如果映射的两方没有任何一方是有序的编号,就不能想数组了,这时应该用集合中具备映射关系的容器Map. 注意: (1)Map中键相同时,键值会被覆盖: (2)Map中一个Key可以对应一个集合,因为集合也是一个对象,集合也能往集合中放. (3)Map<int,char>这样写是不正确的,因为,泛

  • Mybatis如何使用@Mapper和@MapperScan注解实现映射关系

    目录 使用@Mapper和@MapperScan注解实现映射关系 Mybatis-@MapperScan和mybatis:scan分析 <mybatis:scan> MapperScan 使用@Mapper和@MapperScan注解实现映射关系 MyBatis与Spring整合后需要实现实体和数据表的映射关系. 实现实体和数据表的映射关系可以在Mapper类上添加@Mapper注解,如下代码: /** * 用户信息Mapper动态代理接口 * @author pan_junbiao **/

  • mybatisPlus 实体类与数据库表映射关系详解

    目录 实体类与数据库表映射关系 具体的映射方法有两种 忽略某个实体类属性和数据库表字段之间的映射关系 问题描述 解决方案 实体类与数据库表映射关系 使用mybatisPlus时,会确定实体类和数据的映射关系 具体的映射方法有两种 1.默认:采用驼峰映射规则 例如MyUserTable 对应的数据库表为 my_user_table ;  TEMyUserTable 对应表名为t_e_my_user_table; 2.注解@TableName   在类名上方添加@TableName("my_user

  • Mybatis全局配置及映射关系的实现

    目录 一.配置文件内容 1.1.Proerties 1.2.设置setting 1.3.类型别名typeAliases 1.4.映射器Mappers 1.5.dataSource 1.6.事务 二.Mybatis中的关系映射 2.1.一对一映射 2.2.一对多映射 一.配置文件内容 mybatis.xml就是Mybatis的全局配置文件. 全局配置文件需要在头部使用约束文件. <?xml version="1.0" encoding="UTF-8" ?>

  • JavaScript策略模式利用对象键值的映射关系详解

    目录 引言 1.策略模式的极简实现 2.策略模式的简单案例 (1)工具函数 (2)提示样式 总结 引言 策略模式指的是,定义一系列的算法,把它们一个个的封装起来,通过传递一些参数,使他们可以相互替换. 举个周末从家去咖啡馆的例子: 从家去咖啡馆,有跑步.骑行和漫步的方式.也就是说,从家到咖啡馆,有三种策略可选择. 1.策略模式的极简实现 通过对象的键值映射关系,定义策略和具体实现之间的关系: var strategies = { A: xxx, B: yyy, C: zzz } 其中,A.B和C

  • 研究Python的ORM框架中的SQLAlchemy库的映射关系

    前面介绍了关于用户账户的User表,但是现实生活中随着问题的复杂化数据库存储的数据不可能这么简单,让我们设想有另外一张表,这张表和User有联系,也能够被映射和查询,那么这张表可以存储关联某一账户的任意数量的电子邮件地址.这种联系在数据库理论中是典型的1-N (一对多)关系,用户表某一用户对应N条电子邮件记录. 之前我们的用户表称为users,现在我们再建立一张被称为addresses的表用于存储电子邮件地址,通过Declarative系统,我们可以直接用映射类Address来定义这张表: >>

随机推荐