入职外包仅两天,就利用ASP技能搞定核心问题,女上司直呼:提前转正

前言

上篇文章介绍了ASP的基本原理,详细内容请会看文章:

《刚刚下岗的Oracle DBA学了这个国产数据库技能后,下午就上岗了》: https://blog.csdn.net/ORACLE_BBED/article/details/138014441?spm=1001.2014.3001.5501

alt

local_active_session视图

内存里的ASP信息保存在DBE_PERF.local_active_session视图中。视图DBE_PERF.local_active_session的实现是通过调用函数get_local_active_ session()获取g_instance.stat_cxt.active_sess_hist_arrary->active_sess_hist_info里的采样数据数据生成 视图。这部分内容为实时的信息,存储在内存中,显示的是最近的活跃session信息。视图的具体内容如下表:

名称类型描述
sampleidbigint采样ID,后台ASP采样线程开始时从0开始,每采样一次递增1。
sample_timetimestamp w/ timezone采样的时间。
need_flush_sampleboolean该样本是否需要刷新到磁盘。该值是通过计算 sampleid%asp_flush_rate来判断是否需要刷新。 True表示需要,false表示不需要。
databaseidoid数据库ID。
thread_idbigint当前线程的ID,取值来源于t_thrd.proc_cxt.MyProcPid。
sessionidbigint会话的ID。
start_timetimestamp w/ timezone会话的启动时间。
eventtext具体的事件名称。
lwtidinteger当前线程的轻量级线程号。
psessionidbigintstreaming线程的父线程。
tlevelintegerstreaming线程的层级。与执行计划的层级(ID)相对应。
smpidintegersmp执行模式下并行线程的并行编号。
useridoid当前session用户的ID。
application_nametext后台线程的名称,例如'ASP','Wal Writer'等。
client_addrinet数据库client端的地址。
client_hostnametextclient端的名称。
client_portinteger客户端用于与后端通讯的TCP端口号。
query_idbigintdebug query id,获取的是u_sess->debug_query_id值,由node id,timeline id和query sequence number 组合而成。
unique_query_idbigint当前sql在完成rewrite之后生成的unique query id,可能为0此时该字段 显示为空。
user_idoidunique query的key中的user_id。
cn_idinteger在DN上表示下发该unique sql的节点id,unique query的key中的cn_id
unique_querytext规范化后的UniqueSQL文本串,只有unique query id不为0时才有内容。
locktagtext会话等待锁的信息,为LOCALLOCKTAG数据结构,内容包含锁对象标志和锁的 类型。
lockmodetext会话等待锁的类型:- LW_EXCLUSIVE:排他锁,LW_SHARED:共享锁,LW_WAIT_UNTIL_FREE:等待LW_EXCLUSIVE可用
block_sessionidbigint如果会话正在等待锁,阻塞该会话获取锁的会话标识。为0时表示没有当前没有 阻塞。
wait_statustext等待事件的状态信息。
global_sessionidtext全局会话ID。
plan_node_idint执行计划树的算子id,为-1时表明在ASP采样时,执行器还没有给该计划树分 配算子id.
xact_start_timetimestamp w/ timezone当前事务的开始时间
query_start_timetimestamp w/ timezone当前语句的开始时间
stateenum台线程的运行状态,可以是如下值:STATE_UNDEFINED, //初始化状态 STATE_IDLE, //正在空闲等待状态;STATE_RUNNING, //正在active执行状态;STATE_IDLEINTRANSACTION, // 在处理事务过程中,暂时无法执行处于空 闲等待状态;STATE_FASTPATH, //在执行fast path 函数 STATE_IDLEINTRANSACTION_ABORTED, // 在处理事务过程中有某个语句 执行错误,处于空闲状态;STATE_DISABLED, // 被禁用了track_activities,不能追踪状态 STATE_RETRYING, //重试;STATE_COUPLED, //绑定会话 STATE_DECOUPLED //取消绑定会话

ASP系统表

ASP的表为GS_ASP,属于CATALOG里的系统表,在src/include/catalog/gs_asp.h里定义: CATALOG(gs_asp,9534)。具体字段同视图DBE_PERF.local_active_session。GS_ASP的数据来源 为选取g_instance.stat_cxt.active_sess_hist_arrary->active_sess_hist_info 里的部分采样并持久化到磁 盘中。具体选取多少采样值是由GUC参数asp_flush_rate设定。相对于视图DBE_ PERF.local_active_session,ASP表中存放的是过去更长时间内的活跃会话历史信息,适合更长时 间跨度的统计分析。

ASP Log 文件

当GUC参数asp_flush_mode设置为file时,g_instance.stat_cxt.active_sess_hist_arrary里的部分采 样信息不会记录到GS_ASP表,而是会被持久化存放到ASP的log文件中。文件的地址和命名分 别在GUC参数asp_log_directory和asp_log_filename中设置。默认为数据库asp_data目录下。

ASP 的log文件内容样例如下:

{"sampleid":"350430","sample_time":"2023-07-27T23:59:35.558198+08:00","need_flush_sample":true ,"databaseid":0,"thread_id":"139681843377920","sessionid":"139681843377920","global_sessionid" :"0:0#0","start_time":"2023-07-07T16:39:56.969878+08:00","xact_start_time":null,"query_start_t ime":null,"state":"active","event":"none","waitstatus":"none","lwtid":23455,"psessionid":null, "tlevel":0,"smpid":0,"userid":0,"application_name":"Wal Writer","locktag":null,"lockmode":null,"block_sessionid":null,"client_addr":null,"client_hostn ame":null,"client_port":null,"query_id":"","unique_query_id":null,"user_id":null,"cn_id":null, "unique_query":null}

实战:定位阻塞源

模拟故障

执行session1的两条语句后,再执行session2的一条语句,session2会被阻塞等待session1的锁释放。

  • session 1:更新表emp中id为3的记录中字段name 值为c1。
begin;
update emp SET name = 'c1' where id = 3;
alt
  • session2: 更新表emp中id为3的记录中字段name 值为c2。
update emp SET name = 'c2' where id = 3;
alt

查看阻塞

如果是查询实时信息,那么我们可以通过如下SQL去查询阻塞链。

SELECT blocked_locks.pid     AS blocked_pid,
         blocked_activity.usename  AS blocked_user,
         blocking_locks.pid     AS blocking_pid,
         blocking_activity.usename AS blocking_user,
         blocked_activity.query    AS blocked_statement,
         blocking_activity.query   AS current_statement_in_blocking_process
   FROM  pg_catalog.pg_locks         blocked_locks
    JOIN pg_catalog.pg_stat_activity blocked_activity  ON blocked_activity.pid = blocked_locks.pid
    JOIN pg_catalog.pg_locks         blocking_locks
        ON blocking_locks.locktype = blocked_locks.locktype
        AND blocking_locks.database IS NOT DISTINCT FROM blocked_locks.database
        AND blocking_locks.relation IS NOT DISTINCT FROM blocked_locks.relation
        AND blocking_locks.page IS NOT DISTINCT FROM blocked_locks.page
        AND blocking_locks.tuple IS NOT DISTINCT FROM blocked_locks.tuple
        AND blocking_locks.virtualxid IS NOT DISTINCT FROM blocked_locks.virtualxid
        AND blocking_locks.transactionid IS NOT DISTINCT FROM blocked_locks.transactionid
        AND blocking_locks.classid IS NOT DISTINCT FROM blocked_locks.classid
        AND blocking_locks.objid IS NOT DISTINCT FROM blocked_locks.objid
        AND blocking_locks.objsubid IS NOT DISTINCT FROM blocked_locks.objsubid
        AND blocking_locks.pid != blocked_locks.pid
    JOIN pg_catalog.pg_stat_activity blocking_activity ON blocking_activity.pid = blocking_locks.pid
   WHERE NOT blocked_locks.granted;
  blocked_pid   | blocked_user |  blocking_pid  | blocking_user |              blocked_statement              |    current_statement_in_blocking_process    
----------------+--------------+----------------+---------------+---------------------------------------------+---------------------------------------------
 47810227406592 | omm          | 47810357757696 | omm           | update emp SET name = 'MogDB' where id = 3; | update emp SET name = 'MogDB' where id = 3;

alt 可以看出,sessionid:47810227406592被阻塞。

通过ASP数据查询阻塞

SELECT sessionid, start_time, event, count
FROM (
SELECT sessionid, start_time, event, COUNT(*)
FROM dbe_perf.local_active_session
WHERE sample_time > now() - 10 / (24 * 60)
GROUP BY sessionid, start_time, event) as t ORDER BY SUM(t.count) OVER (PARTITION BY t. sessionid, start_time)DESC, t.event;

   sessionid    |          start_time           |         event         | count 
----------------+-------------------------------+-----------------------+-------
 47810357757696 | 2024-04-21 21:07:23.08784+08  | wait cmd              |   598
 47810390652672 | 2024-04-21 21:12:03.224273+08 | HashJoin - build hash |     1

SELECT sessionid,start_time,event,wait_status,block_sessionid,final_block_sessionid FROM dbe_perf.local_active_session where block_sessionid in (47810357757696,47810390652672);

alt 发现阻塞源头是sessionid:47810357757696,sessionid:47810390652672是被阻塞者,与前面结果一致。

增强ASP功能

MogDB企业版增强的ASH能力,称为"SQL运行状态观测",主要是通过在采样数据中增加SQL执行算子的采样来完成的。 在dbe_perf.local_active_session和GS_ASP中新增一列plan_node_id来记录SQL语句每个算子操作的执行情况。即可知道对于出现性能问题的SQL具体是慢在了执行计划的哪个步骤上。

开启增强ASP功能的参数:

  • resource_track_level 参数指定为operator,则会开启算子采样能力,默认值是query,只会记录SQL级别采样。

模拟

创建表test:

MogDB=# create table test(c1 int);
CREATE TABLE
MogDB=# insert into test select generate_series(1, 1000000000);

查询出该SQL的query_id

MogDB=# select query,query_id from pg_stat_activity where query like 'insert into test select%';
                    query                                  |    query_id
-----------------------------------------------------------+-----------------
 insert into test select generate_series(1, 100000000000); | 562949953421368
(1 row)

查询带plan_node_id的执行计划

Set resource_track_cost=10;


MogDB=# select query_plan from dbe_perf.statement_complex_runtime where queryid = 562949953421368;
                                 query_plan
----------------------------------------------------------------------------
 Coordinator Name: datanode1                                               +
 1 | Insert on test  (cost=0.00..17.51 rows=1000 width=8)                         +
 2 |  ->  Subquery Scan on "*SELECT*"  (cost=0.00..17.51 rows=1000 width=8)    +
 3 |   ->  Result  (cost=0.00..5.01 rows=1000 width=0)                         +
                                                                        +
(1 row)

SQL运行状态观测

在session2中,根据query_id从采样视图dbe_perf.local_active_session中查询出该语句的采样情况,结合上面查询的执行计划做性能分析。

MogDB=# select plan_node_id, count(plan_node_id) from dbe_perf.local_active_session where query_id = 562949953421368 group by plan_node_id;
 plan_node_id | count
--------------+-------
        3     |   12
        1     |   366
        2     |   2
(3 rows)

结论

当发现insert into test select generate_series(1, 1000000000)存在性能瓶颈,通过以上的步骤定位发现,insert操作在整个SQL语句执行过程中被采样的数值最高( plan_node_id =1 ,count=366),可以对其进行优化。

本文由 mdnice 多平台发布

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值