
作者:郑增权,爱可生 DBA 团队成员,OceanBase 和 MySQL 数据库技术爱好者。
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。
本文约 2500 字,预计阅读需要 8 分钟。

1. 背景
1.1 客户疑问
某个租户一直在频繁的转储,有什么方法可以找到是哪些 SQL 语句导致的?
1.2 环境信息
OB V 4.2.1.10
2. 基础知识
2.1 LSM Tree 存储架构

OceanBase 数据库的租户内部的内存总体上分为两类: 可伸缩内存(KVCache 等) 不可伸缩内存(MemStore 等)。 写数据( DML 操作)时首先会写入内存区(MemStore)。 memstore_limit_percentage :用于设置租户使用 MemStore 的内存占其总可用内存的百分比,默认值是 50%。
2.2 MemTable 中的数据结构

2.2.1 两种数据结构的特点
我们可以认为 MemStore 是一个容器,容器内部由多个 MemTable 组成。 一个分区对应一个 MemTable(非分区表对应一个 MemTable,分区表则对应多个 MemTable)。 在 插入/更新/删除 数据时,根据数据涉及的范围选择 HashTable 或者 BTree 找到或更新对应的数据。
HashTable 的优点:插入一行数据的时候,需要先检查此行数据是否已经存在,当且仅当数据不存在时才能插入,检查冲突时,用 Hashtable 要比 BTree 快。 事务在插入或更新一行数据的时候,需要找到此行并对其进行上锁,防止其它事务修改此行,OceanBase 数据库的行锁放在行头数据结构中,需要先找到它,才能上锁。
HashTable 的缺点:不适合对范围查询使用 HashTable。
BTree 的优点:范围查找时,由于 BTree 中的数据都是有序的,因此只需要搜索局部的数据就可以了。
BTree 的缺点:单行的查找,也需要进行大量的主键比较,从根结点找到叶子结点,而主键比较性能是较差的,因此理论上性能比 HashTable 慢很多。
2.3 Mini Compaction(转储)
转储(Mini Compaction 或称之为 Mini Merge):当租户的 MemTable 大小超过 freeze_trigger_percentage (默认值 20%)的值时,对内存中的数据进行冻结(Freeze)并转储为 Mini SSTable ,然后统一释放这些 MemTable 占用的内存。 转储是租户级别,而不是集群级别。 转储是 OBServer 级别的,每个 OBServer 根据租户在该节点的 MemStore 使用情况单独触发转储。 自动转储时,会将 MemStore 中所有分区的 MemTable 均冻结和转储,而不是针对某个分区。
3. 实验
3.1 建表并插入数据
往 test_table
表插入 10 万条数据。
MySQL [evan]> show createtable test_table;
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | CreateTable |
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| test_table | CREATETABLE`test_table` (
`id`bigint(20) NOTNULL AUTO_INCREMENT,
`name`varchar(50) DEFAULTNULL,
`create_time` datetime DEFAULTNULL,
PRIMARY KEY (`id`)
) AUTO_INCREMENT = 39998 AUTO_INCREMENT_MODE = 'ORDER'DEFAULTCHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 |
+------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1rowinset (0.01 sec)
MySQL [evan]> CALL insert_test_data();
往表 test_users
插入 1000 条数据。
-- Creating test_users table
CREATE TABLE test_users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL,
register_date DATETIME NOT NULL
);
CALL insert_test_users();
3.2 业务租户执行转储
MySQL [allen]> alter system minor freeze;
Query OK, 0 rows affected (0.11 sec)
3.3 查看正在转储的表的 tablet_id
tablet_id
为 49401、49402 的是 OB 内部事务状态表,需要排除,无需关注。tablet_id很短的一般都是系统的表,无需关注。 很长的可能是索引之类的,可以查看所属的表是哪个。 我们主要关注业务表,业务表 table_id
一般是 6 位数。ACTION 为 MINI_MERGE:Mini Compaction,将 MemTable 转变成 Mini SSTable。 MACRO_BLOCK_COUNT:Compaction 宏块总数。
SQL 1:查看 1002 租户一天的转储情况,Compaction 宏块总数降序排序,取前 10 条结果。
MySQL [oceanbase]> SELECT SVR_IP,TENANT_ID,LS_ID,TABLET_ID,ACTION,MACRO_BLOCK_COUNT,COMPACTION_SCN,START_TIME,END_TIME FROM oceanbase.GV$OB_MERGE_INFO WHERE TENANT_ID = 1002AND LS_ID <> 1AND tablet_id notin ( 49401,49402) ANDACTION='MINI_MERGE'AND START_TIME LIKE'2025-06-26%'ORDERBY MACRO_BLOCK_COUNT DESCLIMIT10;
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| SVR_IP | TENANT_ID | LS_ID | TABLET_ID | ACTION | MACRO_BLOCK_COUNT | COMPACTION_SCN | START_TIME | END_TIME |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:24.317534 | 2025-06-26 22:33:24.544235 |
| 10.186.65.8 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:27.144210 | 2025-06-26 22:33:27.415615 |
| 10.186.65.9 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403793514050 | 2025-06-26 22:33:25.361842 | 2025-06-26 22:33:26.058388 |
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:23.916445 | 2025-06-26 21:36:23.967620 |
| 10.186.65.8 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:21.704055 | 2025-06-26 21:36:21.812143 |
| 10.186.65.9 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:23.889711 | 2025-06-26 21:36:24.165441 |
| 10.186.65.23 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:24.318647 | 2025-06-26 22:33:24.338969 |
| 10.186.65.8 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:27.190671 | 2025-06-26 22:33:27.195573 |
| 10.186.65.9 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:25.369246 | 2025-06-26 22:33:25.380798 |
| 10.186.65.23 | 1002 | 1003 | 200004 | MINI_MERGE | 0 | 1749261600449876665 | 2025-06-26 10:00:48.110727 | 2025-06-26 10:00:48.114597 |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
10 rows in set (0.14 sec)
按照涉及的宏块总数来看,200006 这个 tablet 对应的表对于 memstore 的占用是最高的。
SQL 2:查看 1002 租户最新的转储情况,取前 10 条结果。
MySQL [oceanbase]> SELECT SVR_IP,TENANT_ID,LS_ID,TABLET_ID,ACTION,MACRO_BLOCK_COUNT,COMPACTION_SCN,START_TIME,END_TIME FROM oceanbase.GV$OB_MERGE_INFO WHERE TENANT_ID = 1002AND LS_ID <> 1AND tablet_id notin (49401,49402) ANDACTION='MINI_MERGE'AND START_TIME LIKE'2025-06-26%'ORDERBY START_TIME DESCLIMIT10;
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| SVR_IP | TENANT_ID | LS_ID | TABLET_ID | ACTION | MACRO_BLOCK_COUNT | COMPACTION_SCN | START_TIME | END_TIME |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| 10.186.65.8 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:27.190671 | 2025-06-26 22:33:27.195573 |
| 10.186.65.8 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:27.144210 | 2025-06-26 22:33:27.415615 |
| 10.186.65.9 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:25.369246 | 2025-06-26 22:33:25.380798 |
| 10.186.65.9 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403793514050 | 2025-06-26 22:33:25.361842 | 2025-06-26 22:33:26.058388 |
| 10.186.65.23 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:24.318647 | 2025-06-26 22:33:24.338969 |
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:24.317534 | 2025-06-26 22:33:24.544235 |
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:23.916445 | 2025-06-26 21:36:23.967620 |
| 10.186.65.9 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:23.889711 | 2025-06-26 21:36:24.165441 |
| 10.186.65.8 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:21.704055 | 2025-06-26 21:36:21.812143 |
| 10.186.65.9 | 1002 | 1001 | 200001 | MINI_MERGE | 0 | 1 | 2025-06-26 10:03:21.758154 | 2025-06-26 10:03:21.850344 |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
10 rows in set (0.34 sec)
3.4 根据 tablet_id
查询表名
通过 sys 租户执行 SQL 。 CON_ID:是租户 id,请根据实际替换。 OWNER:数据库名称。 OBJECT_NAME:对象名称(表名)。 此处我们主要查询 tablet_id
为 200006 和 200007 对应的表。
SELECT CON_ID,OWNER,OBJECT_NAME,OBJECT_TYPE,SUBOBJECT_NAME, OBJECT_ID,DATA_OBJECT_ID from oceanbase.CDB_OBJECTS WHERE CON_ID = 1002 AND DATA_OBJECT_ID = '200006';
+--------+-------+-------------+-------------+----------------+-----------+----------------+
| CON_ID | OWNER | OBJECT_NAME | OBJECT_TYPE | SUBOBJECT_NAME | OBJECT_ID | DATA_OBJECT_ID |
+--------+-------+-------------+-------------+----------------+-----------+----------------+
| 1002 | evan | test_table | TABLE | NULL | 500012 | 200006 |
+--------+-------+-------------+-------------+----------------+-----------+----------------+
1 row in set (0.16 sec)
MySQL [oceanbase]> SELECT CON_ID,OWNER,OBJECT_NAME,OBJECT_TYPE,SUBOBJECT_NAME, OBJECT_ID,DATA_OBJECT_ID from oceanbase.CDB_OBJECTS WHERE CON_ID = 1002 AND DATA_OBJECT_ID = '200007';
+--------+-------+-------------+-------------+----------------+-----------+----------------+
| CON_ID | OWNER | OBJECT_NAME | OBJECT_TYPE | SUBOBJECT_NAME | OBJECT_ID | DATA_OBJECT_ID |
+--------+-------+-------------+-------------+----------------+-----------+----------------+
| 1002 | allen | test_users | TABLE | NULL | 500016 | 200007 |
+--------+-------+-------------+-------------+----------------+-----------+----------------+
1 row in set (0.09 sec)
3.5 查看两个表涉及的 DML 相关的 SQL
可以看到是前面执行的造数调用的存储过程的 SQL 语句。
-- test_table 表
MySQL [oceanbase]> select svr_ip,trace_id,sql_id,usec_to_time(request_time),query_sql from gv$ob_sql_audit where tenant_id =1002 and query_sql like 'insert%test_table%' or query_sql like 'INSERT%test_table%' or query_sql like 'delete%test_table%' or query_sql like 'DELETE%test_table%' or query_sql like 'update%test_table%' or query_sql like 'UPDATE%test_table%' order by elapsed_time desc limit 1;
+-------------+-----------------------------------+----------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| svr_ip | trace_id | sql_id | usec_to_time(request_time) | query_sql |
+-------------+-----------------------------------+----------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 10.186.65.9 | YB420ABA4109-000635FFFC8AF16E-0-0 | D0A0BE901EA6BFE0DA916255FFBF954B | 2025-06-26 22:33:28.006047 | INSERTINTO test_table (name, create_time)
VALUES (
CONCAT('user_', :0), -- Generates names like 'user_1', 'user_2', etc.
NOW() - INTERVAL FLOOR(RAND() * 365) DAY-- Random date within the last year
) |
+-------------+-----------------------------------+----------------------------------+----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row inset (0.35 sec)
-- test_users 表(同理,不做重复粘贴)
select svr_ip,trace_id,sql_id,usec_to_time(request_time),query_sql from gv$ob_sql_audit where tenant_id =1002 and query_sql like 'insert%test_users%' or query_sql like 'INSERT%test_users%' or query_sql like 'delete%test_users%' or query_sql like 'DELETE%test_users%' or query_sql like 'update%test_users%' or query_sql like 'UPDATE%test_users%' order by elapsed_time desc limit 1;
3.6 进一步验证语句的有效性
往 test_users
表再插入 20W 条数据。
MySQL [allen]> CALL insert_test_users();
Query OK, 1 row affected (9 min 8.23 sec)
3.7 再次查看 1002 租户一天的转储情况
可以看到 tablet 200007 涉及的宏块总数由 1 增长到 2 或者 3 了。
MySQL [oceanbase]> SELECT SVR_IP,TENANT_ID,LS_ID,TABLET_ID,ACTION,MACRO_BLOCK_COUNT,COMPACTION_SCN,START_TIME,END_TIME FROM oceanbase.GV$OB_MERGE_INFO WHERE TENANT_ID = 1002 AND LS_ID <> 1 AND tablet_id not in (49401,49402) AND ACTION='MINI_MERGE' AND START_TIME LIKE '2025-06-26%' ORDER BY MACRO_BLOCK_COUNT DESC LIMIT 10;
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| SVR_IP | TENANT_ID | LS_ID | TABLET_ID | ACTION | MACRO_BLOCK_COUNT | COMPACTION_SCN | START_TIME | END_TIME |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
| 10.186.65.23 | 1002 | 1003 | 200007 | MINI_MERGE | 3 | 1750949839751752853 | 2025-06-26 22:57:24.442409 | 2025-06-26 22:57:24.778592 |
| 10.186.65.8 | 1002 | 1003 | 200007 | MINI_MERGE | 3 | 1750949798303843049 | 2025-06-26 22:56:42.263684 | 2025-06-26 22:56:42.599886 |
| 10.186.65.9 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403793514050 | 2025-06-26 22:33:25.361842 | 2025-06-26 22:33:26.058388 |
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:24.317534 | 2025-06-26 22:33:24.544235 |
| 10.186.65.8 | 1002 | 1002 | 200006 | MINI_MERGE | 2 | 1750948403741623375 | 2025-06-26 22:33:27.144210 | 2025-06-26 22:33:27.415615 |
| 10.186.65.9 | 1002 | 1003 | 200007 | MINI_MERGE | 2 | 1750949784654232477 | 2025-06-26 22:56:25.246718 | 2025-06-26 22:56:26.265284 |
| 10.186.65.23 | 1002 | 1002 | 200006 | MINI_MERGE | 1 | 1750944980577137690 | 2025-06-26 21:36:23.916445 | 2025-06-26 21:36:23.967620 |
| 10.186.65.8 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750949932352151540 | 2025-06-26 22:59:32.283314 | 2025-06-26 22:59:32.365460 |
| 10.186.65.9 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750949932352151540 | 2025-06-26 22:59:25.293952 | 2025-06-26 22:59:25.648741 |
| 10.186.65.23 | 1002 | 1003 | 200007 | MINI_MERGE | 1 | 1750948403497631799 | 2025-06-26 22:33:24.318647 | 2025-06-26 22:33:24.338969 |
+--------------+-----------+-------+-----------+------------+-------------------+---------------------+----------------------------+----------------------------+
10 rows in set (0.30 sec)
4. 结论
租户若频繁转储,一般是由于 DML 操作导致,单纯的查询主要占用 KVCache 部分的内存,占用 MemStore 不大,自然也不会导致频繁的转储。 租户转储动作会产生对于宏块的变更,当转储时某个 tablet 涉及的宏块数量较大时,一般我们需要关注它对应的 DML 操作是否合理并采取对应的措施。
5. 参考资料
《MemTable》:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002014004 《GV$OB_MERGE_INFO》: https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000002014914
本文关键字:#OceanBase #热点表


✨ Github:https://github.com/actiontech/sqle
📚 文档:https://actiontech.github.io/sqle-docs/
💻 官网:https://opensource.actionsky.com/sqle/
👥 微信群:请添加小助手加入 ActionOpenSource
🔗 商业支持:https://www.actionsky.com/sqle





