把 OceanBase 4.4 接进第三方客户端:15 个面板里 12 个真正能用,剩下的卡在哪

先交代清楚:我们在做一个 MIT 协议的开源数据库客户端,OceanBase 是我们连真实实例测过的数据库之一。下面全是我们自己踩出来的记录,包括一个我们自己写错的地方。不是评测 OceanBase,是把一个外部工具接进来的时候会遇到什么。

测试环境

项 值
镜像 4.4.2-lts,MODE=mini
version() 5.7.25-OceanBase_CE-v4.4.2.1
走的驱动 MySQL 协议
对照 同一轮里还测了 MySQL 26.7.0

15 个功能面,14 个能返回不报错,但只有 12 个真正给出有用的东西。差的那两个不是崩,是答了等于没答。

一、健康检查是唯一的硬失败

租户里根本没有 performance_schema 这个库:

ERROR 1049 (42000): Unknown database 'performance_schema'

同一轮测试里 MySQL 26.7.0 的健康检查是过的,所以这一条是 OceanBase 这边的差异,不是我们的连接问题。

这件事有个副作用,在你点开任何面板之前就能看见:顶部状态徽章显示「Slow」而不是「Online」。这里容易误会——那个徽章不是延迟指标,它只看健康请求成功没成功。而健康检查恰好是这个引擎拒绝的那一个。所以徽章写着 Slow,实际查询快得很。

二、所有体积读数都是 0 B

表、索引、库、存储,四个地方的体积全是 0 B。原因在 information_schema.TABLES:

DATA_LENGTH  = 0
INDEX_LENGTH = 0

不是我们没读,是读回来就是 0。

存储统计那一栏还有个更有意思的东西:会列出一行 InnoDB,内容是 ibdata1:12M:autoextend,而它的大小读数是 N/A。OceanBase 为了兼容性伪造了 innodb_data_file_path 这个变量,但后面并没有这么一个文件。第一次看到的时候我们以为自己解析错了。

三、行数是对的,但要先 ANALYZE,而且写法有讲究

行数没问题——跑过 ANALYZE TABLE 之后,2000 行的表读出来就是 2000。

但必须用 MySQL 模式的写法。Oracle 模式那句会被直接拒绝:

ANALYZE TABLE t COMPUTE STATISTICS;
→ ERROR 1235

如果你的工具里写死了 Oracle 模式的语句,这里会静默地拿不到统计信息,然后你看到的行数就是 0,很容易归到「工具不支持」上去。

四、外键会被强制执行,但不建索引

外键是真的生效的——插一条孤儿记录会被拒:

ERROR 1452

但是不会自动建配套索引。所以同一份表结构,在 MySQL 和在 OceanBase 上,索引数量对不上。做结构对比或者迁移校验的时候这一条会咬人。

五、对象浏览器很干净,这一点比预想的好

2 张用户表,对象浏览器里就是 2 个对象。

我们原本担心会被系统对象淹掉——OceanBase 自己有 860 + 70 + 18 个目录对象。结果它们全被标成 SYSTEM TABLE 或 SYSTEM VIEW,我们按 TABLE_SCHEMA 和 TABLE_TYPE = 'BASE TABLE' 过滤,两个条件都不放它们进来。这块不用额外处理。

取消查询是真取消。Explain 是真的只描述不执行,返回一个 11 行的 ASCII 计划,带 EST.ROWS 列。

六、登录要连业务租户,不是 sys

MODE=mini 会建一个叫 test 的用户租户,登录名是 root@test。

用 sys 租户连进去会看到九个库,里面混着 Oracle 模式的产物:LBACSYS、ORAAUDITOR、SYS、ocs、sys_external_tbs。业务租户里没有这些。如果你是拿 sys 测的,看到的东西跟你应用实际看到的不是一回事。

七、我们自己写错的一处

慢查询面板一开始读出来是 0 行。看上去像「这个库没有慢查询」,其实是源根本读不了——租户没有 performance_schema,那句查询报的就是上面那个 ERROR 1049。

我们的代码把这个错误吞掉了,然后给面板填了个 0。这是个编出来的数字,比空白更糟:空白你知道自己没拿到,0 会让你以为拿到了。

已经改掉了,现在直接把租户返回的 ERROR 1049 原样显示出来。写工具的时候这类地方值得回头查一遍——读不到和读到 0,在界面上必须长得不一样。

想请教社区两件事

  1. 租户里没有 performance_schema 是 4.4 的设计,还是我们 MODE=mini 这个起法的问题?正式部署的用户租户里有吗?
  2. 体积统计有没有别的读法?information_schema.TABLES 这条路是 0,但 OceanBase 自己肯定知道真实占用,有没有推荐查的视图?

如果你们也把第三方工具接过 OceanBase,很想知道你们在哪些地方卡住过。上面每一条都是在 4.4.2-lts 上跑出来的,版本不同结论可能不一样。

3 个赞
  1. performance_schema好像一直就是没有的
  2. 至少mysql租户里information_schema.tables里DATA_LENGTH和INDEX_LENGTH是有正常值记录的,不知道你怎么查的
4 个赞

谢谢回复,两点分开说。

第一点我们同意,帖子里写的也是这个:租户里没有 performance_schema。我们当时不确定这是 4.4 的设计,还是 MODE=mini 这个起法带来的,所以在文末当成问题问了出来。你这句算是把它确认了。

第二点正是我们想请你帮着看的。先把实际跑的语句贴出来,省得互相猜:

SELECT TABLE_NAME, TABLE_ROWS, DATA_LENGTH, INDEX_LENGTH
FROM information_schema.TABLES
WHERE TABLE_SCHEMA = ? AND TABLE_TYPE = ‘BASE TABLE’;

有一点可能是关键:TABLE_ROWS 和 DATA_LENGTH 是同一条查询、同一行里取回来的。跑完 ANALYZE TABLE 之后,同一行的 TABLE_ROWS 读出来是 2000,是对的;而同一行的 DATA_LENGTH 是 0。所以这看起来不像是我们漏跑了 ANALYZE,也不像是语句写错了,否则行数也该是 0 才对。

我们这边的环境:OceanBase CE 4.4.2-lts,docker 里用 MODE=mini 起的,连的是业务租户 root@test(MySQL 模式),version() 返回 5.7.25-OceanBase_CE-v4.4.2.1。

顺便说一句,这一类坑我们自己栽过。在 StarRocks 上 INDEX_LENGTH 返回的是 NULL 而不是 0,我们在 SQL 里做 DATA_LENGTH + INDEX_LENGTH,NULL 把整个和污染成 NULL,于是每张表都显示 0 B,我们还一度以为是引擎的问题。那是我们自己的 bug,9 月 16 日改成 COALESCE(INDEX_LENGTH, 0) 修掉了。不过上面这条查询取的是原始列,不做加法,所以不是同一个问题。

想请教:你那边是哪个版本、怎么部署的?正式部署的用户租户里是有值的吗?如果这是环境差异,我们想把话说准,也会把帖子改过来。

4 个赞

目前是4.2.5 , OCP标准部署的,这个mode=mini没见过不知道是什么情况,之前2.X, 3.X一路用过来DATA_LENGTH + INDEX_LENGTH应该都是有的,OB里DATA_FREE是NULL的,不能用,你这个DATA_LENGTH 是0我怀疑是2000行太少了,要不多写一点看看?写个100w行看看DATA_LENGTH 有没有值?

4 个赞

按你的建议又测了一遍,结论是你说得对,我们帖子里那条要改。

环境和之前一样:4.4.2-lts,MODE=mini,连的是 root@test。

  1. 2048 行,ANALYZE 之后:TABLE_ROWS=2048,DATA_LENGTH=0。
  2. 加到 1048576 行,ANALYZE 之后:DATA_LENGTH=6291456,正好 3 个 2MB。这一步没有手动合并,应该是数据量大了自动转储到磁盘了。
  3. 另建一张 2048 行的表,在 sys 租户执行 ALTER SYSTEM MAJOR FREEZE TENANT=ALL,等合并完成后再 ANALYZE:2048 行的表 DATA_LENGTH=2097152,100 万行那张也变成了 2097152。我们的测试数据每行内容都一样,压缩率很高,看起来是大合并后压缩了。

所以 0 并不是读不到体积。看起来数据还在 MemTable 里、没落盘成宏块之前就是 0,转储或合并之后按 2MB 宏块计算。我们的测试表小,又是刚写进去就查,正好踩在这个点上。你那边 4.2.5 是 OCP 部署的正式库,数据一般早就合并过,自然一直有值。

我们会把帖子里「体积读数全是 0 B」这一条改成上面的结论。谢谢指点。

2 个赞