查询统计
mxstat 查询统计模块用来对查询信息进行统计,包括:
- 查询使用时间
- 查询资源消耗
1. 部署
该模块包含在 matrixmgr 扩展中,会随着系统默认安装。
[mxadmin@mdw ~]$ gpconfig -s shared_preload_libraries
Values on all segments are consistent
GUC : shared_preload_libraries
Master value: matrixts,matrixmgr,matrixgate,telemetry,mars
Segment value: matrixts,matrixmgr,matrixgate,telemetry,mars
但是要查看统计信息,必须创建 matrixmgr 数据库并在该数据库中创建 matrixmgr 扩展(MatrixDB 集群初始化后会默认创建数据库和扩展)。
createdb matrixmgr
psql -d matrixmgr
matrixmgr=# CREATE EXTENSION matrixmgr CASCADE;
NOTICE: installing required extension "matrixts"
CREATE EXTENSION
2. 表结构
部署成功后,在 matrixmgr 数据库的 matrixmgr_internal 模式下会出现如下表和视图:
- mx_query_execute_history
- mx_query_execute_history_with_text
- mx_query_usage_history
- mx_querytext
- mxstat_execute
- mxstat_usage
2.1 mxstat_execute
查询执行信息视图。
该视图展示了系统从上次收集历史信息完毕后(默认 5 分钟),运行查询的统计信息。包括如下字段:
字段名 | 类型 | 描述 |
---|---|---|
seg | integer | 查询生成并下发计划节点编号 |
userid | oid | 用户 OID |
dbid | oid | 数据库 OID |
queryid | bigint | 查询 ID,由扩展生成,用来将相同类型的查询进行归类 |
nestlevel | integer | 嵌套深度 |
query | text | 查询文本 |
calls_begin | bigint | 查询启动次数 |
calls_alive | bigint | 上次收集历史信息时,处于执行状态的查询数 |
calls_end | bigint | 查询正常结束次数 |
total_time | double precision | 该类查询总执行时间,单位毫秒 |
min_time | double precision | 该类型查询最短执行时间,单位毫秒 |
max_time | double precision | 该类查询最长执行时间,单位毫秒 |
mean_time | double precision | 该类查询平均执行时间,单位毫秒 |
stddev_time | double precision | 该类查询执行时间标准差,单位毫秒 |
sample_planid | bigint | 执行计划ID |
sample_start | timestamp with time zone | 最慢查询启动时间戳 |
sample_parse_done | timestamp with time zone | 最慢查询完成解析时间戳 |
sample_plan_done | timestamp with time zone | 最慢查询生成计划时间戳 |
sample_exec_start | timestamp with time zone | 最慢查询开始执行时间戳 |
sample_exec_end | timestamp with time zone | 最慢查询执行完毕时间戳 |
2.2 mxstat_usage
查询资源消耗信息视图。
该视图展示了系统从上次收集历史信息完毕后(默认 5 分钟),运行查询的资源消耗信息。包括如下字段:
字段名 | 类型 | 描述 |
---|---|---|
seg | integer | 查询执行节点编号 |
userid | oid | 用户 OID |
dbid | oid | 数据库 OID |
queryid | bigint | 查询 ID,由扩展生成,用来将相同类型的查询进行归类 |
nestlevel | integer | 嵌套深度 |
rows | bigint | 该语句检索或影响的行总数 |
shared_blks_hit | bigint | 该语句造成的共享块缓冲命中总数 |
shared_blks_read | bigint | 该语句读取的共享块的总数 |
shared_blks_dirtied | bigint | 该语句弄脏的共享块的总数 |
shared_blks_written | bigint | 该语句写入的共享块的总数 |
local_blks_hit | bigint | 该语句造成的本地块缓冲命中总数 |
local_blks_read | bigint | 该语句读取的本地块的总数 |
local_blks_dirtied | bigint | 该语句弄脏的本地块的总数 |
local_blks_written | bigint | 该语句写入的本地块的总数 |
temp_blks_read | bigint | 该语句读取的临时块的总数 |
temp_blks_written | bigint | 该语句写入的临时块的总数 |
blk_read_time | double precision | 该语句花在读取块上的总时间,以毫秒计 |
blk_write_time | double precision | 该语句花在写入块上的总时间,以毫秒计 |
ru_utime | double precision | 用户态 CPU 时间 |
ru_stime | double precision | 系统态 CPU 时间 |
ru_maxrss | bigint | 实际使用物理内存,包含共享库占用的内存,单位 KB |
ru_ixrss | bigint | 集成共享内存大小 |
ru_idrss | bigint | 集成非共享数据大小 |
ru_isrss | bigint | 集成非共享堆栈大小 |
ru_minflt | bigint | 缺页中断的次数,且处理这些中断不需要进行 I/O |
ru_majflt | bigint | 缺页中断的次数,且处理这些中断需要进行 I/O |
ru_nswap | bigint | 交换空间 |
ru_inblock | bigint | 文件系统需要进行输入操作的次数 |
ru_oublock | bigint | 文件系统需要进行输出操作的次数 |
ru_msgsnd | bigint | 消息发送数量 |
ru_msgrcv | bigint | 消息接收数量 |
ru_nsignals | bigint | 接收信号数量 |
ru_nvcsw | bigint | 因进程自愿放弃处理器时间片而导致的上下文切换的次数 |
ru_nivcsw | bigint | 因进程时间片使用完毕或被高优先级进程抢断导致的上下文切换的次数 |
2.3 mx_query_execute_history
该表为分区表,是 mxstat_execute 视图的历史信息收集,默认5分钟一次。其表结构和 mxstat_execute 视图一致,只是多了一个 ts_bucket 字段,记录收集的时间点。
2.4 mx_query_usage_history
该表为分区表,是 mxstat_usage 视图的历史信息收集,默认5分钟一次。其表结构和 mxstat_usage 视图一致,只是多了一个 ts_bucket 字段,记录收集的时间点。
2.5 mx_querytext
存储 queryid 与 querytext 的映射,和其他历史信息收集表一样,周期存储,目的是使历史查询可以获取 SQL 文本。
2.6 mx_query_execute_history_with_text
将 mx_query_execute_history 与 mx_querytext 通过 queryid 进行关联后的视图。同时读取历史查询统计信息和 SQL 文本。
3. 使用方法
3.1 查询归类方法
mxstat 统计查询信息,并不是将每条查询都记录,而是将一类查询统一汇总。查询按照解析结果进行归类。
如下查询,都是向 test1 表插入数据,只是参数不同,这些查询会生成相同的 queryid,归位一类。
INSERT INTO test1 VALUES(1);
INSERT INTO test1 VALUES(2);
INSERT INTO test1 VALUES(3);
如下查询只是条件参数不同,其他都一样,也会归位一类。
SELECT * FROM test1 WHERE c1 = 1;
SELECT * FROM test1 WHERE c1 = 2;
SELECT * FROM test1 WHERE c1 = 3;
如下查询虽然相似,但是查询的是不同的表,不能归位一类。
SELECT * FROM test1 WHERE c1 = 1;
SELECT * FROM test2 WHERE c1 = 1;
SELECT * FROM test3 WHERE c1 = 1;
3.2 使用案例
下面举例来看如何使用 mxstat 来查看查询统计信息。
案例1
执行如下3条SQL语句:
select pg_sleep(5);
select pg_sleep(10);
select pg_sleep(15);
然后查询 mxstat_execute 的统计信息:
matrixmgr=# select * from matrixmgr_internal.mxstat_execute where query like '%pg_sleep%';
seg | userid | dbid | queryid | nestlevel | query | calls_begin | calls_alive | calls_end | total_time | min_time
| max_time | mean_time | stddev_time | sample_planid | sample_start | sample_parse_done |
sample_plan_done | sample_exec_start | sample_exec_end
-----+--------+-------+----------------------+-----------+---------------------+-------------+-------------+-----------+------------+----------
+-----------+--------------------+-------------------+----------------------+-------------------------------+-------------------------------+--
-----------------------------+-------------------------------+-------------------------------
-1 | 10 | 16384 | -2007749946425010549 | 0 | select pg_sleep($1) | 3 | 0 | 3 | 30041 | 5009.054
| 15018.717 | 10013.666666666666 | 4086.427819588182 | -2693056513545111817 | 2022-03-25 13:58:58.503851-04 | 2022-03-25 13:58:58.503933-04 | 2
022-03-25 13:58:58.503994-04 | 2022-03-25 13:58:58.504008-04 | 2022-03-25 13:59:13.522725-04
(1 row)
从视图结果可以看出,查询被调用了 3 次,并且 query 文本也做了归一化,将时间参数替换成了 $ + 参数序号。查询执行的总时间、最大时间、最小时间、平均时间与预期一致。并且记录了最慢一次查询执行各个阶段的时间戳,即 select pg_sleep(15),休息 15 秒的查询。
然后再查看一下该语句资源使用情况,这个就需要用到 mxstat_execute.queryid 做关联:
matrixmgr=# select * from matrixmgr_internal.mxstat_usage where queryid = -2007749946425010549;
seg | userid | dbid | queryid | nestlevel | rows | shared_blks_hit | shared_blks_read | shared_blks_dirtied | shared_blks_writte
n | local_blks_hit | local_blks_read | local_blks_dirtied | local_blks_written | temp_blks_read | temp_blks_written | blk_read_time | blk_write
_time | ru_utime | ru_stime | ru_maxrss | ru_ixrss | ru_idrss | ru_isrss | ru_minflt | ru_majflt | ru_nswap | ru_inblock | ru_oublock | ru_msgs
nd | ru_msgrcv | ru_nsignals | ru_nvcsw | ru_nivcsw
-----+--------+-------+----------------------+-----------+------+-----------------+------------------+---------------------+-------------------
--+----------------+-----------------+--------------------+--------------------+----------------+-------------------+---------------+----------
------+----------+----------+-----------+----------+----------+----------+-----------+-----------+----------+------------+------------+--------
---+-----------+-------------+----------+-----------
-1 | 10 | 16384 | -2007749946425010549 | 0 | 3 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0.001297 | 0.000431 | 20568 | 0 | 0 | 0 | 6 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 122 | 0
(1 row)
从查询结果可以看到该查询仅在 master 节点上执行过,所以仅有一条 seg=-1 的记录。
案例2
下面再看一个例子:
create table test1(c1 int, c2 int) distributed by(c1);
然后查询 mxstat_execute 的统计信息:
matrixmgr=# select * from matrixmgr_internal.mxstat_execute where query like '%create table test1%';
seg | userid | dbid | queryid | nestlevel | query | calls_begin | calls_alive |
calls_end | total_time | min_time | max_time | mean_time | stddev_time | sample_planid | sample_start | sample_parse_done | sa
mple_plan_done | sample_exec_start | sample_exec_end
-----+--------+-------+----------------------+-----------+-------------------------------------------------------+-------------+-------------+-
----------+------------+----------+----------+-----------+-------------+---------------+-------------------------------+-------------------+---
---------------+-------------------------------+-------------------------------
-1 | 10 | 16384 | -6276724884379903029 | 0 | create table test1(c1 int, c2 int) distributed by(c1) | 1 | 0 |
1 | 46.221 | 46.221 | 46.221 | 46.221 | 0 | 0 | 2022-03-25 14:08:51.754458-04 | |
| 2022-03-25 14:08:51.754735-04 | 2022-03-25 14:08:51.800956-04
(1 row)
再查看一下该语句资源使用情况:
matrixmgr=# select * from matrixmgr_internal.mxstat_usage where queryid = -6276724884379903029;
seg | userid | dbid | queryid | nestlevel | rows | shared_blks_hit | shared_blks_read | shared_blks_dirtied | shared_blks_writte
n | local_blks_hit | local_blks_read | local_blks_dirtied | local_blks_written | temp_blks_read | temp_blks_written | blk_read_time | blk_write
_time | ru_utime | ru_stime | ru_maxrss | ru_ixrss | ru_idrss | ru_isrss | ru_minflt | ru_majflt | ru_nswap | ru_inblock | ru_oublock | ru_msgs
nd | ru_msgrcv | ru_nsignals | ru_nvcsw | ru_nivcsw
-----+--------+-------+----------------------+-----------+------+-----------------+------------------+---------------------+-------------------
--+----------------+-----------------+--------------------+--------------------+----------------+-------------------+---------------+----------
------+----------+----------+-----------+----------+----------+----------+-----------+-----------+----------+------------+------------+--------
---+-----------+-------------+----------+-----------
-1 | 10 | 16384 | -6276724884379903029 | 0 | 0 | 295 | 59 | 21 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0.004053 | 0 | 22744 | 0 | 0 | 0 | 429 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 6 | 0
1 | 10 | 16384 | -6276724884379903029 | 0 | 0 | 261 | 82 | 19 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0.001691 | 0.001558 | 19284 | 0 | 0 | 0 | 510 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 1
0 | 10 | 16384 | -6276724884379903029 | 0 | 0 | 314 | 34 | 19 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0.002537 | 0.000193 | 18508 | 0 | 0 | 0 | 574 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 1 | 1
2 | 10 | 16384 | -6276724884379903029 | 0 | 0 | 261 | 82 | 19 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0.003043 | 2.9e-05 | 19292 | 0 | 0 | 0 | 514 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 2
(4 rows)
从查询结果可以看到,该查询在每个节点上都要创建表,所以所有节点都会记录资源使用状况。
案例3 从上面的执行结果可以看到,在 mxstat_execute 中,nestlevel 值都为 0,因为查询执行都没有嵌套。下面构造一种嵌套执行的例子。嵌套执行通常是通过调用 UDF 来实现。
CREATE OR REPLACE FUNCTION nest_query() RETURNS SETOF RECORD
AS $$ SELECT 1;$$
LANGUAGE SQL;
创建名为 nest_query 的 UDF,函数内部调用了 SQL:SELECT 1。然后调用该 UDF。
注意:mxstat 默认不会记录嵌套信息,需要将 mxstat_statements.track 设置为'all'。
mxadmin=# SET mxstat_statements.track TO 'all';
SET
mxadmin=# select nest_query();
nest_query
------------
(1)
(1 row)
然后查询内部语句 SELECT 1
的执行信息。因为 1 是常量,所以归一化后的 query 会用 $1 替换:
matrixmgr=# select * from matrixmgr_internal.mxstat_execute where query like '%SELECT $1%';
seg | userid | dbid | queryid | nestlevel | query | calls_begin | calls_alive | calls_end | total_time | min_time | max_time
| mean_time | stddev_time | sample_planid | sample_start | sample_parse_done | sample_plan_done
| sample_exec_start | sample_exec_end
-----+--------+-------+----------------------+-----------+-----------+-------------+-------------+-----------+------------+----------+---------
-+-----------+-------------+---------------------+-------------------------------+-------------------------------+-----------------------------
--+-------------------------------+-------------------------------
-1 | 10 | 16384 | -4554727679305370053 | 1 | SELECT $1 | 1 | 0 | 1 | 0.031 | 0.031 | 0.031
| 0.031 | 0 | -382705668420232707 | 2022-03-25 14:35:30.668124-04 | 2022-03-25 14:35:30.668373-04 | 2022-03-25 14:35:30.668403-0
4 | 2022-03-25 14:35:30.668408-04 | 2022-03-25 14:35:30.668439-04
(1 row)
可以看到,这次 nestlevel 的值为 1,因为嵌套调用的深度为 1。如果嵌套更深的话,nestlevel 的值会更大,mxstat 最深会记录到第 31 层。
4. 配置
mxstat 包含了如下 GUC,用来控制监控行为:
名称 | 类型 | 描述 |
---|---|---|
mxstat_statements.max | 整型 | 存储查询时间的哈希槽位。默认 5000 |
mxstat_statements.usage_multiple | 整型 | 存储查询资源信息的哈希槽位相对于查询时间哈希槽位的倍数,大一些的原因是希望每个查询都能找到对应的资源消耗信息。默认为 2 |
mxstat_statements.track | 字符串 | top:只跟踪第一层,不进行嵌套跟踪(默认)。 all:跟踪全部。 none:不跟踪,相当于关闭了该功能 |
mxstat_statements.track_utility | 布尔 | 是否跟踪 utility 语句的执行,默认为 true |
mxstat_statements.save | 布尔 | 当集群重启的时候是否将共享内存中的信息转储到文件,默认为 true |
mxstat_statements.harvest_interval | 整型 | 查询统计信息默认在共享内存里,会周期收集到历史表中,该 GUC 用来设置采集周期。默认为 5 分钟 |