查询及分析TopSQL最佳实践
TopSQL简介
在DWS分布式数据库的复杂运维场景中,计划跳变、异常中断、长事务阻塞等突发状况频发。传统运维手段常面临"三无困境":异常现场难复现、执行过程无追踪、运行指标无留存,导致故障定位如同"大海捞针",既耗费大量人力成本,又易陷入问题溯源的死循环。
为解决此问题,DWS推出了TopSQL监控功能,支持记录运行中和运行完成的SQL语句(实时TopSQL和历史TopSQL),主要实现以下功能:
- 快速定位影响数据库性能且占用资源最密集的查询语句。
- 监控和跟踪这些查询语句随时间推移的性能变化。
- 分析查询执行计划以确定潜在的优化手段。
作为数据库运维的核心支撑工具,TopSQL已深度集成于生产环境各场景,为系统性能诊断、SQL劣化追踪及安全审计溯源等关键环节提供全链路支持,其多维监控矩阵全面涵盖内存占用、执行耗时、IO吞吐、网络时延及存储空间等多项核心指标。
TopSQL原理介绍
作业下发执行后,数据库内核通过打桩记录作业的各项资源信息,如内存、CPU、下盘、IO和网络信息等,作业执行完成后该资源信息先存在无锁队列中,资源管理后台辅助线程将该数据信息定期转储到dbms_om.gs_wlm_session_info系统表中,后续通过topsql_retention_time定期老化数据。

TopSQL相关GUC参数
集群创建成功后,系统默认开启TopSQL功能(由GUC参数use_workload_manager,enable_resource_track,enable_resource_record控制,默认都为on),GUC详细参数如表1所示。
|
参数 |
描述 |
建议值 |
||
|---|---|---|---|---|
|
use_workload_manager |
是否开启资源管理功能,开启TopSQL功能,该参数需要为on。 |
on |
||
|
enable_resource_track |
是否开启资源实时监控功能,实时TopSQL的总开关,关闭之后实时TopSQL将不再进行记录,更不会在历史TopSQL中出现。 |
on |
||
|
enable_resource_record |
是否开启资源监控记录归档功能。开启时,对于执行结束的记录,会分别被归档到相应的INFO视图,CN和DN都需要设置上。 |
on |
||
|
enable_track_record_subsql |
是否开启子语句记录归档功能,控制是否记录存储过程、匿名块内部语句。
|
on |
||
|
resource_track_duration |
设置实时TopSQL中记录的语句执行结束后进行历史信息转存的最小执行时间,该时间记录值的判断是包含了排队时间和运行时间,当排队时间+运行时间 > resource_track_duration时,TopSQL历史视图会记录作业信息。
|
60s |
||
|
resource_track_subsql_duration |
存储过程内部中子语句转储的最小执行时间。 该参数仅8.2.1及以上集群版本支持。 |
180s |
||
|
resource_track_cost |
设置对当前会话的语句进行资源监控的最小执行代价。 |
0 |
||
|
resource_track_level |
设置当前会话的资源监控的等级,默认为query级别。
|
query |
||
|
topsql_retention_time |
历史TopSQL中GS_WLM_SESSION_INFO和GS_WLM_OPERATOR_INFO表中数据的保存时间,单位为天。 |
30 |
||
|
session_history_memory |
设置历史查询视图的内存大小。 如果语句运行过程中出现"TopSQL lfq is full, failed to save queryid"报错信息,可通过如下SQL查询TopSQL无锁队列总的内存和已使用的内存。
|
100MB |
设置GUC参数方法:
通过DWS控制台设置:
- 在DWS控制台,左侧导航栏,选择“专属集群 > 集群列表”。
- 在集群列表中找到所需要的集群,单击集群名称,进入“集群详情”页面。
- 单击“参数修改”页签,并在“参数列表”模块修改相应的参数值,然后单击“保存”。

查询TopSQL相关GUC参数设置的常用SQL:
SELECT name,setting FROM pg_settings WHERE name LIKE '%resource%';

TopSQL相关视图及分析思路
TopSQL监控等级包括query、perf、operator_realtime、operator4个级别,由GUC参数resource_track_level控制,默认为query级别。
- query级别:此级别会把SQL语句的计划信息(类似explain输出信息)记录到TopSQL中。
- perf级别:此级别会把包含实际执行时间和执行行数的计划信息(类似explain analyze输出信息)记录到TopSQL中。
- operator_realtime级别:此级别会记录实时运行的作业算子信息到TopSQL中,但不会持久化到历史TopSQL中。
- operator级别:此级别不仅会把包含实际执行时间和执行行数的信息记录到TopSQL中,还会把算子级别执行信息刷新到TopSQL中。
TopSQL功能主要通过视图承载,相关视图如表2所示,根据视图中的字段信息可以进一步分析TopSQL信息,视图中常用的分析字段参见表3。
|
级别 |
类型 |
查询数据范围 |
视图名称 |
描述 |
|---|---|---|---|---|
|
query/perf级别 |
实时 |
单CN |
用户在当前CN上正在执行的作业的负载管理记录。 |
|
|
所有CN |
用户在所有CN上正在执行的作业的负载管理信息。 |
|||
|
历史 |
单CN |
用户在当前CN执行上作业结束后的负载管理记录。 |
||
|
所有CN |
用户在所有CN上执行作业结束后的负载管理记录。 |
|||
|
所有CN(显示经典字段信息) |
用户在所有CN上执行作业的TopSQL经典字段信息。仅9.1.1.100及以上版本支持。 |
|||
|
operator_realtime级别 / operator级别 |
实时 |
单CN |
用户在当前CN上正在执行的作业的算子相关信息。 |
|
|
所有CN |
用户在所有CN上正在执行作业的算子信息。 |
|||
|
历史 |
单CN |
用户在当前CN上执行作业结束后的算子相关的记录。 |
||
|
所有CN |
用户在所有CN上执行作业结束时的算子信息。 |
|
序号 |
字段名称 |
字段描述 |
分析出可能的现象 |
|---|---|---|---|
|
1 |
block_time |
语句执行前的阻塞时间,包含:语句解析、语句优化时间,以及作业排队时间。 |
A1: block_time较大,而duration值并无明显变化,说明用户作业受其它作业影响,在真正开始执行前进行了较长时间的排队,下一步需要查看当前数据表,统计起始时间小于start_time、结束时间大于finish_time的作业数量。 A2: block_time较小,而duration值较大,说明用户作业执行的时间大幅增加是因为自身导致,需要继续分析数据量的变化情况、各DN的执行时间变化。 |
|
2 |
start_time |
语句开始执行时间。 |
|
|
3 |
finish_time |
语句执行结束时间 |
|
|
4 |
duration |
语句执行时长。 |
|
|
5 |
status |
语句执行的结束状态,正常为finished,异常为aborted。 |
可以查看作业是否正常结束,如果异常,还会有异常原因。 |
|
6 |
abort_info |
语句执行结束状态为aborted时显示异常信息。 |
|
|
7 |
min_peak_memory |
语句在所有DN上的最小内存峰值,单位MB。 |
B1: 对于同一个查询,可对比前后几次的内存消耗情况,内存消耗平均值能够反映出数据表的数据量是否有变化,memory_skew_percent值能够侧面反映出相关数据表在各DN上的数据分布是否有倾斜。同时,query_plan(参见该表的序号31)能够直接显示作业的执行计划,对比执行计划是否有变化。 |
|
8 |
max_peak_memory |
语句在所有DN上的最大内存峰值,单位MB。 |
|
|
9 |
average_peak_memory |
语句执行过程中的内存使用平均值,单位MB。 |
|
|
10 |
memory_skew_percent |
语句在各DN间的内存使用倾斜率。 |
|
|
11 |
min_spill_size |
若发生下盘,所有DN上下盘的最小数据量,单位MB。 |
C1: 对有大量下盘的查询有显著帮助信息,当下盘量剧增的时候,通常是表数据量有大幅增加,或者是执行计划有问题导致的,结合query_plan能进一步分析,spill_skew_percent可以查看作业是否有严重数据倾斜。 |
|
12 |
max_spill_size |
若发生下盘,所有DN上下盘的最大数据量,单位MB。 |
|
|
13 |
average_spill_size |
若发生下盘,所有DN上下盘的平均数据量,单位MB。 |
|
|
14 |
spill_skew_percent |
若发生下盘,DN间下盘倾斜率。 |
|
|
15 |
min_dn_time |
语句在所有DN上的最小执行时间,单位ms。 |
D1: DN上的执行时间,结合duration数据,如果一个查询在DN执行时间有严重倾斜,那就需要考虑数据表的分区、分布列是否设置合适;不合理的分区、分布列,可能会导致本应分散到多个DN的执行任务被集中到个别DN上执行,执行时间必然大大增加。 |
|
16 |
max_dn_time |
语句在所有DN上的最大执行时间,单位ms。 |
|
|
17 |
average_dn_time |
语句在所有DN上的平均执行时间,单位ms。 |
|
|
18 |
dntime_skew_percent |
语句在各DN间的执行时间倾斜率。 |
|
|
19 |
min_cpu_time |
语句在所有DN上的最小CPU时间,单位ms。 |
E1: CPU执行时间是分配给该作业的实际执行时间,当duration有明显增加,而平均CPU执行时间无明显变化时,很可能的一个原因是作业执行期间,有多个其它计算密集型作业同时段执行,因CPU抢占的原因,拉长了该作业的执行时长。 |
|
20 |
max_cpu_time |
语句在所有DN上的最大CPU时间,单位ms。 |
|
|
21 |
total_cpu_time |
语句在所有DN上的CPU总时间,单位ms。 |
|
|
22 |
cpu_skew_percent |
语句在DN间的CPU时间倾斜率。 |
|
|
23 |
min_dn_time |
语句在所有DN上的最小执行时间,单位ms。 |
D1: DN上的执行时间,结合duration数据,如果一个查询在DN执行时间有严重倾斜,那就需要考虑数据表的分区、分布列是否设置合适;不合理的分区、分布列,可能会导致本应分散到多个DN的执行任务被集中到个别DN上执行,执行时间必然大大增加。 |
|
24 |
max_dn_time |
语句在所有DN上的最大执行时间,单位ms。 |
|
|
25 |
average_dn_time |
语句在所有DN上的平均执行时间,单位ms。 |
|
|
26 |
dntime_skew_percent |
语句在各DN间的执行时间倾斜率。 |
|
|
27 |
min_peak_iops |
语句在所有DN上的每秒最小IO峰值。 |
F1: IO是最变化莫测的一个资源,一个作业在数据量、内存消耗、CPU执行时间、下盘量都无变化的情况下,偏偏duration增加了,那最可能的原因是IO变化导致。IO的特点是,IOPS变小表示作业执行时间变慢,即IO跑不起来,拖长了作业执行时间;而其它属性通常相反,如:内存、CPU、下盘量,这些值变小通常意味着作业执行变快了。 |
|
28 |
max_peak_iops |
语句在所有DN上的每秒最大IO峰值。 |
|
|
29 |
average_peak_iops |
语句在所有DN上的每秒平均IO峰值。 |
|
|
30 |
iops_skew_percent |
语句在DN间的IO倾斜率。 |
|
|
31 |
query_plan |
语句的执行计划。 |
G1: 作业执行计划是否有变化。 |
|
32 |
unique_sql_id |
标识一类语句。 |
H1: 如果某类语句可能占用较多内存或者CPU资源,需要终止,可利用 gs_append_blocklist(unique_sql_id int8) 或者 gs_append_blocklist(sql_hash text) 函数将该类语句加入黑名单,后续该类语句下发将不再执行。 |
|
33 |
sql_hash |
||
|
34 |
enqueue |
语句的排队状态。 |
I1:作业是否异常排队/排队时间过久。可能出现的几种情况有:
|
|
35 |
warning |
语句的告警信息及SQL自诊断调优相关告警,常见的warning信息参见表4。 |
J1:可能出现的异常有下面几类告警:
|
总结:
- 因数据量变化,导致作业执行时间增加,可以分析A2/B1/D1/G1,进而确认作业查询的数据表是否有明显的数据量增加。
- 由于目前历史TopSQL视图字段信息较多,建议使用PGXC_QUERY_INFO视图查看查询经典字段信息,无需手动过滤无关字段。
- 因其它并发作业抢占,导致作业排队,进而导致作业执行时间增加,可以分析A1/B1/D1,查看作业执行的同时期是否有大量并发作业在执行。
- 因其它作业而产生的CPU抢占,导致作业执行时间增加,可以分析A2/D1/E1,进而查看作业执行的同时期是否有大量并发作业在执行。
- 因其它作业而产生的IO抢占,导致作业执行时间增加,可以分析A2/F1,进而查看作业执行的同时期是否有大量并发作业在执行。
- 禁止某一类语句执行,可参考H1。
值得注意的是,发生资源争抢时,可能会出现并发现象,即CPU、IO抢占,作业排队现象都会发生,针对并发问题,可以逐步分析解决,比如:
- 调整作业执行顺序,减少并发作业数量,减少阻塞时间。
- 定位出同时段执行的典型计算密集型、存储密集型作业,先移动到其它时间段执行,减少对本作业的影响。
- 在无其他作业明显干预的情况下,做进一步分析。
|
场景分类 |
具体信息 |
解决方法 |
|---|---|---|
|
下盘量过大或过早下盘 |
The max spill size exceeds the alarm size xxxMB |
下盘可能是因为缓冲区设置过小,也可能是因为表的连接顺序或连接方式不合理等原因导致,要结合具体的SQL进行分析,可通过改写SQL语句或者通过Plan Hint指定连接方式等手段解决。 |
|
The max broadcast size exceeds the alarm size xxxMB |
||
|
Early spill |
||
|
Spill times is greater than 3 |
||
|
Spill on memory adaptive |
||
|
Hash table conflict |
||
|
统计信息 |
Nestloop in hashjoin |
有可能统计信息不准确,及时对相关业务表进行analyze操作。 |
|
Table whose delta data exceeds 10% cannot be analyzed on VW |
弹性VW场景下,不支持analyze,此为规格限制。 |
|
|
Replication table cannot be analyzed on VW in temporary table sampling mode. |
||
|
Table cannot be analyzed on VW when enable_paralled_analyze is disabled in temporary table sampling mode. |
||
|
Replication table with more than 100,000 rows cannot be analyzed on VW. |
||
|
弹性VW |
Concurrent scaling is not supported because the statement is in a transation block. |
弹性VW负载均衡功能开启后,作业未能路由到弹性VW,此为规格限制。 |
|
Concurrent scaling is not supported because the statement is a stored procedure. |
||
|
Concurrent scaling is not supported because the statement is not of the DML type. |
||
|
Concurrent scaling is not supported because the statement involves tables except V3 tables and foreign tables. |
||
|
Concurrent scaling is not supported because the statement does not support the cudesc streaming. |
||
|
Concurrent scaling is not supported because the resource pool associated with the statement disables the concurrency extension parameter. |
||
|
Concurrent scaling is not supported because the statement does not support cn retry. |
||
|
物化视图 |
has others update base table, can not active matview. |
物化视图刷新告警,此为规格限制。 |
TopSQL约束与限制
- TopSQL不记录白名单和内部语句,但可正常记录超户下发的语句信息,可记录定时任务。
- query和perf级别的TopSQL监控主要差异点在于query_plan字段,相比于query级别的算子信息,perf级别的query_plan字段增加算子的实际信息,如算子实际内存峰值,内存自动扩展信息,CU,Buffers等统计信息。
- query和perf级别实时TopSQL和历史TopSQL的start_time字段信息含义不一致,实时TopSQL中的start_time表示的是作业下发的时间,历史TopSQL中的start_time表示的是作业真正开始运行的时间。
- 查询历史TopSQL Query,perf以及算子级别数据时,仅能连接postgres数据库进行查询。
- 实时TopSQL中能够记录的SQL语句的规格是:
- 不记录特殊数据定义语句,如:SET、RESET、SHOW、ALTER SESSION SET、SET CONSTRAINTS语句。
- 记录数据定义语句,例如:执行CREATE、ALTER、DROP、GRANT、REVOKE和VACUUM语句。
- 记录数据操作语句,例如:
- 执行SELECT、INSERT、UPDATE和DELETE语句。
- 执行explain analyze和explain performance场景。
- 使用query级别/perf级别视图。
- 记录函数与存储过程的调用入口语句,当GUC参数enable_track_record_subsql开启的情况下,可记录存储过程的部分内部语句(declare定义语句除外),仅会记录其中下发到DN执行的内部语句,未下发到DN执行的内部语句会被过滤掉。
- 记录匿名块语句,当GUC参数enable_track_record_subsql开启的情况下,可记录匿名块中的部分内部语句,仅会记录其中下发到DN执行的内部语句,未下发到DN执行的内部语句会被过滤掉。
- 记录游标语句,当游标并未从缓存中读取数据,而确实触发语句下发到DN上执行的条件下,该游标语句会被记录,并且会进行语句、执行计划增强,但当游标从缓存中读取数据时,不进行记录;当游标语句在匿名块或者函数中使用时,当游标从DN上读取较多数据但不完全使用时,因当前架构限制,无法记录该游标在DN上的监控信息。对于With Hold游标,由于该语法执行逻辑较特殊,会在事务提交阶段执行实际查询动作,当语句在该阶段执行报错时,作业的aborted状态无法反馈到TopSQL历史表中。
- 重分布过程中的作业不统计。
- JDBC执行的带占位符语句,通常会补齐参数内容,但如果参数和原语句合起来长度超过64KB,则不记录参数,或者如果是轻量化语句,直接下发到DN上执行,不记录参数。如果普通语句超过64KB,在TopSQL的query字段记录中将被截断。
- 8.1.3及以上集群版本,query、perf级别TopSQL运行时监控功能已完全不影响查询性能,对当前会话的语句进行资源监控的GUC参数resource_track_cost默认值已修改为0,查询TopSQL实时监控视图时,默认会显示所有正在执行的语句。
- 8.1.3及以上集群版本,对于存储过程中的子语句监控功能,如果在查询TopSQL实时监控视图的会话中,开启控制子语句记录归档功能的GUC参数enable_track_record_subsql,不论业务语句中是否开启子语句监控开关,查询TopSQL实时监控视图的结果都能看到执行语句的子语句运行信息。
- 关于存储过程中子语句的监控功能即enable_track_record_subsql,8.1.3集群版本中建议不要全面开启,由于没有按时间过滤子语句的功能,全面开启可能会记录过多子语句,导致归档的监控表占用大量磁盘空间;8.1.3集群版本建议仅用于查询实时监控信息,或对个别存储过程业务做定位分析时,仅开启对应会话中的参数。8.2.1版本新增GUC参数resource_track_subsql_duration(默认值为180秒),可以通过执行时间过滤需要归档的子语句,用户可以按需调整该值大小。
- 由于规格限制,对于未下盘的主语句,TopSQL历史表中的记录会有延时,等待下次作业下发时才会显示在TopSQL历史表中。
- 从8.2.1.200集群版本开始,新增operator_realtime级别的TopSQL运行时监控能力,提供算子级实时监控的能力,开启此级别的监控可以查询语句的执行计划以及具体执行信息,查询TopSQL算子级实时监控视图时,默认会显示所有正在执行的语句。但是对于存储过程和游标场景,暂时不支持显示算子级实时监控信息。
- operator_realtime级别TopSQL运行时监控对于CN轻量化和存储过程的情况,暂时不支持。另由于算子执行速度较快的原因,对于算子信息的显示会有一定滞后性。
- query级别的作业监控和operator的算子监控中的spill_size字段,由于统计维度不同,会有一定差异,query级别监控的语句实际下盘文件大小,算子监控的是具体算子在逻辑层IO读写的数据量。
- 当GUC参数enable_stream_operator设置为off状态时,算子执行信息存在显示不准的情况。
- 在8.1.3版本中,除初始用户外,enable_gtm_free开启且关联队列不管控情况下,用户作业不进入资源管控。此时实时与历史TopSQL均不记录该用户下发的作业。
通过TopSQL识别密集占用资源的SQL
- 识别stream数量多的语句:
SELECT *,(length(query_plan) - length(replace(query_plan, 'Streaming', ''))) / length('Streaming') AS stream_count FROM pgxc_wlm_session_info ORDER BY stream_count DESC limit 100;
- 识别内存占用高的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' ORDER BY max_peak_memory desc limit 100;
- 识别需要优化的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' AND warning is not null ORDER BY duration desc limit 100;
- 识别执行时间长的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' ORDER BY duration desc;
- 识别不下推的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' AND warning like ‘%can not be shipped%’ ORDER BY max_peak_memory desc;
- 识别高CPU语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' ORDER BY max_cpu_time desc;
- 识别下盘量大的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' ORDER BY max_cpu_time desc;
- 识别未做analyze的语句:
SELECT * FROM pgxc_wlm_session_info WHERE start_time > 'xxxx-xx-xx' AND start_time < 'xxxx-xx-xx' AND warning ilike '%statistics%';
监控PERT作业级别TopSQL
现网中有概率出现某一个SQL语句起初执行较快随后执行时间变长的情况,此时可以利用TopSQL中的query_plan以及其他资源信息进行分析定位,query_plan中的信息越详细,越接近于explain performance,定位过程就更容易。query级别与perf级别的TopSQL差异主要在query_plan,perf级别的TopSQL的query_plan字段可显示算子的时间actual_time,memory,rows和buffer等信息。

监控OPERATOR算子级的TopSQL
在SQL执行过程中,有些用户更希望能对算子执行进度进行监控,对于长时间运行的SQL,能够看出哪个算子执行时间长,通过算子执行时间和已处理行数等信息,确定是否需要查杀SQL,此时需要将resource_track_level参数设置为OPERATOR。
算子监控可以将SQL执行过程的算子监控数据以可视化的方式呈现出来,以便用户更加直观地了解算子的运行情况和性能表现。算子监控主要有以下价值:
- 提升用户体验:用户可以更加直观地了解算子的运行情况和性能。
- 性能优化:可以发现算子运行中的瓶颈和问题,进行优化和调整,提高算子的运行效率。
- 故障排查:可以及时发现算子运行中的问题和异常,进行修复和维护,提高SQL的可维护性。
- 提高算子的可扩展性:可以发现算子运行中的瓶颈和问题,及时进行优化和调整,提高算子的可扩展性,为后续的业务发展提供支持。
OPERATOR算子监控和QUERY/PERF语句监控功能类似,均包含实时和历史二种形态,包含静态和动态二类信息:
- 语句静态信息是语句在真正执行前就已经由优化器生成的信息,如执行计划plan_node_name,queryid,预估行数estimated rows等信息。可用来分析生成的执行计划是否合适。
- 语句动态信息是语句在执行器中执行过程中所占用的资源信息,如算子执行进度progress、内存peak_memory、算子下盘spill_size、网络net_size、磁盘IO(read_bytes、write_bytes),CPU(cpu_time)等不同DN的实时的信息记录。可用来分析语句执行过程中的进度和资源消耗情况,通过该字段可以分析出语句在运行时消耗较久的在什么地方,便于后续优化。
功能展示:下发某个查询,在另一个会话中查询实时算子视图pgxc_wlm_operator_statistics,结果如下:

TopSQL与其他视图交互
不同视图从不同维度统计业务在数据库中的运行状态,因为或多或少都包含部分同类字段,可用于后续关联分析,此处给出历史TopSQL视图常交互的其他视图:
使用示例:如果某个语句在历史pgxc_wlm_session_info视图中显示该作业很快运行完成,但在pgxc_stat_activity视图中发现该语句运行很长时间没有结束,则此时可能有异常,可利用以下步骤进行定位:
常用定位过程如下所示:
- 查询pgxc_stat_activity活跃视图,找出长时间运行不结束的异常作业。
SELECT coorname, usename, client_addr, now()-query_start as dur, state, enqueue, waiting, pid, query_id, substr(query,1,150) FROM pgxc_stat_activity WHERE usename not in ('omm','Ruby') AND state = 'active' ORDER BY dur DESC limit 100; - 根据1得到的query信息,查询历史TopSQL视图,比较以往和现在的运行情况,如果以前运行时间很快,但当前语句运行时间很长未结束,则可考虑该语句已发生异常(历史topsql视图按天分区,查询时尽量带start_time条件)。
SELECT * FROM pgxc_wlm_session_info WHERE start_time > '2024-08-22 00:00' AND start_time < '2024-08-24 00:00' AND query ilike '%XXXXXXXXX%' ORDER BY start_time;
- 根据1得到的query_id查询等待视图pgxc_thread_wait_status,得到作业线程号lwtid,并打出作业堆栈进行分析。
SELECT * FROM pgxc_thread_wait_status WHERE query_id = xxx; SELECT * FROM gs_stack('nodename',tid); # 本节点可直接 \! gstack lwtid
分析和处理TopSQL实践案例
通常情况下,TopSQL记录的信息较多, 查询时可使用start_time做条件,避免全表查询,且使用limit对结果集大小限制,防止结果集过大导致客户端异常。
- 案例1:某客户集群出现系统级性能问题,CPU持续飚高,业务受阻。
通过TopSQL历史视图查询到有10+业务SQL存在stream数超过100,判断为CPU高的原因:
SELECT *,(length(query_plan) - length(replace(query_plan, 'Streaming', ''))) / length('Streaming') as stream_count FROM pgxc_wlm_session_info ORDER BY stream_count DESC limit 100;
针对此业务SQL进行下线并进行优化后,问题解决。
- 案例2:业务语句性能下降,业务起初较快后来变慢。
因为TopSQL记录了一些语句的执行情况和资源消耗情况,在定位性能问题的时候非常有帮助,比如周期执行的SQL,突然有一天变慢了,可以通过分析语句的执行时间和阻塞时间判断是语句被阻塞了(排队等)还是执行慢了,通过记录的执行计划分析语句为什么慢了,是不是当时的统计信息统计不准,还是没有对表做ANALYZE,也可以根据下盘量大小分析是不是下盘量大造成的性能变慢。
- 通过pgxc_wlm_session_info视图确认历史的SQL信息(注:历史topsql视图按天分区,查询时尽量带start_time条件)。
SELECT * FROM pgxc_wlm_session_info WHERE start_time > '2023-08-22 00:00' AND start_time < '2023-08-24 00:00' AND query ilike '%XXXXXXXXX%' ORDER BY start_time;
- 根据作业的sql_hash信息确定作业的历史执行情况,借助历史TopSQL的资源信息和query_plan字段分析作业性能劣化原因。
SELECT start_time, block_time, duration, sql_hash, warning, max_peak_memory, max_spill_size, query_plan FROM pgxc_wlm_session_info were start_time > 'xxxx-xx-xx xx:xx' and sql_hash = 'xxx' ORDER BY start_time desc limit 10;
找到对应的快慢语句后,对比其执行计划query_plan,发现执行计划跳变严重。

- 对相应的表做ANALYZE后,恢复合理计划,语句性能恢复。
统计信息不准,导致计划跳变,是十分常见语句变慢原因,ANALYZE不影响读写,遇见语句变慢可预先做ANALYZE。
ANALYZE dwrdim_dw1.dwr_dim_region_rc_d;
- 通过pgxc_wlm_session_info视图确认历史的SQL信息(注:历史topsql视图按天分区,查询时尽量带start_time条件)。
- 案例3:作业长时间运行不结束。
在作业无排队无死锁正常运行期间,发现作业长时间不结束,此时可查看算子级别的实时TopSQL监控,能够看出哪个算子执行时间长,通过算子执行时间和已处理行数等信息,确定是否需要终止SQL。
- 开启实时算子监控:
SET resource_track_level = 'operator_realtime';

- 根据需要查杀作业
SELECT * FROM pg_terminate_backend(xxx); # 入参为pid
- 开启实时算子监控:
- 案例4:作业整体使用内存较高,需分析算子内存使用情况。
当发现作业内存整体使用较高,query级别的TopSQL无法记录算子的实际资源信息,此时可以设置TopSQL的监控级别为perf,query级别与perf级别的TopSQL差异主要在query_plan,perf级记录更详细执行信息,较query级性能损耗5%以内,perf级别的TopSQL的query_plan字段可显示算子的时间actual_time,memory,rows和buffer等信息。
