统计数据库当前数据容量

一、SQL Server

单表:sp_spaceused '表名'

单库:sp_MSforeachtable "sp_spaceused '?'" --对每一张表进行单表查询,不好用

那么怎么快速统计当前库数据量?让我先介绍一下SQL Server的page概念。

在 SQL Server 中,Page(页) 是数据存储的最小物理单位,所有的数据、索引、日志等最终都会以页为单位存储在磁盘上。

页的核心基础属性

  1. 固定大小 :SQL Server 中每个页的大小固定为 8KB(8192 字节),这是不可更改的系统设定。
  2. 页标识 :每个页都有唯一的标识 FileID:PageID(文件 ID + 页 ID),用于精确定位页的位置。
  3. 页的结构 :一个 8KB 的页包含三部分:
    • 页头(Page Header):占 96 字节,存储页的元数据(如页类型、所属对象 ID、页的可用空间、上 / 下一页指针等)。
    • 数据区:占约 8060 字节,存储实际的数据行、索引项等核心内容。
    • 行偏移数组:存储数据行在页内的偏移量,占用剩余字节(随数据行数变化)。

了解了页属性,我们就可以使用通过页的计算来明确我们当前数据库存储数据的大小

示例:

sql 复制代码
SELECT 
    OBJECT_SCHEMA_NAME(t.object_id) AS 架构名,  -- 从sys.tables获取架构信息
    t.name AS 表名,                              -- 从sys.tables获取表名
    SUM(p.rows) AS 行数,                         -- 从sys.partitions获取行数
    
    -- 总空间 (MB) - 从sys.allocation_units获取页数
    CAST(ROUND((SUM(a.total_pages) * 8 / 1024.00), 2) AS NUMERIC(36, 2)) AS 总空间_MB,
    
    -- 数据空间 (MB) - 从sys.allocation_units获取数据页
    CAST(ROUND((SUM(a.data_pages) * 8 / 1024.00), 2) AS NUMERIC(36, 2)) AS 数据空间_MB,
    
    -- 索引空间 (MB) - 计算得出(已用页 - 数据页)
    CAST(ROUND(((SUM(a.used_pages) - SUM(a.data_pages)) * 8 / 1024.00), 2) AS NUMERIC(36, 2)) AS 索引空间_MB,
    
    -- 未使用空间 (MB) - 计算得出(总页 - 已用页)
    CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8 / 1024.00), 2) AS NUMERIC(36, 2)) AS 未使用空间_MB
    
FROM 
    sys.tables t  -- 主表:所有用户表

改造使用:

sql 复制代码
WITH TableSpace AS (
    SELECT 
        t.object_id,
        t.name AS 表名,
        SCHEMA_NAME(t.schema_id) AS 架构名,
        
        -- 行数
        (SELECT SUM(rows) FROM sys.partitions p 
         WHERE p.object_id = t.object_id AND p.index_id IN (0,1)) AS 行数,
        
        -- 总空间
        (SELECT SUM(total_pages) * 8 / 1024.0 FROM sys.allocation_units a
         INNER JOIN sys.partitions p ON a.container_id = p.partition_id
         WHERE p.object_id = t.object_id) AS 总空间_MB,
        
        -- 数据空间
        (SELECT SUM(CASE WHEN a.type IN (0,1,4) THEN a.total_pages ELSE 0 END) * 8 / 1024.0 
         FROM sys.allocation_units a
         INNER JOIN sys.partitions p ON a.container_id = p.partition_id
         WHERE p.object_id = t.object_id) AS 数据空间_MB
    FROM sys.tables t
    WHERE t.is_ms_shipped = 0
)
SELECT 
    架构名,
    表名,
    行数,
    CONVERT(DECIMAL(18,2), 总空间_MB) AS 总空间_MB,
    CONVERT(DECIMAL(18,2), 数据空间_MB) AS 数据空间_MB,
    CONVERT(DECIMAL(18,2), 总空间_MB - 数据空间_MB) AS 索引及其他空间_MB,
    CONVERT(VARCHAR(20), CONVERT(DECIMAL(18,2), 总空间_MB)) + ' MB' AS 总空间_显示,
    CONVERT(VARCHAR(20), 行数) + ' 行' AS 行数_显示
FROM TableSpace
ORDER BY 总空间_MB DESC;

查询结果

总计汇总的sql:

sql 复制代码
SELECT 
    DB_NAME() AS 数据库名,
    CAST(SUM(size) * 8 / 1024.0 AS DECIMAL(18,2)) AS 总大小_MB,
    CAST(SUM(CASE WHEN type = 0 THEN size ELSE 0 END) * 8 / 1024.0 AS DECIMAL(18,2)) AS 数据文件_MB,
    CAST(SUM(CASE WHEN type = 1 THEN size ELSE 0 END) * 8 / 1024.0 AS DECIMAL(18,2)) AS 日志文件_MB,
    CAST(SUM(size) * 8 / 1024.0 / 1024 AS DECIMAL(18,2)) AS 总大小_GB
FROM sys.database_files;

二、MySQL

老朋友比较直接

sql 复制代码
-- 展示test03数据库test_01表的大小
SELECT * FROM information_schema.`TABLES` WHERE table_schema = 'test3' AND table_name = 'test_01';

SHOW TABLE STATUS LIKE 'test_01';

但是查询出来不容易读,data_length 记录的是字节数,所以需要进行换算

sql 复制代码
-- 最常用的换算
SELECT 
    table_name,
    CONCAT(ROUND(data_length / 1024 / 1024, 2), ' MB') AS 数据大小,
    CONCAT(ROUND(index_length / 1024 / 1024, 2), ' MB') AS 索引大小,
    CONCAT(ROUND((data_length + index_length) / 1024 / 1024, 2), ' MB') AS 总大小
FROM information_schema.TABLES 
WHERE table_schema = 'test3' 
    AND table_name = 'test_01';

结果

三、postgresql

postgresql分层为

PostgreSQL 服务器实例

├── 数据库1 (Database)

│ ├── 架构1 (Schema) ── 表、视图、函数等对象

│ ├── 架构2 (Schema) ── 表、视图、函数等对象

│ └── 架构3 (Schema) ── 表、视图、函数等对象

├── 数据库2 (Database)

│ ├── 架构1 (Schema)

│ └── 架构2 (Schema)

└── 数据库3 (Database)

└── 架构1 (Schema)

所以我们要明确的需要的是schema的数据量还是database的数据量

sql 复制代码
-- 一个好用的函数
-- 1. 查询当前连接数据库的大小
SELECT pg_database_size(current_database());

-- 2. 查询指定名称的数据库大小
SELECT pg_database_size('数据库名');

-- 3. 查询所有数据库的大小
SELECT 
    datname AS 数据库名,
    pg_database_size(datname) AS 字节数,
    pg_size_pretty(pg_database_size(datname)) AS 可读大小
FROM pg_database
ORDER BY pg_database_size(datname) DESC;

转换成好读的格式

sql 复制代码
-- 查看数据库总大小(包含所有 schema)
SELECT
    current_database() AS 数据库名,
    pg_size_pretty(pg_database_size(current_database())) AS 数据库总大小;

更多时候需要的会是个别schema的大小

主要使用两张表来达成我们的目的

  1. pg_namespace - 存储所有schema(命名空间)的信息

  2. pg_class - 存储所有数据库对象(表、索引、视图等)的信息

我的postgresql没有做大小写忽略,所以要拿oid去做联查

这是pg_namespace的数据,public是我要算的schema

接下来查询pg_class表,获取到11行数据,跟我们public中存储的表数量相同

sql 复制代码
select * from pg_class where relnamespace = 2200 and relkind = 'r';

📋 pg_class 关键字段

字段 说明 在本SQL中的作用
oid 对象的唯一ID 传给 pg_total_relation_size() 计算大小
relname 对象名称 COUNT() 统计表数量
relnamespace 所属schema的OID pg_namespace.oid 关联
relkind 对象类型 'r' 表示普通表

relkind 的可能值:

  • r = 普通表 (ordinary table)

  • i = 索引 (index)

  • S = 序列 (sequence)

  • v = 视图 (view)

  • m = 物化视图 (materialized view)

  • c = 复合类型 (composite type)

  • t = TOAST表

  • f = 外部表 (foreign table)

成品sql

sql 复制代码
WITH schema_name_oid AS (
    SELECT oid
    FROM pg_namespace
    WHERE nspname = 'public'
       OR nspname ILIKE '%public%'  -- 不区分大小写搜索
)
SELECT
    'public' AS schema名,
    COUNT(c.relname) AS 表数量,
    pg_size_pretty(COALESCE(SUM(pg_total_relation_size(c.oid)), 0)) AS schema总大小
FROM pg_class c
CROSS JOIN ts_dmp_oid t
WHERE c.relnamespace = t.oid
  AND c.relkind = 'r';

四、Oracle

单表查询

SELECT * FROM dba_segments WHERE owner = '架构名' AND segment_name = '表名';

读的话还是要处理一下

sql 复制代码
SELECT 
    owner AS 所有者,
    segment_name AS 段名称,
    segment_type AS 段类型,
    tablespace_name AS 表空间,
    ROUND(bytes / 1024 / 1024, 2) AS 大小_MB,
    ROUND(bytes / 1024 / 1024 / 1024, 4) AS 大小_GB,
    blocks AS 块数,
    extents AS 区数量
FROM dba_segments 
WHERE owner = '架构名' 
  AND segment_name = '表名';

查询当前schema(owner)的全部数据

sql 复制代码
SELECT
    owner,
    ROUND(SUM(bytes) / 1024 / 1024, 2) AS 真实总大小_MB,
    ROUND(SUM(bytes) / 1024 / 1024 / 1024, 4) AS 真实总大小_GB
FROM dba_segments
WHERE owner = 'xxxx'
GROUP BY owner;

dba_segments 介绍

dba_segments 是Oracle数据库中一张核心的系统视图。简单来说,你可以把它理解为一张记录了数据库中所有"储物箱"(段)详细信息的清单。

在Oracle里,数据库的存储结构是分层的:数据库由多个表空间组成,表空间里又包含多个段。一个段就是一个占用存储空间的数据库对象。最常见的段就是表和索引。每当你创建一个表或索引,Oracle就会为它分配一个段来存放数据。

dba_segments 表里有什么?

字段名 描述 你的关注点
OWNER 段的拥有者,也就是哪个**模式(Schema)**拥有这个对象。 如果你想看某个用户(如 TS_DMP)下的所有对象,就用这个字段过滤。
SEGMENT_NAME 段的名称。 如果段是表,这里就是表名;如果是索引,这里就是索引名。
SEGMENT_TYPE 段的类型。 这是关键字段 。它告诉你这个段到底是表、索引,还是大对象段(LOBSEGMENT)等。常见的类型有:TABLE, INDEX, LOBSEGMENT, TABLE PARTITION 等。
TABLESPACE_NAME 这个段存储在哪个表空间中。 用于查看对象在表空间层面的分布情况。
BYTES 段的实际大小,单位是字节。 这是你最关心的字段。它是计算空间占用的直接数据来源。
BLOCKS 段占用的Oracle块数量。 可以结合数据库块大小(通常是8KB)来计算空间,但直接用BYTES更准确。
EXTENTS 为这个段分配了多少个"区"(Extent)。 反映了段的碎片化程度和分配情况。

未完待续。。。

达梦

相关推荐
Leon-Ning Liu2 小时前
OGG同步Oracle到Kafka
数据库·oracle·kafka
远方16092 小时前
117-Oracle 26ai FILTER(过滤)子句新特性
大数据·数据库·sql·oracle·database
Maverick062 小时前
Oracle 归档日志(Archive Log)操作手册
数据库·oracle
isNotNullX2 小时前
一文讲清8大数据清洗方法
大数据·数据库·数据挖掘·数据迁移
Francek Chen2 小时前
【大数据存储与管理】分布式数据库HBase:05 HBase运行机制
大数据·数据库·hadoop·分布式·hdfs·hbase
小小怪7502 小时前
将Python Web应用部署到服务器(Docker + Nginx)
jvm·数据库·python
麦聪聊数据2 小时前
SQL 到 API 转化过程中的版本控制与灰度发布机制
数据库·sql·低代码·微服务
Coder-coco2 小时前
家政服务管理系统|基于springboot + vue家政服务管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·家政服务管理系统
人道领域2 小时前
Day | 07 【苍穹外卖 :用户端添加购物车】
java·开发语言·数据库·后端·苍穹外卖