GBase 8c 数据库性能分析场景实战指南

在金融、电信、政务等核心业务场景中,GBase 8c 分布式数据库承载着高并发、低延迟的事务处理与分析任务。随着业务规模扩大与数据量激增,SQL 语句的执行效率直接决定了系统的整体性能与稳定性。传统“黑盒式”的性能监控手段(如仅观察 CPU、内存等资源指标)已难以快速定位响应延迟的根因——低效 SQL 往往隐藏在复杂的业务逻辑中,成为系统瓶颈的隐形杀手。为此,GBase 8c提供了丰富的工具或系统对象,辅助用户快速完成SQL性能分析。

本文以dbe_perf.statement 与 dbe_perf.statement_history视图为例。这两个视图如同数据库内部的“X光机”,为运维与开发人员提供了 SQL 执行全生命周期的透视能力:

  • dbe_perf.statement:动态捕获当前活跃 SQL 的执行状态(如运行时长、资源消耗、锁等待)。
  • dbe_perf.statement_history:持久化记录历史 SQL 的执行统计(如调用次数、总耗时、I/O 与 CPU 开销)。

1、分析SQL执行时间

dbe_perf.statement 这个视图实际执行的是 get_instr_unique_sql() 内置函数,它能够显示CN节点上执行过的sql的一些时间信息,比如 sql执行的总耗时,在执行器中的耗时等信息,在优化器中执行的耗时等。它只能在CN节点上执行,不能在DN上执行。

内置函数get_instr_unique_sql()的数据来自于 g_instance.stat_cxt.UniqueSQLHashtbl 哈希表。哈希表内存有限,所以不能保存所有的sql信息,通过配置 instr_unique_sql_count GUC参数(默认值是 100)可以调整 dbe_perf.statement 能够记录的sql的数据。节点重启后,g_instance.stat_cxt.UniqueSQLHashtbl 哈希表内容会被清空。

示例

下面的示例展示了benchmarksql测试中 UPDATE bmsql_warehouse SET w_ytd = w_ytd + $1 WHERE w_id = $2 语句的统计信息。

test=# select * from dbe_perf.statement where query ~ 'UPDATE bmsql_warehouse';

例如返回如下信息:

以下信息表示在测试的这段时间,这条sql执行了 9339次。每次执行的时间是 db_time / n_calls = 313us 实际消耗CPU的时间 CPU_time / n_calls = 97us。这条sql走lightproxy,所以 plan_time rewrite_time execution_time 都是0。

-[ RECORD 1 ]--------+----------------------------------------------------------------------
node_name            | cn1
node_id              | -1178713634
user_name            | test1
user_id              | 16974
unique_sql_id        | 739002000
query                | UPDATE bmsql_warehouse     SET w_ytd = w_ytd + $1     WHERE w_id = $2
n_calls              | 9339
min_elapse_time      | 150
max_elapse_time      | 26529
total_elapse_time    | 2512361
n_returned_rows      | 0
n_tuples_fetched     | 0
n_tuples_returned    | 0
n_tuples_inserted    | 0
n_tuples_updated     | 0
n_tuples_deleted     | 0
n_blocks_fetched     | 1
n_blocks_hit         | 1
n_soft_parse         | 0
n_hard_parse         | 0
db_time              | 2929210
CPU_time             | 906947
execution_time       | 0
parse_time           | 24
plan_time            | 0
rewrite_time         | 9
pl_execution_time    | 0
pl_compilation_time  | 0
data_io_time         | 0
net_send_info        | {"time":215081, "n_calls":28017, "size":1285855}
net_recv_info        | {"time":1385396, "n_calls":26612, "size":884261}
net_stream_send_info | {"time":0, "n_calls":0, "size":0}
net_stream_recv_info | {"time":0, "n_calls":0, "size":0}
last_updated         | 2022-12-12 13:51:59.767953+08
sort_count           | 0
sort_time            | 0
sort_mem_used        | 0
sort_spill_count     | 0
sort_spill_size      | 0
hash_count           | 0
hash_time            | 0
hash_mem_used        | 0
hash_spill_count     | 0
hash_spill_size      | 0

字段解析

n_calls

表示这个sql执行的次数,下面的时间都是总的时间,如果要计算平均时间需要除以 n_calls。

db_time

表示这个sql 执行的总时间, 用这个时间除以 n_calls 就是每条sql执行的平均时间。这个时间的计时从 ReadCommand 接收到 client的消息开始 (timeInfoRecordStart), 到给client 发给 ReadyForQuery消息结束 (timeInfoRecordEnd)。

CPU_time

这个时间和db_time 的计时类似,和db_time 不同的是,它调用的是 clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tv) API,也就是只计算CPU时间,不计算在内核中sleep的时间。

parse_time

统计的是pg_parse_query 函数内生成查询数的时间。

plan_time

统计的是 planner 函数 优化器生成执行计划的时间。

rewrite_time

统计的是 pg_rewrite_query 函数内查询重写的时间。

execution_time

统计的是 PortalRun 函数内执行器消耗的时间。

data_io_time

统计的是读取表的block的时间,因为CN上只有元数据,所以这个值很小。

net_send_info

统计的是CN向DN发送执行计划或者下推的sql而调用 com_send的次数,消耗的时间,发送数据量的大小。

net_recv_info

同net_send_info 统计的是CN调用 com_recv的次数,消耗的时间,接收数据的大小。

清除统计信息

如果想清空统计信息,重新开始统计,可调用 reset_unique_sql 内置函数。reset_unique_sql 有三个入参。第一个入参可选 global 或 local,表示清除全局的或者本地的 sql。 第二个参数是 cleanType 用 all 即可, 第三个参数 cleanValue 用0 即可。调用完后再查视图就会发现内容已清空。

调用内置函数:

test=# select reset_unique_sql('local', 'all', 0);
-[ RECORD 1 ]
----+--
reset_unique_sql | t

查询视图为空:

test=# select * from dbe_perf.statement where query ~ 'UPDATE bmsql_warehouse';
(No rows)

2、查询慢sql原因

数据库执行sql时有的查询特别慢,为了搞清楚查询慢的原因可以使用 dbe_perf.statement_history 视图,显示sql在各个执行阶段花费的时间,进一步定位问题。

启用慢sql查询功能

控制慢查询功能的主要参数是 enable_stmt_track 和 log_min_duration_statement。用 gsql 登陆数据库,分布式登陆 CN节点,并确认 enable_stmt_track参数为on。

test=# show enable_stmt_track;
-[ RECORD 1 ]
----+---
enable_stmt_track | on

查看 log_min_duration_statement 设置的值,如果sql的执行时间大于这个值,将会被记录在statement_history 视图中,否则不会记录。如果这个值设置的是 0则 所有的 sql都会记录,如果这个值设置的是-1 则所有的 sql都不会记录。例子中设置的值是 30分钟,也就是大于30分钟的sql才会记录。

test=# show log_min_duration_statement;
-[ RECORD 1 ]
--------------+------
log_min_duration_statement | 30min

使用 gs_guc 将log_min_duration_statement 参数改成需要的值,比如2秒 ,这个值的单位是 ms。使用命令:

gs_guc reload -Z coordinator -N all -I all -c “log_min_duration_statement=2000”

再确认一下:

test=# show log_min_duration_statement;
log_min_duration_statement 
----------------------------
2s
(1 row)

执行sql

在设置完成后执行慢的sql,如果sql执行时间超过2s就会记录在 statement_history视图中。

查看慢sql

在查看 statement_history 视图时,用 where 子句过滤掉不想看的sql。

即可在返回的结果中可以看到sql执行的开始时间,结束时间,parse的时间,plan的时间,以及在执行器的时间等。再依据日志或其他信息分析慢sql的根因。

test=# select * from dbe_perf.statement_history where query ~ 'insert into test';
-[ RECORD 3 ]
--------+-----------------------------------------------
db_name              | gbase
schema_name          | "$user",public
origin_node          | -1178713634
user_name            | gbase
application_name     | gsql
client_addr          | 
client_port          | -1
unique_query_id      | 812114989
debug_query_id       | 79094468455694433
query                | insert into test values(generate_series(?,?));
start_time           | 2022-12-27 15:50:01.781449+08
finish_time          | 2022-12-27 15:50:11.570623+08
slow_sql_threshold   | 2000000
transaction_id       | 108244
thread_id            | 140135375890176
session_id           | 140135375890176
n_soft_parse         | 0
n_hard_parse         | 1
query_plan           | 
n_returned_rows      | 0
n_tuples_fetched     | 0
n_tuples_returned    | 0
n_tuples_inserted    | 0
n_tuples_updated     | 0
n_tuples_deleted     | 0
n_blocks_fetched     | 0
n_blocks_hit         | 0
db_time              | 9789194
CPU_time             | 3063
execution_time       | 9786209
parse_time           | 65
plan_time            | 416
rewrite_time         | 11
pl_execution_time    | 0
pl_compilation_time  | 0
data_io_time         | 0
net_send_info        | {"time":260, "n_calls":19, "size":23243}
net_recv_info        | {"time":61306609, "n_calls":12, "size":350}
net_stream_send_info | {"time":0, "n_calls":0, "size":0}
net_stream_recv_info | {"time":0, "n_calls":0, "size":0}
lock_count           | 23
lock_time            | 0
lock_wait_count      | 0
lock_wait_time       | 0
lock_max_count       | 4
lwlock_count         | 0
lwlock_wait_count    | 0
lwlock_time          | 0
lwlock_wait_time     | 0
details              | 
is_slow_sql          | t
trace_id             | 

原创文章,作者:kirin,如若转载,请注明出处:https://blog.ytso.com/tech/bigdata/317645.html

(0)
上一篇 47分钟前
下一篇 40分钟前

相关推荐

发表回复

登录后才能评论