文档首页/ 数据仓库服务 GaussDB(DWS)/ 最佳实践/ 性能调优/ 分析正在执行的SQL以处理GaussDB(DWS)业务阻塞
更新时间:2024-10-10 GMT+08:00

分析正在执行的SQL以处理GaussDB(DWS)业务阻塞

在开发过程中,开发者常遇到SQL连接数超限、SQL查询时间过长、SQL查询阻塞等问题,您可以通过PG_STAT_ACTIVITYPGXC_THREAD_WAIT_STATUS视图来分析和定位SQL问题,以下通过PG_STAT_ACTIVITY视图展示常用的一些定位思路。

表1 部分PG_STAT_ACTIVITY字段

名称

类型

描述

usename

name

登录该后端的用户名。

client_addr

inet

连接到该后端的客户端的IP地址。 如果此字段是null,则表示通过服务器机器上UNIX套接字连接客户端或者这是内部进程,如autovacuum。

application_name

text

连接到该后端的应用名。

state

text

后端当前总体状态。取值如下:

  • active:后台正在执行查询。
  • idle:后台正在等待新的客户端命令。
  • idle in transaction:后端在事务中,但事务中没有语句在执行。
  • idle in transaction (aborted):后端在事务中,但事务中有语句执行失败。
  • fastpath function call:后端正在执行一个fast-path函数。
  • disabled:如果后端禁用track_activities,则报告此状态。
说明:

普通用户只能查看到自己账户所对应的会话状态,即其他账户的state信息为空。

waiting

boolean

如果后端当前正等待锁则为t,否则为f。

  • t代表true。
  • f代表false。

enqueue

text

语句当前排队状态。可能值是:

  • waiting in global queue:表示语句在全局并发队列排队中,主要包含并发数超过单CN配置的max_active_statements。
  • waiting in respool queue:表示语句在资源池排队中,简单作业并发受限,主要是简单作业并发超过快车道并发上限max_dop。
  • waiting in ccn queue:表示作业在CCN排队中,包含全局内存排队和慢车道内存和并发排队,包含以下场景:
    1. 全局可用内存超过上限,进行全局内存队列排队。
    2. 资源池慢车道并发上限,即资源池并发超过active_statements上限。
    3. 资源池慢车道内存上限,即资源池并发作业估算内存超过mem_percent计算的上限。
  • 空或no waiting queue:表示语句正在运行。

pid

bigint

后端线程ID。

查看连接信息

  • 设置参数track_activities为on:
    SET track_activities = on;

    当此参数为on时,数据库系统才会收集当前活动查询的运行信息。

  • 通过以下SQL就能确认当前的连接用户、连接地址、连接应用、状态、是否等待锁、排队状态以及线程id。
    1
    SELECT usename,client_addr,application_name,state,waiting,enqueue,pid FROM PG_STAT_ACTIVITY WHERE DATNAME='数据库名称';
    

    回显如下:

    1
    2
    3
    4
    5
    6
     usename |  client_addr  | application_name | state  | waiting | enqueue |       pid       
    ---------+---------------+------------------+--------+---------+---------+-----------------
     leo     | 192.168.0.133 | gsql             | idle   | f       |         | 139666091022080
     dbadmin | 192.168.0.133 | gsql             | active | f       |         | 139666212681472
     joe     | 192.168.0.133 |                  | idle   | f       |         | 139665671489280
    (3 rows)
    
  • 中止某个会话连接(仅系统管理员有权限):
    1
    SELECT PG_TERMINATE_BACKEND(pid);
    

查看SQL运行信息

  • 获取当前用户有权限查看的所有的SQL信息(若有管理员权限或预置角色权限可以显示和所有用户查询相关的信息):
    1
    SELECT usename,state,query FROM PG_STAT_ACTIVITY WHERE DATNAME='数据库名称';
    
    如果state为active,则query列表示当前执行的SQL语句,其他情况则表示为上一个查询语句;如果state字段显示为idle,则表明此连接处于空闲,等待用户输入命令。回显如下:
    1
    2
    3
    4
    5
    6
     usename | state  |                                   query                                   
    ---------+--------+---------------------------------------------------------------------------
     leo     | idle   | select * from joe.mytable;
     dbadmin | active | SELECT usename,state,query FROM PG_STAT_ACTIVITY WHERE DATNAME='gaussdb';
     joe     | idle   | GRANT SELECT ON TABLE mytable to leo;
    (3 rows)
    
  • 查看当前正在运行(非idle)的SQL信息:
    1
    SELECT datname,usename,query FROM PG_STAT_ACTIVITY WHERE state != 'idle' ;
    

查看耗时较长的语句

  • 查看当前运行中的耗时较长的SQL语句:
    1
    SELECT current_timestamp - query_start as runtime, datname, usename, query FROM PG_STAT_ACTIVITY WHERE state != 'idle' order by 1 desc;
    

    查询会返回按执行时间长短从大到小排列的查询语句列表。第一条结果就是当前系统中执行时间最长的查询语句。

    1
    2
    3
    4
    5
         runtime     | datname  | usename |                                                                  query                                                                  
    -----------------+----------+---------+-----------------------------------------------------------------------------------------------------------------------------------------
     00:04:47.054958 | gaussdb  | leo     | insert into mytable1 select generate_series(1, 10000000);
     00:00:01.72789  | gaussdb  | dbadmin | SELECT current_timestamp - query_start as runtime, datname, usename, query FROM PG_STAT_ACTIVITY WHERE state != 'idle' order by 1 desc;
    (2 rows)
    
  • 若当前系统较为繁忙,可以通过限制current_timestamp - query_start大于某一阈值来查看执行时间超过此阈值的查询语句。
    1
    SELECT query from PG_STAT_ACTIVITY WHERE current_timestamp - query_start > interval '2 days';
    

查看处于阻塞状态的语句

  • 查看当前处于阻塞状态的查询语句:
    1
    SELECT pid, datname, usename, state, query FROM PG_STAT_ACTIVITY WHERE state <> 'idle' and waiting=true;
    
    执行以下语句结束到阻塞的SQL会话:
    1
    SELECT PG_TERMINATE_BACKEND(pid);
    
    • 大部分场景下,阻塞是因为系统内部锁而导致的,waiting字段才显示为true,此阻塞可在视图pg_stat_activity中体现。
    • 在一些少数场景下,例如写文件、定时器等情况的查询阻塞,不会在视图pg_stat_activity中体现。
  • 查看阻塞的查询语句及阻塞查询的表、模式信息
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    SELECT w.query as waiting_query,
    w.pid as w_pid,
    w.usename as w_user,
    l.query as locking_query,
    l.pid as l_pid,
    l.usename as l_user,
    t.schemaname || '.' || t.relname as tablename
    from pg_stat_activity w join pg_locks l1 on w.pid = l1.pid
    and not l1.granted join pg_locks l2 on l1.relation = l2.relation
    and l2.granted join pg_stat_activity l on l2.pid = l.pid join pg_stat_user_tables t on l1.relation = t.relid
    where w.waiting;
    

    该查询返回会话ID、用户信息、查询状态,以及导致阻塞的表、模式信息。

    查询到阻塞的表及模式信息后请根据会话ID结束会话。

    1
    SELECT PG_TERMINATE_BACKEND(pid);
    

    显示类似如下信息,表示结束会话成功。

    PG_TERMINATE_BACKEND 
    ----------------------  
    t 
    (1 row)

    显示类似如下信息,表示用户正在尝试结束当前会话,此时仅会重连会话,而不是结束会话。

    FATAL:  terminating connection due to administrator command 
    FATAL:  terminating connection due to administrator command 
    The connection to the server was lost. Attempting reset: Succeeded.

    gsql客户端使用PG_TERMINATE_BACKEND函数终止本会话后台线程时,客户端不会退出而是自动重连。