DBA 必知必会 —— OB 4.x 版本如何查询磁盘空间占用情况?

首先为大家推荐这个 OceanBase 开源负责人老纪的公众号 "老纪的技术唠嗑局",会持续更新和 #数据库 、#AI#技术架构 相关的各种技术内容。欢迎感兴趣的朋友们关注!
这是一篇纯运维向的文章。

献给所有正在了解 OB,以及准备对 OB 进行测试的朋友们。

背景

准备对 OceanBase 进行测试的朋友们,一定会测一下这款数据库的高压缩比是否如官网上所说的这么恐怖。

目前,在 OceanBase 官网上,虽然已经有 999+ 个与 "磁盘占用空间" 相关的官方文档,但依然无法阻碍用户在 OceanBase 社区论坛中提出 999+ 个与 "磁盘占用空间" 相关的问题。

为了减轻 OceanBase 社区论坛值班同学的工作量,今天简单整理了一篇与 "磁盘占用空间" 相关的文章,在这里和大家分享。欢迎大家在留言区评论、吐槽,以及合理地对作者进行谩骂。

注意:

下文中出现的命令,需要通过 sys 租户,在 oceanbase 库中执行。

文中可能会不厌其烦地备注,希望读者朋友们能够宽恕我的啰嗦。

查询集群和节点的磁盘空间

使用 sys 租户,在 oceanbase 库中,查询各个节点的磁盘占用:

sql 复制代码
SELECT
  SVR_IP,
  DATA_DISK_IN_USE / 1024 / 1024 / 1024 AS USED_GB
FROM oceanbase.gv$ob_servers;

+--------------+----------------+
| SVR_IP       | USED_GB        |
+--------------+----------------+
| 12.345.67.89 | 0.300781250000 |
+--------------+----------------+
1 row in set (0.02 sec)

查询租户的的磁盘空间

使用 sys 租户,在 oceanbase 库中,查询指定租户的磁盘占用。需要在 SQL 中填写 tenant_id = xxx:

sql 复制代码
SELECT svr_ip,
       svr_port,
       tenant_id,
       sum(used_size) / 1024 / 1024 / 1024 AS used_gb
FROM oceanbase.__all_space_usage
WHERE tenant_id = xxx
  AND file_type IN ('tenant file data',
                    'tenant meta data',
                    'tenant tmp data')
GROUP BY svr_ip,
         svr_port;

+--------------+----------+-----------+----------------+
| svr_ip       | svr_port | tenant_id | used_gb        |
+--------------+----------+-----------+----------------+
| 12.345.67.89 |    22602 |      1002 | 0.026878356934 |
+--------------+----------+-----------+----------------+

查询 DataBase 的的磁盘空间

使用 sys 租户,在 oceanbase 库中,查询指定 database 的磁盘占用。需要在 SQL 中填写 tenant_id = xxx。

这里有必要多解释一下下面这条 SQL 中 sum 聚合函数里的 case when:

  • 如果一个 sstable 比较小的话,多个 sstable 会共用一个 2 MB 宏块,计算存储空间的方式会比较特殊。when b.nested_offset = 0 就是用于判断 sstable 是否是小 sstable 的。
    • 如果普通 sstable 的话(b.nested_offset = 0),就使用 2 MB * 宏块数量。
    • 如果是小 sstable 的话(b.nested_offset != 0),就直接用这个 sstable 的 size。
sql 复制代码
SELECT /*+ query_timeout(30000000) */
  a.DATABASE_NAME,
  sum(CASE WHEN b.nested_offset = 0 
      THEN IFNULL(b.data_block_count + b.index_block_count + b.linked_block_count, 0) * 2 * 1024 * 1024
      ELSE IFNULL(b.size, 0) END) / 1024 / 1024 / 1024 AS data_size_in_GB
FROM oceanbase.CDB_OB_TABLE_LOCATIONS a
     INNER JOIN oceanbase.__all_virtual_table_mgr b ON a.svr_ip = b.svr_ip
AND a.svr_port = b.svr_port
AND a.tenant_id = b.tenant_id
AND a.LS_ID = b.LS_ID
AND a.TABLET_ID = b.TABLET_ID
AND a.role = 'LEADER'
AND a.tenant_id = xxx
AND b.table_type >= 10
AND b.size > 0
GROUP BY a.DATABASE_NAME;

+---------------+-----------------+
| DATABASE_NAME | data_size_in_GB |
+---------------+-----------------+
| oceanbase     |  0.003973903134 |
| test          |  0.000002717599 |
| __recyclebin  |  0.000006728805 |
| mysql         |  0.000002369284 |
+---------------+-----------------+
4 rows in set (0.58 sec)

查询表的磁盘空间

以下 4.x 版本,需要使用 sys 租户,在 oceanbase 库中,查询指定 table 的磁盘占用。

  • **4.2.1 BPX < 4.2.1 BP9 **
  • 4.2.2
  • 4.3.x < 4.3.2

需要在 SQL 中填写 tenant_id = xxx,如果不加 database_name = 'xxx' AND table_name = 'xxx' 查询出的结果包含。

sql 复制代码
SELECT /*+ query_timeout(30000000) */ 
    a.TENANT_ID,
    a.DATABASE_NAME,
    a.TABLE_NAME,
    a.TABLE_ID,
    sum(CASE WHEN b.nested_offset = 0
        THEN IFNULL(b.data_block_count + b.index_block_count + b.linked_block_count, 0) * 2 * 1024 * 1024
        ELSE IFNULL(b.size, 0) END) / 1024 / 1024 /1024 AS data_size_in_GB
FROM CDB_OB_TABLE_LOCATIONS a
INNER JOIN __all_virtual_table_mgr b
      ON a.svr_ip = b.svr_ip
      AND a.svr_port = b.svr_port
      AND a.tenant_id = b.tenant_id
      AND a.LS_ID = b.LS_ID
      AND a.TABLET_ID = b.TABLET_ID
      AND a.role = 'LEADER'
      AND a.tenant_id = xxx
      AND b.table_type >= 10
      AND b.size > 0
-- WHERE database_name = 'xxx' AND table_name = 'xxx'
GROUP BY a.TABLE_ID;

+-----------+---------------+------------+----------+-----------------+
| TENANT_ID | DATABASE_NAME | TABLE_NAME | TABLE_ID | data_size_in_GB |
+-----------+---------------+------------+----------+-----------------+
|      1002 | test          | t1         |   500024 |  0.000000458210 |
+-----------+---------------+------------+----------+-----------------+
1 row in set (0.66 sec)

以下版本,推荐使用下面这种更高性能查询方式。

  • 4.2.1 BPX >= 4.2.1 BP9
  • 4.2.x >= 4.2.3
  • 4.3.x >= 4.3.2

这里也有必要多解释一下下面这条 SQL 中的 occupy_size 和 required_size。

  • occupy_size:可以理解成 data_size,表示压缩后的数据量大小。比如 2 GB 数据压缩成了 1 MB,那么这个数据的 occupy_size 就是 1 MB。
  • required_size:可以理解成 used_size,表示实际给数据分配的空间。比如 2G 数据压缩成了 1 MB,然后占用了一个宏块(一个宏块的默认大小 2 MB),那么这个数据的 required_size = 2 MB。
sql 复制代码
-- 查普通用户表(非系统表)
SELECT atnt.tenant_id AS TENANT_ID,
       avttl.table_id AS TABLE_ID,
       atnt.tenant_name AS TENANT_NAME,
       ad.database_name AS DATABASE_NAME,
       avt.table_name AS TABLE_NAME,
       sum(avtps.occupy_size) / 1024 / 1024 /1024 AS OCCUPY_SIZE_IN_GB,
       sum(avtps.required_size) / 1024 / 1024 /1024 AS REQUIRED_SIZE_IN_GB
FROM oceanbase.__all_virtual_tablet_pointer_status avtps
      INNER JOIN oceanbase.__all_virtual_tablet_to_ls avttl
            ON avttl.tenant_id = avtps.tenant_id
            AND avttl.tablet_id = avtps.tablet_id
      INNER JOIN oceanbase.__all_tenant atnt
            ON atnt.tenant_id = avttl.tenant_id
      INNER JOIN oceanbase.__all_virtual_table avt
            ON avt.tenant_id = avttl.tenant_id
            AND avt.table_id = avttl.table_id
      INNER JOIN oceanbase.__all_virtual_database ad
            ON ad.tenant_id = atnt.tenant_id
            AND ad.database_id = avt.database_id
      INNER JOIN oceanbase.__all_virtual_ls_meta_table avlmt
            ON avtps.tenant_id = avlmt.tenant_id
            AND avtps.ls_id = avlmt.ls_id
            AND avtps.svr_ip = avlmt.svr_ip
            AND avtps.svr_port = avlmt.svr_port
            AND avlmt.role = 1
WHERE atnt.tenant_id = 1002 AND database_name = 'test' AND table_name = 't2'
GROUP BY tenant_id,
         table_id
ORDER BY tenant_id,
         table_id
         \G
*************************** 1. row ***************************
          TENANT_ID: 1002
           TABLE_ID: 500024
        TENANT_NAME: mysql
      DATABASE_NAME: test
         TABLE_NAME: t1
  OCCUPY_SIZE_IN_GB: 0.000000458210 -- 数据压缩后的真实大小
REQUIRED_SIZE_IN_GB: 0.000003814697 -- 4 MB,实际占用了两个宏块
1 row in set (0.32 sec)

What's more ?

从 4.3.4 版本开始,开始支持使用标准 CDB 视图查询空间占用。还是需要使用 sys 租户,在 oceanbase 库中查询。

sql 复制代码
create table t1 (a int) ;
Query OK, 0 rows affected (0.278 sec)

select * from CDB_OB_TABLE_SPACE_USAGE\G
*************************** 1. row ***************************
    TENANT_ID: 1002
     TABLE_ID: 500024
  TENANT_NAME: mysql
DATABASE_NAME: test
   TABLE_NAME: t1
  OCCUPY_SIZE: 492
REQUIRED_SIZE: 4096
1 row in set (0.52 sec)
sql 复制代码
select * from CDB_OB_SERVER_SPACE_USAGE\G
*************************** 1. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Clog Data
 DATA_BYTES: 1677562658
USAGE_BYTES: 1677562658
*************************** 2. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Index Data
 DATA_BYTES: 1801
USAGE_BYTES: 16384
*************************** 3. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Meta Data
 DATA_BYTES: 17129472
USAGE_BYTES: 17129472
*************************** 4. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Slog Data
 DATA_BYTES: 16629760
USAGE_BYTES: 16629760
*************************** 5. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Table Data
 DATA_BYTES: 2012
USAGE_BYTES: 16384
*************************** 6. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
  SERVER_IP: 11.158.31.20
SERVER_PORT: 22602
 SPACE_TYPE: Tmp Data
 DATA_BYTES: 0
USAGE_BYTES: 0
sql 复制代码
obclient> select * from CDB_OB_SPACE_USAGE\G
*************************** 1. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
   ENDPOINT: NULL
       PATH: NULL
 SPACE_TYPE: Clog Data
USAGE_BYTES: 1677328015
*************************** 2. row ***************************
  TENANT_ID: 1
TENANT_NAME: sys
   ENDPOINT: NULL
       PATH: NULL
 SPACE_TYPE: Local Data
USAGE_BYTES: 67760128

附录

最后附上本文中出现的一些系统表的简单介绍:

  • __all_virtual_table_mgr
    • 用于通过 size 字段,查询所有 sstable、memtable 的 occupy_size。
    • 表名中带 virtual 字样的都是虚拟表,查询时实时构建。查这张表是准的,但可能比较慢。
  • __all_virtual_tablet_meta_table
    • 查询到的 occupy_size,required_size 是基线 sstable 的大小。
    • 只展示基线、多版本基线的大小(没有转储 sstable 的数据,和其他表的数据量对不上是符合预期的)。
  • __all_virtual_tablet_pointer_status
    • 查询所有 tablet 相关的信息
      • occupy_size:tablet 的 occupy_size
      • required_size:tablet 的 required_size
  • __all_space_usage
    • 实体表,定时任务,定时更新。
    • 展示每个 server 上的每个租户不同类型的空间占用信息。
    • tenant file data : 租户下所有 tablet 的 occupy_size 总和。

💌

老纪的技术唠嗑局 不仅希望能持续给大家带来有价值的技术分享,也希望能和大家一起为开源社区贡献力量。如果你对 OceanBase 开源社区认可,点亮一颗小星星 ✨ 吧!你的每一个Star,都是我们努力的动力~💕
https://github.com/oceanbase/oceanbase