接前面。

回到程序调用关系上来:

estimate_rel_size -> RelationGetNumberOfBlocks->RelationGetNumberOfBlocksINFork

->Smgrnblocks->mdnblocks...

折腾了一圈,就是为了评估一个表的大小。

那么,我们所获得的block,它到底是个什么单位?

BlockNumber
mdnblocks(SMgrRelation reln, ForkNumber forknum)
{MdfdVec    *v = mdopen(reln, forknum, EXTENSION_FAIL);BlockNumber nblocks;BlockNumber segno = 0;/** Skip through any segments that aren't the last one, to avoid redundant* seeks on them.  We have previously verified that these segments are* exactly RELSEG_SIZE long, and it's useless to recheck that each time.** NOTE: this assumption could only be wrong if another backend has* truncated the relation.    We rely on higher code levels to handle that* scenario by closing and re-opening the md fd, which is handled via* relcache flush.    (Since the checkpointer doesn't participate in* relcache flush, it could have segment chain entries for inactive* segments; that's OK because the checkpointer never needs to compute* relation size.)*/while (v->mdfd_chain != NULL){segno++;v = v->mdfd_chain;}for (;;){
        nblocks = _mdnblocks(reln, forknum, v);fprintf(stderr,"%d blocks by process %d\n\n",nblocks,getpid());if (nblocks > ((BlockNumber) RELSEG_SIZE))elog(FATAL, "segment too big");if (nblocks < ((BlockNumber) RELSEG_SIZE))return (segno * ((BlockNumber) RELSEG_SIZE)) + nblocks;/** If segment is exactly RELSEG_SIZE, advance to next one.*/segno++;if (v->mdfd_chain == NULL){/** Because we pass O_CREAT, we will create the next segment (with* zero length) immediately, if the last segment is of length* RELSEG_SIZE.  While perhaps not strictly necessary, this keeps* the logic simple.*/v->mdfd_chain = _mdfd_openseg(reln, forknum, segno, O_CREAT);if (v->mdfd_chain == NULL)ereport(ERROR,(errcode_for_file_access(),errmsg("could not open file \"%s\": %m",_mdfd_segpath(reln, forknum, segno))));}v = v->mdfd_chain;}
}

还是用实验来验证一下吧:

先建立表:

postgres=# create table tst01(id integer);
CREATE TABLE
postgres=# postgres=# select oid from pg_class where relname='tst01';oid
-------16384
(1 row)

据我所知,PostgreSQL中,integer类型的数据会在每条记录中占用4个字节。

那么我想,4字节×2048条记录=8192字节,也就是8K。

事实如何呢?

[root@lex base]# ls ./12788/16384
./12788/16384postgres=# insert into tst01 values(generate_series(1,2048));
INSERT 0 2048
postgres=# [root@lex base]# ls -lrt ./12788/16384
-rw------- 1 postgres postgres 81920 May 28 11:54 ./12788/16384
[root@lex base]# ls -lrt -kb ./12788/16384
-rw------- 1 postgres postgres 80 May 28 11:54 ./12788/16384
[root@lex base]# 

不是8K,而是 80K!

数据量再翻上一倍会如何?

postgres=# insert into tst01 values(generate_series(2049,4096));
INSERT 0 2048
postgres=#[root@lex base]# ls -lrt -kb ./12788/16384
-rw------- 1 postgres postgres 152 May 28 11:56 ./12788/16384
[root@lex base]# 

原本我以为,8K为单位的block,仅仅是一小部分是冗余数据(如Header),但事实是并非这样。

问了牛人,得到的答复是:

postgres=# select pg_column_size(id) from tst01 limit 1;pg_column_size
----------------4
(1 row)postgres=# select pg_column_size(t) from tst01 t limit 1;pg_column_size
----------------28
(1 row)

然后再来看程序里对block的处理:

postgres=# select count(*) from tst01;count
-------4096
(1 row)postgres=# 

此时,后台输出的是:

19 blocks by process 4920

19是什么概念:

[root@lex 12788]# ls -lrt 16384
-rw------- 1 postgres postgres 155648 May 28 11:58 16384
[root@lex 12788]# 155648/8096 = 19.225296442688

正好合拍。所以PostgreSQL的源代码中,mdnblocks 取得的block数目,就是 8K为单位的数据块的个数。

从前面的小实验中也可以看到,如果一条记录中的数据较少,header部分所占冗余就占比较大了。

因此,如果想要正确评估一个表所占用的实际空间,基本上要靠抽样了。

PostgreSQL在何处处理 sql查询之二十二相关推荐

  1. SQL Server-聚焦深入理解动态SQL查询(三十二)

    前言 之前有园友一直关注着我快点出SQL Server性能优化系列,博主我也对性能优化系列也有点小期待,本来打算利用周末写死锁以及避免死锁系列的接着进入SQL Server优化系列,但是在工作中长时间 ...

  2. FreeSql (二十二)Dto 映射查询

    适合喜欢使用 dto 的朋友,很多时候 entity 与 dto 属性名相同,属性数据又不完全一致. 有的人先查回所有字段数据,再使用 AutoMapper 映射. 我们的功能是先映射,再只查询映射好 ...

  3. 零基础带你学习MySQL—单行子查询和多行子查询(二十二)

    零基础带你学习MySQL-多行子查询(二十二) 一.什么是子查询? 子查询是指嵌入在其它 sql 语句中的 select 语句,也叫嵌套查询 二.什么是单行子查询? 单行子查询是指只返回一行数据的子查 ...

  4. (二十二)查询订单的详情

    (二十二)查询订单的详情 案例2-查询订单的详情 需求:只有未付款的订单,点击"付款",跳转到订单的详情页面 步骤分析:1.在订单列表,点击付款,/store/order?meth ...

  5. 实验二十二 SCVMM中的SQL Server配置文件

    实验二十二 SCVMM中的SQL Server配置文件 在VMM 2012中管理员可以使用 SQL Server 配置文件,在部署完成虚拟机之后,实现 SQL Server 数据库服务自动化部署并交付 ...

  6. Android项目实战(二十二):启动另一个APP or 重启本APP

    Android项目实战(二十二):启动另一个APP or 重启本APP 原文:Android项目实战(二十二):启动另一个APP or 重启本APP 一.启动另一个APP 目前公司项目需求,一个主AP ...

  7. OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()

    OpenCV学习(二十二) :反向投影:calcHist(),minMaxLoc(),compareHist() 参考博客: 反向投影backproject的直观理解 opencv 反向投影 颜色直方 ...

  8. JAVA基础知识总结:一到二十二全部总结

    >一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...

  9. Reflex WMS入门系列二十二:物料库存报表

    Reflex WMS入门系列二十二:物料库存报表 在Reflex WMS系统上,我们可以通过物料号查询它的HD列表,或者IPG列表.通过在其HD/IPG信息得知其库存数据.当然还可以通过如下方式直接获 ...

  10. 【转载】 javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册 - 孤傲苍狼 - 博 http://www.cnblogs.com/xdp-gacl/

    javaweb学习总结(二十二)--基于Servlet+JSP+JavaBean开发模式的用户登录注册 一.Servlet+JSP+JavaBean开发模式(MVC)介绍 Servlet+JSP+Ja ...

最新文章

  1. php 下划线转大写开头,使用PHP把下划线分隔命名的字符串 转换成驼峰式命名方式 , 把下划线后面的第一个字母变成大写...
  2. 中国大学生源质量排行榜150强
  3. 给你推荐几个 NB 的公众号
  4. Redis sorted set 类型操作及常用命令
  5. C语言数字3转变字符 3 程序,大学c语言知识点总结
  6. 【java基础知识】Spring Boot启动报错com.sun.jersey.api.client.ClientHandlerException: java.net.ConnectExcepti
  7. [渝粤教育] 西南科技大学 材料力学 在线考试复习资料
  8. BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)
  9. java课程设计——简易计算器
  10. Boni Satani谈迁移遗留系统的5个原因
  11. Exploit开发系列教程-Windows基础shellcode
  12. 天空卫士API数据安全解决方案
  13. 优化网站提高打开速度
  14. EPLAN之设备编号
  15. WWW 2019 | HAN:异质图注意力网络
  16. 这次一定 | “学废” 正则表达式
  17. 8188gu驱动和su realtek_RTL8188CU 和RTL8188SU有什么区别,哪个好,谢谢
  18. 网易云音乐中你见过最扎心的热评是什么
  19. 升级windows11的方法
  20. 乐鑫科技,活跃在国际舞台上的中国芯

热门文章

  1. 高德地图 JS API - 根据地名实现标记定位
  2. Linux中查看各文件夹大小(扫盘)
  3. 1014冒泡排序文法推导
  4. 数据库三范式的理解(引用其他网友)
  5. 统计含中英文混编的NSString 字符串长度
  6. Linux服务器网页显示乱码
  7. mysql 安全扫描_MySQL 安全和监控 - Can't Wait Any Longer - OSCHINA - 中文开源技术交流社区...
  8. 【CoppeliaSim】远程 API 之 Matlab 控制,对比 V-rep 有些不同
  9. 【OFDM频域同步】基于OFDM数字电视地面广播系统中频域同步技术matlab仿真
  10. 基于FPGA的costas环同步系统仿真与分析