【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】
【 使用版本 】
【问题描述】清晰明确描述问题
【复现路径】问题出现前后相关操作
【附件及日志】推荐使用OceanBase敏捷诊断工具obdiag收集诊断信息,详情参见链接(右键跳转查看):
https://ask.oceanbase.com/t/topic/35605619
【备注】基于 LLM 和开源文档 RAG 的论坛小助手已开放测试,在发帖时输入 [@论坛小助手 ] 即可召唤小助手,欢迎试用!
obloader导入一张销售流水数据表,目前针对1亿多数据量,半小时导入完成后,查询速度较慢,
建表语句
create table if not exists da_sale
(
change_date int comment "销售日期,
store_code varchar(40) comment "门店代码,
pdt_no varchar(40) comment "商品代码,
size varchar(40) comment "尺码,
qty int comment "销量,
price decimal(14,2) comment "实收价,
pricelist int comment "吊牌价,
is_groupbuy varchar(4) comment "是否团购,
amt decimal(14,2) comment "实收金额,
amt_list int comment "吊牌金额,
tot_qty int comment "累计销量,
change_month varchar(12)
);
create index idx_da_sale on da_sale(store_code,pdt_no,change_date)
主要针对下面2个场景
select count(*) from da_sale;
select * from da_sale limit 10;
这种情况下如何排查优化
1 个赞
论坛小助手
2024 年12 月 17 日 17:44
#3
根据您提供的信息,obloader 导入大量数据后查询性能下降,这可能是由于多种因素引起的。以下是一些可能的原因和优化建议:
1. 检查索引
2. 数据分布和分区
数据分布 :确保数据在各个节点上均匀分布。您可以使用 EXPLAIN
查看查询计划,确认数据是否均匀分布在各个节点上。
分区表 :对于大规模数据表,建议使用分区表来提高查询性能。例如,按 change_date
或 change_month
进行分区:CREATE TABLE da_sale (
change_date INT COMMENT '销售日期',
store_code VARCHAR(40) COMMENT '门店代码',
pdt_no VARCHAR(40) COMMENT '商品代码',
size VARCHAR(40) COMMENT '尺码',
qty INT COMMENT '销量',
price DECIMAL(14,2) COMMENT '实收价',
pricelist INT COMMENT '吊牌价',
is_groupbuy VARCHAR(4) COMMENT '是否团购',
amt DECIMAL(14,2) COMMENT '实收金额',
amt_list INT COMMENT '吊牌金额',
tot_qty INT COMMENT '累计销量',
change_month VARCHAR(12)
) PARTITION BY RANGE (change_date) (
PARTITION p0 VALUES LESS THAN (20230101),
PARTITION p1 VALUES LESS THAN (20230201),
PARTITION p2 VALUES LESS THAN (20230301),
-- 添加更多分区
);
3. 查询优化
4. 系统参数调整
内存和缓存 :检查系统参数,确保有足够的内存和缓存来支持查询。例如,调整 memory_limit
和 memory_limit_percentage
参数。
并行度 :增加查询的并行度可以提高查询性能。您可以调整 parallel_query
相关参数。
5. 合并操作
6. 日志和诊断
日志分析 :使用 obdiag
工具收集诊断信息,分析日志文件,查找可能的性能瓶颈。
全链路诊断 :如果问题仍然存在,可以使用全链路诊断机制,追踪 SQL 请求在数据库全链路过程中的执行情况,帮助快速定位问题。
7. 其他建议
硬件资源 :确保硬件资源(如 CPU、内存、磁盘 I/O)足够支持当前的查询负载。
数据预处理 :在导入数据前,可以对数据进行预处理,例如删除重复数据、优化数据格式等。
希望以上建议能帮助您优化查询性能。如果问题仍然存在,建议联系 OceanBase 的技术支持团队获取进一步的帮助。
更多信息请查看:
向量索引
使用 LOAD DATA 语句导入数据
OceanBase AP 核心特性
全链路追踪概述
OceanBase AP 概述
分布式执行和并行查询
SQL 调优典型场景和案例
obloader/obdumper
列存 FAQ
自适应合并
1 个赞
count计数查询直接超时,调整超时时间1分钟仍然失败,
分页limit10获取长达21s
1 个赞
论坛小助手
2024 年12 月 17 日 17:46
#5
根据您提供的信息,count
计数查询直接超时,即使调整超时时间到 1 分钟仍然失败,而 limit 10
查询也耗时较长。这表明查询性能存在严重问题。以下是一些详细的排查和优化建议:
1. 检查查询计划
2. 优化 count
查询
3. 优化 limit
查询
使用索引 :确保 limit
查询使用了合适的索引。例如,如果经常查询前 10 条记录,可以创建一个覆盖索引:CREATE INDEX idx_limit ON da_sale(store_code, pdt_no, change_date);
避免大偏移量 :如果 limit
查询涉及较大的偏移量,可以考虑使用子查询来优化:SELECT * FROM da_sale WHERE change_date IN (SELECT change_date FROM da_sale ORDER BY change_date LIMIT 10);
4. 调整系统参数
5. 数据分布和分区
数据分布 :确保数据在各个节点上均匀分布。您可以使用 EXPLAIN
查看查询计划,确认数据是否均匀分布在各个节点上。
分区表 :对于大规模数据表,建议使用分区表来提高查询性能。例如,按 change_date
或 change_month
进行分区:CREATE TABLE da_sale (
change_date INT COMMENT '销售日期',
store_code VARCHAR(40) COMMENT '门店代码',
pdt_no VARCHAR(40) COMMENT '商品代码',
size VARCHAR(40) COMMENT '尺码',
qty INT COMMENT '销量',
price DECIMAL(14,2) COMMENT '实收价',
pricelist INT COMMENT '吊牌价',
is_groupbuy VARCHAR(4) COMMENT '是否团购',
amt DECIMAL(14,2) COMMENT '实收金额',
amt_list INT COMMENT '吊牌金额',
tot_qty INT COMMENT '累计销量',
change_month VARCHAR(12)
) PARTITION BY RANGE (change_date) (
PARTITION p0 VALUES LESS THAN (20230101),
PARTITION p1 VALUES LESS THAN (20230201),
PARTITION p2 VALUES LESS THAN (20230301),
-- 添加更多分区
);
6. 合并操作
7. 日志和诊断
日志分析 :使用 obdiag
工具收集诊断信息,分析日志文件,查找可能的性能瓶颈。
全链路诊断 :如果问题仍然存在,可以使用全链路诊断机制,追踪 SQL 请求在数据库全链路过程中的执行情况,帮助快速定位问题。
8. 硬件资源
确保硬件资源 :确保硬件资源(如 CPU、内存、磁盘 I/O)足够支持当前的查询负载。
9. 统计信息
更新统计信息 :确保统计信息是最新的,这有助于优化器生成更优的执行计划。您可以运行:ANALYZE TABLE da_sale;
10. 联系技术支持
技术支持 :如果以上措施仍然无法解决问题,建议联系 OceanBase 的技术支持团队获取进一步的帮助。
希望以上建议能帮助您优化查询性能。如果问题仍然存在,建议联系 OceanBase 的技术支持团队获取更多帮助。
检索到的文档如下:
OceanBase 术语
GV$OB_SQL_AUDIT
集群管理 FAQ
分页查询
连接次序
ob_trx_idle_timeout
在您开始前
LIMIT
ob_query_switch_leader_retry_timeout
(小助手的答复已结束,如未能解决您的问题,请继续提问并等待其他同学的回复,谢谢!)
辞霜
2024 年12 月 17 日 17:49
#6
试试使用count(1) count*无法走索引的。
是否多次执行都慢呢,第一次硬解析sql会比较慢一些,
可以把你的详细sql和执行计划发出来看看。使用obdiag收集该sql信息
obdiag收集SQL性能问题信息
obdiag gather scene run --scene=observer.perf_sql --env “{db_connect=’-hxx -Pxx -uxx -pxx -Dxx’, trace_id=‘xx’}”
是的,count(*)直接超时,count(1)基本在毫秒级别,谢谢
2 个赞
辞霜
2024 年12 月 17 日 18:02
#9
第二条select * 把* 改为所有字段名称试试
2 个赞
目前可以了,count(1)查询后,后续性能都正常,可能主要是硬解析,没走索引导致
2 个赞
淇铭
2024 年12 月 18 日 10:09
#11
如果是obloader导入的数据 建议先手动收集一下 统计信息 在去查询数据
2 个赞
收集完成后,单表查询效率提升,最快的时候2s,针对2张表关联后做总量sum计算,长达20s
2 个赞
淇铭
2024 年12 月 18 日 13:40
#13
1、两个表结构发一下
2、explain extended sql 保存在文本里
3、 obdiag收集下
obdiag收集SQL性能问题信息
obdiag gather scene run --scene=observer.perf_sql --env “{db_connect=’-hxx -Pxx -uxx -pxx -Dxx’, trace_id=‘xx’}”
https://www.oceanbase.com/docs/common-obdiag-cn-1000000001768178
1 个赞
is_global_index=false是不是这个有关
2 个赞
淇铭
2024 年12 月 18 日 14:12
#16
1、把da_sale_imp2表结构 也发一下
2、select count(store_code) from da_store where region =‘A089’;你统计这个大概多少数据
3、explain extended select sum(qty) from da_sale_imp2 where store_code
in (select store_code from da_store where region =‘A089’); --保存在文本里
4、explain extended select sum(qty) from da_sale_imp2 dsi inner join (select store_code from da_store where region =‘A089’) ds on dsi.store_code=ds.store_code; 保存在文本里
5、select sum(qty) from da_sale_imp2 dsi inner join (select store_code from da_store where region =‘A089’) ds on dsi.store_code=ds.store_code;–执行一下这个语句 看看多长时间
6、obdiag尽量收集一下
obdiag收集SQL性能问题信息
obdiag gather scene run --scene=observer.perf_sql --env “{db_connect=’-hxx -Pxx -uxx -pxx -Dxx’, trace_id=‘xx’}”
https://www.oceanbase.com/docs/common-obdiag-cn-1000000001768178
CREATE TABLE da_sale_imp2
(
change_date
int(11) DEFAULT NULL COMMENT ‘销售日期’,
store_code
varchar(40) DEFAULT NULL COMMENT ‘门店代码’,
pdt_no
varchar(40) DEFAULT NULL COMMENT ‘商品代码’,
size
varchar(40) DEFAULT NULL COMMENT ‘尺码’,
qty
int(11) DEFAULT NULL COMMENT ‘销量’,
price
decimal(14,2) DEFAULT NULL COMMENT ‘实收价’,
pricelist
int(11) DEFAULT NULL COMMENT ‘吊牌价’,
is_groupbuy
varchar(4) DEFAULT NULL COMMENT ‘是否团购’,
amt
decimal(14,2) DEFAULT NULL COMMENT ‘实收金额’,
amt_list
int(11) DEFAULT NULL COMMENT ‘吊牌金额’,
tot_qty
int(11) DEFAULT NULL COMMENT ‘累计销量’,
change_month
varchar(12) DEFAULT NULL
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = ‘zstd_1.3.8’ REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0 WITH COLUMN GROUP(each column)
explain extended select sum(qty) from da_sale_imp2 where store_code
in (select store_code from da_store where region =‘A089’);
|ID|OPERATOR |NAME |EST.ROWS |EST.TIME(us)|
|0 |SCALAR GROUP BY | |1 |45447656 |
|1 |└─HASH RIGHT SEMI JOIN | |16761789 |45143864 |
|2 | ├─SUBPLAN SCAN |VIEW1 |978 |2600 |
|3 | │ └─TABLE RANGE SCAN |da_store(idx_da_store_01)|978 |2598 |
|4 | └─COLUMN TABLE FULL SCAN|da_sale_imp2 |159999999|2037933 |
Outputs & filters:
0 - output([T_FUN_SUM(da_sale_imp2.qty(0x7fbb8a039520))(0x7fbb8a038b90)]), filter(nil), rowset=256
group(nil), agg_func([T_FUN_SUM(da_sale_imp2.qty(0x7fbb8a039520))(0x7fbb8a038b90)])
1 - output([da_sale_imp2.qty(0x7fbb8a039520)]), filter(nil), rowset=256
equal_conds([da_sale_imp2.store_code(0x7fbb8a0384d0) = VIEW1.store_code(0x7fbb8a03b960)(0x7fbb8a03bda0)]), other_conds(nil)
2 - output([VIEW1.store_code(0x7fbb8a03b960)]), filter(nil), rowset=256
access([VIEW1.store_code(0x7fbb8a03b960)])
3 - output([da_store.STORE_CODE(0x7fbb8a037fd0)]), filter(nil), rowset=256
access([da_store.__pk_increment(0x7fbb8a039ec0)], [da_store.STORE_CODE(0x7fbb8a037fd0)]), partitions(p0)
is_index_back=true, is_global_index=false,
range_key([da_store.REGION(0x7fbb8a0374d0)], [da_store.__pk_increment(0x7fbb8a039ec0)]), range(A089,MIN ; A089,MAX),
range_cond([da_store.REGION(0x7fbb8a0374d0) = ‘A089’(0x7fbb8a183cf0)])
4 - output([da_sale_imp2.store_code(0x7fbb8a0384d0)], [da_sale_imp2.qty(0x7fbb8a039520)]), filter(nil), rowset=256
access([da_sale_imp2.store_code(0x7fbb8a0384d0)], [da_sale_imp2.qty(0x7fbb8a039520)]), partitions(p0)
is_index_back=false, is_global_index=false,
range_key([da_sale_imp2.__pk_increment(0x7fbb8a03a500)]), range(MIN ; MAX)always true
Used Hint:
/*+
*/
Qb name trace:
stmt_id:0, stmt_type:T_EXPLAIN
stmt_id:1, SEL$1 > SEL$6FCAE2AA
stmt_id:2, SEL$2
Outline Data:
/*+
BEGIN_OUTLINE_DATA
LEADING(@“SEL$6FCAE2AA” (“VIEW1”@“SEL$1” “ob”.“da_sale_imp2”@“SEL$1”))
USE_HASH(@“SEL$6FCAE2AA” “ob”.“da_sale_imp2”@“SEL$1”)
INDEX(@“SEL$2” “ob”.“da_store”@“SEL$2” “idx_da_store_01”)
FULL(@“SEL$6FCAE2AA” “ob”.“da_sale_imp2”@“SEL$1”)
USE_COLUMN_TABLE(@“SEL$6FCAE2AA” “ob”.“da_sale_imp2”@“SEL$1”)
UNNEST(@“SEL$2”)
OPTIMIZER_FEATURES_ENABLE(‘4.3.4.0’)
END_OUTLINE_DATA
*/
Optimization Info:
da_store:
table_rows:17833
physical_range_rows:978
logical_range_rows:978
index_back_rows:978
output_rows:978
table_dop:1
dop_method:Table DOP
avaiable_index_name:[idx_da_store, idx_da_store_01, DA_STORE]
pruned_index_name:[idx_da_store]
unstable_index_name:[DA_STORE]
stats info:[version=1734489554279688, is_locked=0, is_expired=0]
dynamic sampling level:0
estimation method:[OPTIMIZER STATISTICS, STORAGE]
da_sale_imp2:
table_rows:25929589
physical_range_rows:159999999
logical_range_rows:159999999
index_back_rows:0
output_rows:159999999
table_dop:1
dop_method:Table DOP
avaiable_index_name:[da_sale_imp2]
stats info:[version=1734487610882355, is_locked=0, is_expired=0]
dynamic sampling level:0
estimation method:[OPTIMIZER STATISTICS, STORAGE]
Plan Type:
LOCAL
Note:
Degree of Parallelisim is 1 because of table property
EXPLAIN EXTENDED SELECT
sum( qty )
FROM
da_sale_imp2 dsi
INNER JOIN ( SELECT store_code FROM da_store WHERE region =‘A089’ ) ds ON dsi.store_code = ds.store_code
================================================================================
|ID|OPERATOR |NAME |EST.ROWS |EST.TIME(us)|
|0 |SCALAR GROUP BY | |1 |45448679 |
|1 |└─HASH JOIN | |16775301 |45144643 |
|2 | ├─TABLE RANGE SCAN |da_store(idx_da_store_01)|978 |2598 |
|3 | └─COLUMN TABLE FULL SCAN|dsi |159999999|2037933 |
Outputs & filters:
0 - output([T_FUN_SUM(dsi.qty(0x7fbd3ae37830))(0x7fbd3ae36ea0)]), filter(nil), rowset=256
group(nil), agg_func([T_FUN_SUM(dsi.qty(0x7fbd3ae37830))(0x7fbd3ae36ea0)])
1 - output([dsi.qty(0x7fbd3ae37830)]), filter(nil), rowset=256
equal_conds([dsi.store_code(0x7fbd3ae363c0) = da_store.STORE_CODE(0x7fbd3ae349e0)(0x7fbd3ae35b00)]), other_conds(nil)
2 - output([da_store.STORE_CODE(0x7fbd3ae349e0)]), filter(nil), rowset=256
access([da_store.__pk_increment(0x7fbd3ae38290)], [da_store.STORE_CODE(0x7fbd3ae349e0)]), partitions(p0)
is_index_back=true, is_global_index=false,
range_key([da_store.REGION(0x7fbd3ae33ee0)], [da_store.__pk_increment(0x7fbd3ae38290)]), range(A089,MIN ; A089,MAX),
range_cond([da_store.REGION(0x7fbd3ae33ee0) = ‘A089’(0x7fbd3af13730)])
3 - output([dsi.store_code(0x7fbd3ae363c0)], [dsi.qty(0x7fbd3ae37830)]), filter(nil), rowset=256
access([dsi.store_code(0x7fbd3ae363c0)], [dsi.qty(0x7fbd3ae37830)]), partitions(p0)
is_index_back=false, is_global_index=false,
range_key([dsi.__pk_increment(0x7fbd3ae388d0)]), range(MIN ; MAX)always true
Used Hint:
/*+
*/
Qb name trace:
stmt_id:0, stmt_type:T_EXPLAIN
stmt_id:1, SEL$1 > SEL$CFEA49FE > SEL$A7A036C9
stmt_id:2, SEL$2
Outline Data:
/*+
BEGIN_OUTLINE_DATA
LEADING(@“SEL$A7A036C9” (“ob”.“da_store”@“SEL$2” “dsi”@“SEL$1”))
USE_HASH(@“SEL$A7A036C9” “dsi”@“SEL$1”)
INDEX(@“SEL$A7A036C9” “ob”.“da_store”@“SEL$2” “idx_da_store_01”)
FULL(@“SEL$A7A036C9” “dsi”@“SEL$1”)
USE_COLUMN_TABLE(@“SEL$A7A036C9” “dsi”@“SEL$1”)
MERGE(@“SEL$2” > “SEL$1”)
OUTER_TO_INNER(@“SEL$CFEA49FE”)
OPTIMIZER_FEATURES_ENABLE(‘4.3.4.0’)
END_OUTLINE_DATA
*/
Optimization Info:
da_store:
table_rows:17833
physical_range_rows:978
logical_range_rows:978
index_back_rows:978
output_rows:978
table_dop:1
dop_method:Table DOP
avaiable_index_name:[idx_da_store, idx_da_store_01, DA_STORE]
pruned_index_name:[idx_da_store]
unstable_index_name:[DA_STORE]
stats info:[version=1734489554279688, is_locked=0, is_expired=0]
dynamic sampling level:0
estimation method:[OPTIMIZER STATISTICS, STORAGE]
dsi:
table_rows:25929589
physical_range_rows:159999999
logical_range_rows:159999999
index_back_rows:0
output_rows:159999999
table_dop:1
dop_method:Table DOP
avaiable_index_name:[da_sale_imp2]
stats info:[version=1734487610882355, is_locked=0, is_expired=0]
dynamic sampling level:0
estimation method:[OPTIMIZER STATISTICS, STORAGE]
Plan Type:
LOCAL
Note:
Degree of Parallelisim is 1 because of table property
1 个赞
目前查询仍然是20S以上,obdiag目前未部署,mac上可以本地部署吗,有没有推荐的文档
1 个赞
表结构基本是这种,目前尝试了三种,未分区,分区模式,列存模式,关联查询反馈基本是一致的
1 个赞
淇铭
2024 年12 月 18 日 14:40
#20
你的ob集群搭建的什么环境上?结构什么样的
参数查询一下
show parameters where name in (‘memory_limit’,‘memory_limit_percentage’,‘system_memory’,‘log_disk_size’,‘log_disk_percentage’,‘datafile_size’,‘datafile_disk_percentage’);
集群资源配置情况
select zone,concat(SVR_IP,’:’,SVR_PORT) observer,
cpu_capacity_max cpu_total,cpu_assigned_max cpu_assigned,
cpu_capacity-cpu_assigned_max as cpu_free,
round(memory_limit/1024/1024/1024,2) as memory_total,
round((memory_limit-mem_capacity)/1024/1024/1024,2) as system_memory,
round(mem_assigned/1024/1024/1024,2) as mem_assigned,
round((mem_capacity-mem_assigned)/1024/1024/1024,2) as memory_free,
round(log_disk_capacity/1024/1024/1024,2) as log_disk_capacity,
round(log_disk_assigned/1024/1024/1024,2) as log_disk_assigned,
round((log_disk_capacity-log_disk_assigned)/1024/1024/1024,2) as log_disk_free,
round((data_disk_capacity/1024/1024/1024),2) as data_disk,
round((data_disk_in_use/1024/1024/1024),2) as data_disk_used,
round((data_disk_capacity-data_disk_in_use)/1024/1024/1024,2) as data_disk_free
from oceanbase.gv$ob_servers;
租户查询
select * from oceanbase.dba_ob_tenants;
1 个赞
sql_result-2.txt (1.1 MB)
这个可以帮忙分析下吗