OceanBase 数据查询问题

【 使用环境 】生产环境
【 ob 组件 】observer
【 使用版本 】4.3.5.1
【问题描述】SQL查询性能问题
【复现路径】

  1. SQL语句
EXPLAIN select
        s.id,
        s.session_name,
        (
        select
                r2.chat_mate
        from
                reply r2
        inner join message m2 on
                r2.message_id = m2.id
        where
                m2.session_id = s.id
        order by
                r2.update_time desc
        limit 1 ) as chat_mate,
        s.create_time,
        s.update_time
from
        session s
where
        s.user_id = 1948235
        and s.app_id = 'com.cnpc.kllm.cost.chat.public'
        and s.update_time >= DATE_SUB(NOW(), interval 90 day)
order by
        s.update_time desc,
        s.create_time desc
limit 20;
  1. 生成环境执行过程
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                         |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ==================================================================================================                                                                 |
| |ID|OPERATOR                                |NAME                          |EST.ROWS|EST.TIME(us)|                                                                 |
| --------------------------------------------------------------------------------------------------                                                                 |
| |0 |SUBPLAN FILTER                          |                              |20      |20954546    |                                                                 |
| |1 |├─PX COORDINATOR                        |                              |20      |311         |                                                                 |
| |2 |│ └─EXCHANGE OUT DISTR                  |:EX10000                      |20      |290         |                                                                 |
| |3 |│   └─TOP-N SORT                        |                              |20      |243         |                                                                 |
| |4 |│     └─TABLE RANGE SCAN                |s(session_user_id_idx,Reverse)|21      |236         |                                                                 |
| |5 |└─PX COORDINATOR                        |                              |1       |1047314     |                                                                 |
| |6 |  └─EXCHANGE OUT DISTR                  |:EX20001                      |1       |1047314     |                                                                 |
| |7 |    └─TOP-N SORT                        |                              |1       |1047313     |                                                                 |
| |8 |      └─NESTED-LOOP JOIN                |                              |3       |1047313     |                                                                 |
| |9 |        ├─EXCHANGE IN DISTR             |                              |26769   |67408       |                                                                 |
| |10|        │ └─EXCHANGE OUT DISTR (BC2HOST)|:EX20000                      |26769   |46839       |                                                                 |
| |11|        │   └─COLUMN TABLE FULL SCAN    |r2                            |26769   |613         |                                                                 |
| |12|        └─COLUMN TABLE GET              |m2                            |1       |36          |                                                                 |
| ==================================================================================================                                                                 |
| Outputs & filters:                                                                                                                                                 |
| -------------------------------------                                                                                                                              |
|   0 - output([s.id], [s.session_name], [subquery(1)], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                   |
|       exec_params_([s.id(:0)]), onetime_exprs_(nil), init_plan_idxs_(nil), use_batch=false                                                                         |
|   1 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|   2 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|       is_single, dop=1                                                                                                                                             |
|   3 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|       sort_keys([s.update_time, DESC], [s.create_time, DESC]), topn(20), prefix_pos(1)                                                                             |
|   4 - output([s.id], [s.update_time], [s.session_name], [s.create_time]), filter([s.is_deleted = 0]), rowset=256                                                   |
|       access([s.id], [s.is_deleted], [s.update_time], [s.session_name], [s.create_time]), partitions(p0)                                                           |
|       is_index_back=true, is_global_index=false, filter_before_indexback[false],                                                                                   |
|       range_key([s.user_id], [s.app_id], [s.update_time], [s.id]), range(1948235,com.cnpc.kllm.cost.chat.public,2026-02-20 09:22:18.000000,MIN ; 1948235,          |
|       com.cnpc.kllm.cost.chat.public,MAX,MAX),                                                                                                                     |
|       range_cond([s.user_id = 1948235], [s.app_id = 'com.cnpc.kllm.cost.chat.public'], [s.update_time >= date_sub(current_timestamp(), cast(90, VARCHAR(1048576)), |
|        4)])                                                                                                                                                        |
|   5 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|   6 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|       is_single, dop=1                                                                                                                                             |
|   7 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|       sort_keys([r2.update_time, DESC]), topn(1)                                                                                                                   |
|   8 - output([r2.chat_mate], [r2.update_time]), filter(nil), rowset=256                                                                                            |
|       conds(nil), nl_params_([r2.message_id(:1)]), use_batch=false                                                                                                 |
|   9 - output([r2.chat_mate], [r2.update_time], [r2.message_id]), filter(nil), rowset=256                                                                           |
|  10 - output([r2.chat_mate], [r2.update_time], [r2.message_id]), filter(nil), rowset=256                                                                           |
|       is_single, dop=1                                                                                                                                             |
|  11 - output([r2.message_id], [r2.chat_mate], [r2.update_time]), filter(nil), rowset=256                                                                           |
|       access([r2.message_id], [r2.chat_mate], [r2.update_time]), partitions(p0)                                                                                    |
|       is_index_back=false, is_global_index=false,                                                                                                                  |
|       range_key([r2.id]), range(MIN ; MAX)always true                                                                                                              |
|  12 - output(nil), filter([m2.session_id = :0]), rowset=256                                                                                                        |
|       access([m2.session_id]), partitions(p0)                                                                                                                      |
|       is_index_back=false, is_global_index=false, filter_before_indexback[false],                                                                                  |
|       range_key([m2.id]), range(MIN ; MAX),                                                                                                                        |
|       range_cond([:1 = m2.id])                                                                                                                                     |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
52 rows in set (0.024 sec)
  1. SQL语句
EXPLAIN select
        s.id,
        s.session_name,
        (
        select
                r2.chat_mate
        from
               message m2 
        inner join reply r2 on
                m2.session_id = s.id
        where
               r2.message_id = m2.id 
        order by
                r2.update_time desc
        limit 1 ) as chat_mate,
        s.create_time,
        s.update_time
from
        session s
where
        s.user_id = 1948235
        and s.app_id = 'com.cnpc.kllm.cost.chat.public'
        and s.update_time >= DATE_SUB(NOW(), interval 90 day)
order by
        s.update_time desc,
        s.create_time desc
limit 20;
  1. 执行过程
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                                                                         |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| ==================================================================================================                                                                 |
| |ID|OPERATOR                                |NAME                          |EST.ROWS|EST.TIME(us)|                                                                 |
| --------------------------------------------------------------------------------------------------                                                                 |
| |0 |SUBPLAN FILTER                          |                              |20      |10273       |                                                                 |
| |1 |├─PX COORDINATOR                        |                              |20      |263         |                                                                 |
| |2 |│ └─EXCHANGE OUT DISTR                  |:EX10000                      |20      |242         |                                                                 |
| |3 |│   └─TOP-N SORT                        |                              |20      |195         |                                                                 |
| |4 |│     └─TABLE RANGE SCAN                |s(session_user_id_idx,Reverse)|21      |189         |                                                                 |
| |5 |└─PX COORDINATOR                        |                              |1       |103         |                                                                 |
| |6 |  └─EXCHANGE OUT DISTR                  |:EX20001                      |1       |102         |                                                                 |
| |7 |    └─TOP-N SORT                        |                              |1       |101         |                                                                 |
| |8 |      └─NESTED-LOOP JOIN                |                              |3       |101         |                                                                 |
| |9 |        ├─EXCHANGE IN DISTR             |                              |2       |21          |                                                                 |
| |10|        │ └─EXCHANGE OUT DISTR (BC2HOST)|:EX20000                      |2       |20          |                                                                 |
| |11|        │   └─TABLE RANGE SCAN          |m2(session_id_IDX)            |2       |18          |                                                                 |
| |12|        └─TABLE RANGE SCAN              |r2(reply_message_id_IDX)      |2       |40          |                                                                 |
| ==================================================================================================                                                                 |
| Outputs & filters:                                                                                                                                                 |
| -------------------------------------                                                                                                                              |
|   0 - output([s.id], [s.session_name], [subquery(1)], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                   |
|       exec_params_([s.id(:0)]), onetime_exprs_(nil), init_plan_idxs_(nil), use_batch=false                                                                         |
|   1 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|   2 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|       is_single, dop=1                                                                                                                                             |
|   3 - output([s.id], [s.session_name], [s.create_time], [s.update_time]), filter(nil), rowset=256                                                                  |
|       sort_keys([s.update_time, DESC], [s.create_time, DESC]), topn(20), prefix_pos(1)                                                                             |
|   4 - output([s.id], [s.update_time], [s.session_name], [s.create_time]), filter(nil), rowset=256                                                                  |
|       access([s.id], [s.update_time], [s.session_name], [s.create_time]), partitions(p0)                                                                           |
|       is_index_back=true, is_global_index=false,                                                                                                                   |
|       range_key([s.user_id], [s.app_id], [s.update_time], [s.id]), range(1948235,com.cnpc.kllm.cost.chat.public,2026-02-20 09:41:35.000000,MIN ; 1948235,          |
|       com.cnpc.kllm.cost.chat.public,MAX,MAX),                                                                                                                     |
|       range_cond([s.user_id = 1948235], [s.app_id = 'com.cnpc.kllm.cost.chat.public'], [s.update_time >= date_sub(current_timestamp(), cast(90, VARCHAR(1048576)), |
|        4)])                                                                                                                                                        |
|   5 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|   6 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|       is_single, dop=1                                                                                                                                             |
|   7 - output([r2.chat_mate]), filter(nil), rowset=256                                                                                                              |
|       sort_keys([r2.update_time, DESC]), topn(1)                                                                                                                   |
|   8 - output([r2.chat_mate], [r2.update_time]), filter(nil), rowset=256                                                                                            |
|       conds(nil), nl_params_([m2.id(:1)]), use_batch=false                                                                                                         |
|   9 - output([m2.id]), filter(nil), rowset=256                                                                                                                     |
|  10 - output([m2.id]), filter(nil), rowset=256                                                                                                                     |
|       is_single, dop=1                                                                                                                                             |
|  11 - output([m2.id]), filter(nil), rowset=256                                                                                                                     |
|       access([m2.id]), partitions(p0)                                                                                                                              |
|       is_index_back=false, is_global_index=false,                                                                                                                  |
|       range_key([m2.session_id], [m2.id]), range(MIN,MIN ; MAX,MAX)always true,                                                                                    |
|       range_cond([m2.session_id = :0])                                                                                                                             |
|  12 - output([r2.chat_mate], [r2.update_time]), filter(nil), rowset=256                                                                                            |
|       access([r2.id], [r2.chat_mate], [r2.update_time]), partitions(p0)                                                                                            |
|       is_index_back=true, is_global_index=false,                                                                                                                   |
|       range_key([r2.message_id], [r2.id]), range(MIN ; MAX),                                                                                                       |
|       range_cond([r2.message_id = :1])                                                                                                                             |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
  1. 检查了一下内连接中两张表的数据量(reply表数据大于message表),两个SQL只是将表位置互换第二个SQL查询可以命中索引查询很快。

【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):

【SOP系列 22 】——故障诊断第一步(自助诊断和诊断信息收集)

【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手] 即可召唤小助手,欢迎试用!

2 个赞

您好,您提的这个技术问题可能牵涉到 OceanBase 企业版范围内的功能细节;针对此类问题,建议你通过以下方式寻求帮助:

  1. 如你所在的企业客户已签署 OceanBase 企业版销售合同,请你联系客户经理;

  2. 如你所在的企业客户尚未签署 OceanBase 企业版销售合同,你可通过OceanBase官网商务咨询页面留下你的联系方式,OceanBase企业版的业务顾问会在一个工作日内与你联系。

另外,我们欢迎你使用社区版,并在论坛/社群中分享你对社区版本的想法、经验和问题,与其他社区成员共同交流。

(小助手的答复已结束,如未能解决您的问题,请继续提问并等待其他同学的回复,谢谢!)

2 个赞

SHOW VARIABLES like ‘version_comment’; 具体版本信息 查一下 要不然会被误判到商业版 如果是社区版 使用obdiag 搜一下plan_monitor信息
obdiag gather plan_monitor --trace_id YB420BA2D99B-0005EBBFC45D5A00-0-0
–env host=xx.xx.xx.xx --env port=2881 --env user=root@test --env password=*** --env database=test
https://www.oceanbase.com/docs/common-obdiag-cn-1000000005726947


第一个看着是列存 没有命中索引 左支表是全表扫的 建议使用obdiag在收集一下信息 看看

1 个赞

好的,我基于工具采集一下
版本信息是:OceanBase_CE 4.3.5.1 (r101000042025031818-b6d5706eb3d2c5f501c7fa646ddbf32f3dc87069) (Built Mar 18 2025 18:12:30)
这三张表都是列存储的

1 个赞

这子查询的层次有点猛啊

我这边是需要提供一下obdiag 拉出来的数据吧

收集完会有一个收集的压缩包 你发一下就好了

obdiag_gather_pack_20260521103633.zip (213.5 KB)
好的,麻烦看一下吧

这样查一下 重新收集一下 信息不全 select /+monitor/ s.id, s.session_name, ( select r2.chat_mate from message m2 inner join reply r2 on r2.message_id = m2.id where m2.session_id = s.id order by r2.update_time desc limit 1 ) as chat_mate, s.create_time, s.update_time from session s where s.user_id = 1948235 and s.app_id = ‘com.cnpc.kllm.cost.chat.public’ and s.update_time >= DATE_SUB(NOW(), interval 90 day) order by s.update_time desc, s.create_time desc limit 20

obdiag_gather_pack_20260521143359.zip (221.0 KB)

你好,这是最新执行内容,麻烦看一下吧