【 使用环境 】生产环境
【 ob 组件 】observer
【 使用版本 】4.3.5.1
【问题描述】SQL查询性能问题
【复现路径】
- 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;
- 生成环境执行过程
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 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)
- 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;
- 执行过程
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| 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]) |
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
- 检查了一下内连接中两张表的数据量(reply表数据大于message表),两个SQL只是将表位置互换第二个SQL查询可以命中索引查询很快。
【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):
【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手] 即可召唤小助手,欢迎试用!
