尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

PostgreSQL数据库大小查询指南:函数原理、实操SQL与DeepSeek排障实践

发布时间:2026/9/29 16:35:02

资讯中心
01
ARTICLE

PostgreSQL数据库大小查询指南:函数原理、实操SQL与DeepSeek排障实践

PostgreSQL数据库大小查询指南:函数原理、实操SQL与DeepSeek排障实践
上周半夜两点监控告警把我从床上叫醒磁盘使用率92%。爬起来第一件事不是去看日志而是登录数据库想搞清楚到底是哪个库、哪张表把空间吃没了。这个场景做运维的应该都经历过而PostgreSQL在这一点上确实非常友好——系统内置了一整套大小函数pg_database_size、pg_total_relation_size、pg_size_pretty这些随时可以调用。再配合DeepSeek做查询整理几分钟就能把所有库、所有表按大小排个名定位问题比翻日志快多了。这篇文章就把这块内容从头到尾盘一遍先解释为什么查询数据库大小是个刚需再把这些大小函数的原理和区别讲清楚给出可以直接抄作业的SQL最后聊聊我用DeepSeek辅助写这些查询的实际做法以及几个容易踩的坑。新手看完能直接用老手也可以对照查漏。1. 到底什么时候需要“查询数据库大小”很多人觉得查大小就是看一眼硬盘满没满其实这个需求比想象中频繁得多。我自己的经验里至少有这么几类场景必须拿到准确的大小数据。磁盘告警和容量规划是最直接的。生产环境磁盘告警是深夜被叫醒的主力原因这时候你不是想知道大概有多满而是需要立刻定位到具体哪个库、哪张表、甚至哪个索引在暴涨。PostgreSQL的大小函数做这件事非常顺手因为它能一层层拆开数据库大小、表大小、索引大小、TOAST大小都能单独拿出来看。相比之下MySQL早期版本查表大小要翻information_schema差点意思。备份和恢复窗口的估算也离不开它。备份耗时和数据库物理大小直接相关恢复更是如此。我见过不止一次因为没提前关注大小增长备份窗口被越挤越短最后凌晨的备份任务和业务高峰撞在一起把IO拖垮。定期记录各库大小配合历史趋势可以提前预判“这个月备份会多慢”“下个月磁盘要不要加”把问题消灭在发生之前。巡检和慢查询定位同样需要大小数据。一张表查得慢原因可能是索引没建好也可能是表膨胀得太厉害——逻辑大小和物理页数都上去了扫描代价自然暴涨。把表和索引的大小排在同一个查询里看很多问题的方向马上清晰。比如某张表数据只有300MB索引却2GB那大概率是索引设计不合理而不是数据本身的问题。分库分表、数据归档这类改造更需要精确度量。哪些库占了80%空间哪些表是历史数据可以归档决定动刀之前没有准确的大小清单方案基本靠拍脑袋。把全库的大小榜拉出来按“表主体索引TOAST”三个维度看归档优先级立刻就有了。一句话查询数据库大小不是“看一眼容量”这种一次性动作而是运维巡检、容量规划、性能排查路上的基础设施。PostgreSQL把这套能力做成系统函数直接暴露给用户就是让这类问题永远不需要去翻文件系统。2. 认识这几个核心大小函数PostgreSQL关于“大小”的函数都定义在pg_catalog里不需要安装扩展连超级用户权限都不用——只要有对应对象的访问权限就能查。它们之间的关系有时候容易绕晕先给一张对照表后面逐个拆。函数返回内容典型用途pg_database_size(datname)整个数据库全部对象占用的总字节数看一个库的整体体量pg_total_relation_size(regclass)表主体 TOAST表 TOAST索引 附属索引看一张表“连同索引”的真实成本pg_table_size(regclass)表主体 TOAST表 TOAST索引看表数据本身不含普通索引pg_relation_size(regclass)表的主体数据文件main fork不含TOAST、不含索引最纯粹的“表数据”pg_indexes_size(regclass)该表附属索引的总大小评估索引开销pg_size_pretty(bigint)把字节数格式化成MB、GB等易读单位让人眼能直接看懂pg_size_bytes(text)反向解析字符串为字节数配置项换算时有用注意一下pg_relation_size也能传索引的OID这时返回的就是索引文件大小。同一个函数传表名返回表主体大小传索引名返回索引大小靠参数类型来判断。很多人会混淆pg_table_size和pg_total_relation_size。简单记忆totaltable 普通索引。pg_table_size本身已经包含了TOAST的部分所以不要把TOAST再单独加一遍。TOAST是什么必须多说一句。PostgreSQL的页大小默认8KB一行数据如果超过了大约2KB实际上是一个页能容纳的行数阈值变长字段就会被压缩甚至拆到额外的TOAST表里。TOAST表有自己的文件独立于主表存储。所以pg_relation_size返回的只是主表文件的大小没算TOAST。一些大字段特别多的表TOAST可能比主表大好几倍只看pg_relation_size会严重低估真实存储成本这也是后面要聊的常见坑之一。这些函数返回的都是字节数是bigint。直接看一长串数字让人头大所以正经用法永远是套一层pg_size_prettySELECT pg_size_pretty(pg_database_size(mydb));需要强调一个特点这些大小函数都是实时计算的不是读统计信息快照。每次调用都要实际去扫描目录、统计页面数量。对于小库来说是毫秒级但碰上几TB的库pg_database_size也可能慢到让你怀疑是不是卡住了——它确实要遍历这个库相关的所有文件。3. 实操从全库总览到单表定位函数本身很简单真正的价值在于组合起来解决实际问题。这一节给几个我日常最常用的查询全部验证过可以直接复制替换库名或表名。3.1 查看当前数据库大小SELECT pg_size_pretty(pg_database_size(current_database())) AS db_size;current_database()返回当前连接的库名省去手写库名的麻烦。这条命令在确认“某台服务器上的库里谁最大”时不是首选因为只能看当前库。3.2 列出实例上所有数据库按大小排序SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database ORDER BY pg_database_size(datname) DESC;这里有个细节排序必须用未格式化的pg_database_size(datname)不能按size排。因为pg_size_pretty返回的是文本6.9 GB和80 MB按字符串排序的话结果是不可预测的。我见过很多新手在这上面栽跟头排出来最大最小完全混乱其实只要排序字段用原始字节数就没问题。执行结果的示例大概长这样datnamesizewarehouse856 GBorders312 GBanalytics45 GBpostgres8 MB如果只想看库里有没有“异常大”的可以加HAVING条件过滤比如只显示超过10GB的省得被一堆几十MB的开发库干扰视线。3.3 查看某个库内所有表的大小排行这是使用频率最高的一条SELECT n.nspname AS schema_name, c.relname AS table_name, pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE n.nspname NOT IN (pg_catalog, information_schema) AND c.relkind r ORDER BY pg_total_relation_size(c.oid) DESC LIMIT 20;拆开解释一下。pg_class是系统表存了所有表和索引的元信息pg_namespace是命名空间也就是schema。过滤掉pg_catalog和information_schema是为了不把系统对象算进来。relkind r表示只要普通表不要索引、视图、序列这些。如果不想和系统表打交道也可以用pg_stat_user_tables视图SELECT relname, pg_size_pretty(pg_total_relation_size(relid)) AS total_size FROM pg_stat_user_tables ORDER BY pg_total_relation_size(relid) DESC LIMIT 20;这个写法更简洁但注意pg_stat_user_tables里没有直接的schema信息多个schema重名时会分不清。生产环境我习惯用pg_class那一版信息完整多加两个join也不麻烦。实际看结果的时候不要只盯着第一行。我通常会把前20条整体扫一遍如果最大表和第二大表之间有数量级的断层说明单体大表问题如果前20名全部很大说明这个库整体设计偏“重”可能要考虑分区或归档了。3.4 只看表的索引大小揪出索引膨胀表大小是表索引的合计但在排查索引膨胀时需要单独看索引SELECT i.relname AS index_name, t.relname AS table_name, pg_size_pretty(pg_relation_size(i.oid)) AS index_size FROM pg_index idx JOIN pg_class i ON i.oid idx.indexrelid JOIN pg_class t ON t.oid idx.indrelid ORDER BY pg_relation_size(i.oid) DESC LIMIT 20;或者用现成的视图pg_stat_user_indexes更简单SELECT indexrelname, pg_size_pretty(pg_relation_size(indexrelid)) AS index_size FROM pg_stat_user_indexes ORDER BY pg_relation_size(indexrelid) DESC LIMIT 20;索引膨胀的经典情况是某张表的索引占了表本身大小的好几倍。这是因为频繁更新时索引页的旧版本不会立刻被复用膨胀比例可以非常夸张。看到这种场景基本就可以安排pg_repack或者重建索引了。3.5 用分项拆解函数精确定位空间去向有时候我们不只是想知道谁大而是想知道大在哪里。一条查询把表拆开SELECT c.relname AS table_name, pg_size_pretty(pg_relation_size(c.oid)) AS table_data, pg_size_pretty(pg_indexes_size(c.oid)) AS index_data, pg_size_pretty(pg_total_relation_size(c.oid)) AS total_size FROM pg_class c JOIN pg_namespace n ON n.oid c.relnamespace WHERE n.nspname NOT IN (pg_catalog, information_schema) AND c.relkind r ORDER BY pg_total_relation_size(c.oid) DESC LIMIT 10;这种拆解的价值在于“对症下药”。如果total_size大是因为index_data占大头那重建索引或删掉冗余索引比任何添加磁盘都更有效如果table_data占大头就要考虑数据归档、分区裁剪如果总大小不算大但查询还慢那就是别的问题了跟容量无关。数据是不会骗人的把大小拆开看方向基本不会错。3.6 反向解析用pg_size_bytes处理自动任务pg_size_bytes比较冷门但在写脚本时很实用。比如某个自动化脚本需要“找出大小超过10GB的库”如果配置项是文本10 GB可以这么用SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database WHERE pg_database_size(datname) pg_size_bytes(10 GB) ORDER BY pg_database_size(datname) DESC;这函数就是把10 GB这种人类友好的写法解析成字节数省得自己在脚本里做单位换算也避免写错数量级。4. 用DeepSeek辅助写大小查询的实战做法说回标题里那个组合DeepSeek和PostgreSQL大小函数。其实逻辑很简单——PostgreSQL提供了准确、完整的大小函数体系而DeepSeek的价值在于帮你把这些函数快速组织成能解决问题的SQL尤其是当你记不清函数名、或者需要临时写一个多表关联的排行查询时。4.1 自然语言直接生成SQL我在日常运维中经常临时起意查一个东西以前要翻文档回忆函数签名现在直接把需求扔给DeepSeek。举个例子我当时的输入是帮我写一条PostgreSQL SQL列出当前实例所有非系统数据库的名称和大小按大小降序用易读单位显示结果限制20行。它给出的答案跟我在3.2节写的基本一致SELECT datname, pg_size_pretty(pg_database_size(datname)) AS size FROM pg_database WHERE datistemplate false AND datallowconn true ORDER BY pg_database_size(datname) DESC LIMIT 20;注意它还主动加了datistemplate false过滤掉模板库这个细节说明它理解“非系统数据库”这个需求。模板库确实不该混进容量排行里。再比如我想找“哪些表的索引占比超过50%”这种需求如果自己拼SQL要写子查询用自然语言就很直接查出当前库里所有用户表显示表名、表数据大小、索引大小和索引占比索引占比超过50%的优先排前面。DeepSeek会组合pg_total_relation_size、pg_relation_size、pg_indexes_size用一条带子查询的语句完成还能保证排序逻辑正确。这比我徒手写要快得多。4.2 报错信息丢进去几秒钟得到排查方向执行SQL报错是家常便饭。最典型的是权限问题ERROR: permission denied for database mydb把完整的报错贴给DeepSeek它通常会给出三条主要检查路径当前用户是否拥有该库的CONNECT权限、是否被授予了pg_read_all_stats角色、表级大小查询需要相应表的权限。我第一次遇到这个报错时用DeepSeek定位到是某个只读账号缺少pg_read_all_stats加上就好。它的价值不在于替代DBA的判断而是把“遇到报错→查文档→确认原因”这个过程压缩到几秒钟。大小函数相关的报错就那么几类语料充分回答一般都比较准确。4.3 生成巡检脚本和持续监控方案查一次大小不难难的是持续监控。用DeepSeek生成一个每天定时执行、把Top20表大小写入日志的脚本是目前我觉得最好用的场景之一。下面是一个典型的Prompt写一个Linux shell脚本用psql查询PostgreSQL中每个库的大小和每个库内最大的5张表把结果按日期追加写入 /var/log/pg_size_daily.log失败时返回非零退出码。它会给出可行的脚本骨架psql -c执行SQLdate %F拼文件名最后用$?检查退出码。这些逻辑本身不复杂但让DeepSeek先出一版再按你的环境改改比从零写要快不少。4.4 用DeepSeek前必须掌握的三个防错要点AI生成的SQL不是免检产品用得多了我总结出三个必须自己把关的地方。第一系统对象过滤条件不能丢。如果Prompt里只说“列出所有表”生成的SQL可能把pg_catalog里的系统表也带进来统计出来的大小完全失真。看到不含nspname NOT IN (pg_catalog, information_schema)的版本要能自己补上。第二排序必须基于数值而不是格式化文本。DeepSeek偶尔会生成ORDER BY pg_size_pretty(...)这种写法结果看起来是按照字符串排的容易出问题。判断标准很简单凡是用于排序的字段必须传原始字节数。第三TOAST和索引的包含关系要确认。有时候你问“查一下这张表多大”它会用pg_relation_size返回的只是表主体不含索引。如果业务上想看的“多大”包括了索引和TOAST就要明确说用pg_total_relation_size。需求描述越准确返回结果越不用改。4.5 从“会查”到“会问”的小技巧我使用DeepSeek配合数据库运维的经验是把问题描述得越接近SQL逻辑结果越能用。与其说“看看哪个库很大让我清理一下”不如说“找出占用空间最大的10个数据库显示库名和大小按大小降序”。心里先有一个大概的SQL结构——要查哪个视图、用哪个函数、怎么过滤、怎么排序——再让AI补全这种方法在任何数据库运维场景都通用。5. 常见问题与排查技巧实录大小函数看着简单实际用起来有一堆细节坑。下面这些都是我在现网环境踩过的整理出来供参考。5.1 查出来的大小和du看到的不一致有段时间我发现pg_database_size算出来某个库是500GB但du -sh那个库对应的目录不到400GB。最初以为函数算错了后来才捋清楚数据库的物理目录不止包含表和索引文件还有一堆别的东西。排查的思路是先看整个数据目录的构成。base/目录放着用户数据库pg_wal/是WAL日志postgresql.conf和pg_control这些是配置文件。WAL可能占到几十GB甚至更多特别是没用异步提交或归档策略密集写入时pg_wal目录经常成为“隐藏容量黑洞”。pg_database_size统计的是该库的表和索引文件不会把WAL算进去所以两者对不上是正常现象。真要核对某个库的文件需要去base/数据库OID/目录下看。数据库OID可以从pg_database表查。但表文件可能分布在多个目录而且TOAST表是另一个文件手动核对非常繁琐一般不建议做。知道“为什么对不上”就够了。5.2 删了大量数据大小却一点没变小这是最常见的认知误区。PostgreSQL里执行DELETE只是把行标记为不可见空间并不会归还给操作系统。表文件里的那些页还在只是变成“可复用”状态。要让它变小常见做法是VACUUM FULL或者pg_repack。但注意VACUUM FULL会持锁生产环境搞不好会阻塞写入必须安排在维护窗口或者用pg_repack在线处理。还有一些DBA会犯另一个错误删完数据什么都不做以为下次VACUUM会自动回收。普通VACUUM只清理死元组腾出页内空间它不会主动把文件末尾的空页截断。想从文件系统层面看到释放必须执行带FULL的重写操作。大小函数返回的字节数会如实反映这种状态删完数据不重建查出来还是旧的那么大。这也是为什么巡检时看到表逻辑数据量明显小于物理大小第一反应应该是“表膨胀了”。5.3 权限不足导致查询失败有只读账号登录后执行pg_database_size报permission denied这个问题不止一次被问到。原因通常是当前角色没有对应数据库的CONNECT权限或者不是pg_read_all_stats的成员。对于表级的大小函数还需要对该表有权限。快速验证方法是用超级用户执行GRANT CONNECT ON DATABASE xxx TO xxx或者把账号加入pg_read_all_stats角色。如果只是想看大小、不需要数据给pg_read_all_stats更合适权限范围也更克制。5.4 TOAST导致表大小严重失实前面提到过TOAST这里给一个真实案例。有一张表存用户行为日志有个字段是JSONB数据膨胀得非常厉害。用pg_relation_size查出来只有60GB总觉得“还可以”但磁盘告警却一直没停。后来用分项拆解一查pg_total_relation_size显示250GB差值几乎全是TOAST和索引。从那以后我判断一张表是否“大”只会用pg_total_relation_size不再看pg_relation_size。TOAST是PostgreSQL自动管理的内部表用户很容易忽略它但它占的空间真实存在而且大字段场景下往往是主要成本。5.5 超大库执行pg_database_size特别慢前面说过这些函数是实时计算的每次调用都要遍历文件。一个2TB的大型库执行pg_database_size可能要几十秒甚至几分钟。有同事一度以为数据库卡死了直接重启结果问题更大。应对手段有三个一是把这类查询放到业务低谷二是如果只是想看趋势建议定时把结果存到一张统计表里巡检时直接查历史表而不是现场计算三是配合监控系统从操作系统层面对比趋势避免在高峰期反复执行大范围统计。这里提供一个简单的记忆表方便日后排查现象可能原因优先排查方向库大小远小于磁盘占用WAL、归档日志、临时文件pg_wal目录、pg_stat_archiver删除数据后大小不变表膨胀VACUUM FULL或pg_repack查询报权限错误缺少CONNECT或pg_read_all_stats检查角色权限表大小合计远超直觉TOAST文件占空间用pg_total_relation_size复核大库查询卡顿实时扫描文件导致低谷执行或定时落库6. 我的日常巡检习惯最后分享一个我自己坚持了很久的做法写一个简单的巡检脚本每天固定时间记录全库Top20表和最大索引。脚本不复杂就是把前面几条SQL交给cron执行把输出追加到按日期命名的文件里。不需要任何可视化平台连续跑一个月哪个库在涨、哪张表突然加速翻翻日志就一目了然。有一次我就是靠这个日志发现一张日志表每周五都会出现一次明显的容量“台阶”排查后定位到是周五的批处理任务没有做周期清理数据只增不减。这种问题没有历史大小记录靠现场排查很难复现因为查的时候可能已经回落了。我个人对大小函数的使用体会是PostgreSQL这套函数设计得非常顺手它把DBA最常用的容量查询抽象成了几个明确的小函数组合起来就能应对绝大多数场景。而DeepSeek在这里扮演的角色更像一个随叫随到的“查询助手”——你不需要背函数签名不需要翻系统表结构只要把需求说清楚它就能给出可用的SQL。前提是你自己得懂函数之间的包含关系、知道怎么排序、会检查系统对象过滤条件AI输出的是草稿最后的校验还得靠自己的基本功。这两者结合起来日常数据库容量管理这件事确实可以变得非常轻松。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。