在压测调优时,有两个方向,一是tpcc这类型的压力测试调优,这种测试主要是标准模型化的测试;另外一种是业务功能压力测试调优,这种就是模拟业务压力,直接测试业务功能。
其中,业务功能压力测试是业务直接使用jmeter等工具,直接触发业务功能,或者直接执行业务sql,并发请求数据库,对数据库进行压力测试。该类测试中请求的sql是客户业务代码中真实使用的,在测试中如果性能存在问题,需要对执行的sql进行分析优化。
在业务功能压力测试进行sql优化时,最常用的就是查找业务慢sql,根据执行计划优化sql,今天我们一起来聊聊GaussDB慢sql信息收集和执行计划查看。
一、在业务功能压力测试时查找慢sql
GaussDB数据库在运行时,如果有开启慢sql记录的话,会在系统视图中记录对应的sql信息,在分析慢sql时,可以根据下面步骤操作:
1、检查慢sql记录相关参数
步骤一:log_min_duration_statement
参数说明:当某条语句的持续时间大于或者等于特定的毫秒数时,sql信息会记录到系统表。
该参数属于SUSET类型参数,可以使用reload设置。
css
gs_guc reload -Z datanode -N all -I all -c "log_min_duration_statement=10ms"
注意:这里的命令里,all后面是-i,如果是分布式,需要在-Z datanode 前/后 加上-Z coordinator,文档下面的gs_guc命令相同
取值范围:整型,-1~ 2147483647,单位为毫秒。
设置为250,所有运行时间不短于250ms的sql语句都会被记录。设置为0,输出所有语句的持续时间。
设置为-1,关闭此功能。
默认值:3s(即3000ms)
推荐值:根据客户实际要求设置。
步骤二:track_stmt_stat_level
参数说明:控制语句执行跟踪的级别。
该参数属于USERSET类型参数,可以使用reload设置。
取值范围:字符型
该参数分为两部分,形式为'full sql stat level, slow sql stat level'
第一部分为全量sql跟踪级别,取值范围为OFF、L0、L1、L2
第二部分为慢sql的跟踪级别,取值范围为OFF、L0、L1、L2
默认值:OFF,L0
推荐值:分析慢sql时,可以设置为L0,L1。
css
gs_guc reload -Z datanode -N all -I all -c "track_stmt_stat_level='L0,L1'"
步骤三:track_stmt_parameter
参数说明:开启track_stmt_parameter后,在statement_history中记录的执行语句不再进行归一化操作,可以显示完整sql语句信息,辅助DBA进行问题定位。
其中对于简单查询,显示完整语句信息;对于PBE语句,显示完整语句信息的同时,追加每个变量数值信息,格式为"query string;parameters:1=value1,2=value2,..."。该参数提供目的是为用户呈现完整sql信息,不受track_activity_query_size参数控制。
该参数属于SIGHUP类型参数,可以使用reload设置。
取值范围:布尔型
on:表示开启显示完整sql语句信息的功能
off:表示关闭显示完整sql语句信息的功能
默认值:off
推荐值:分析慢sql时,可以设置为on。
css
gs_guc reload -Z datanode -N all -I all -c "track_stmt_parameter='on'"
步骤四:track_activity_query_size
参数说明:设置用于跟踪每一个活动会话的当前正在执行命令的字节数。
该参数属于POSTMASTER类型参数,需要使用set设置(set方式设置的需要重启数据库)。
取值范围:整型,100~102400,单位为byte
默认值:1024
推荐值:根据客户的sql长度设置。
css
gs_guc set -Z datanode -N all -I all -c "track_activity_query_size=10000"
2、执行脚本,清空当前记录的所有慢sql信息
该sql要在postgres库下执行,会清空dbe_perf.summary_statement和dbe_perf.statement_history等表/视图中数据。
css
select reset_unique_sql( 'GLOBAL','ALL','0') ;
3、客户运行业务,数据库根据sql执行时间把慢sql信息记录到系统表和视图
4、登录数据库对应表/视图,查看慢sql信息
该示例sql要在postgres库下执行,具体字段意义可以参考数据库产品文档,根据实际情况修改sql。这里是按sql总执行时间排序,可以根据实际情况修改,比如按sql平均执行时间排序。
为了方便分析,并且排除非业务数据库的影响,可以把表中数据备份
css
`create table public.huawei_t03 as selec * from dbe_perf.summary_statement;`
5、根据实际需要,得到dbe_perf.summary_statement表中sql的唯一id(归一化sql id),即表中unique_sql_id字段值
6、根据得到的归一化sql id,查看sql具体信息
两个示例sql要在postgres库下执行,根据需要备份相关数据:
方法一:使用函数取该sql取最近一个小时的数据。
css
select *, pg_catalog. statement_detail_decode(details, 'plaintext', true) from (select * from dbe_perf.get_global_full_sql_by_timestamp(now() - 1 / 24, now())) a where unique_query_id = 1647590198 order by db_time desc limit 1;
sql结果中有执行的sql语句(包含sql参数),执行计划,软解析次数,硬解析次数等等。
方法二:从dbe_perf.statement_history表中取
css
select * from dbe_perf.statement_history where start_time >= '2023-09-26 22:15:00' and user_name <> 'rdsAdmin';
在客户执行业务时,也可以查看实时会话,从会话中找到比较慢的sql,示例为分布式数据库执行sql,主备单机查询表为pg_stat_activity,注意分布式和主备板字段可能存在差异,根据实际情况修改示例sql。
css
select coorname, unique_sql_id, now() - query_start as use_time, query, query_start, state_change, backend_start, xact_start from pgxc_stat_activity where state <> 'idle' and query_start is not null order by 5 desc; --分布式查看实时会话
css
select unique_sql_id, now() - query_start as use_time, query, query_start, state_change, backend_start, xact_start from pg_stat_activity where state <> 'idle' and query_start is not null order by 5 desc; --主备查看实时会话
二、sql执行计划查看
数据库执行计划是数据库系统在执行sql查询时所采用的具体步骤的详细描述。它显示了数据库如何访问数据,包括表的扫描方式、索引的使用、连接方法等。通过执行计划,我们可以了解查询的执行路径,从而找到性能瓶颈并进行优化。
通过分析执行计划,可以识别出性能瓶颈,如全表扫描、索引使用不当等,并采取相应的优化措施,比如创建或调整索引、重写查询语句等。执行计划是数据库性能优化的重要工具,可以帮助开发者和数据库管理员提升查询效率和系统性能。
在不同的数据库系统中,查看sql执行计划的方法各有不同。GaussDB和PG数据库一样,可以使用EXPLAIN命令可以查看优化器为每个查询生成的具体执行计划。
1、如何启动执行计划
css
explain select 投影列 FROM 表名 WHERE 条件
2、Explain分析示例
EXPLAIN给每个执行节点都输出一行,显示基本的节点类型和优化器为执行这个节点预计的开销值。
最底层节点是表扫描节点,它扫描表并返回原始数据行。不同的表访问模式有不同的扫描节点类型:顺序扫描、索引扫描等。最底层节点的扫描对象也可能是非表行数据(不是直接从表中读取的数据),如VALUES子句和返回行集的函数,它们有自己的扫描节点类型。
如果查询需要连接、聚集、排序或者对原始行做其他操作,那么就会在扫描节点上添加其他节点。并且这些操作通常都有多种方法,因此在这些位置也有可能出现不同的执行节点类型。
第一行(最上层节点)是执行计划总执行开销的预计。这个数值就是优化器试图最小化的数值。
3、语法格式
显示sql语句的执行计划,支持多种选项,对选项顺序无要求。
css
`EXPLAIN [ ( option [, ...] ) ] statement;`
其中选项option子句的语法为。
css
ANALYZE [ boolean ] | VERBOSE [ boolean ] | COSTS [ boolean ] | CPU [ boolean ] | DETAIL [ boolean ] | NODES [ boolean ] |(仅分布式模式可用,集中式模式不可用) NUM_NODES [ boolean ] |(仅分布式模式可用,集中式模式不可用) BUFFERS [ boolean ] | TIMING [ boolean ] | PLAN [ boolean ] | BLOCKNAME [ boolean ] | OUTLINE [ boolean ] | ADAPTCOST [ boolean ] | FORMAT { TEXT | XML | JSON | YAML } OPTEVAL [ boolean ]
显示sql语句的执行计划,且要按顺序给出选项。
css
EXPLAIN { [ ANALYZE ] [ VERBOSE ] } statement;
参数说明:
statement 指定要分析的sql语句。
ANALYZE boolean 显示实际运行时间和其他统计数据。当两个参数同时使用时,在option中排在后面的一个生效。
取值范围:
TRUE(缺省值):显示实际运行时间和其他统计数据。
FALSE:不显示。
VERBOSE boolean 显示有关计划的额外信息。
取值范围:
TRUE(缺省值):显示额外信息。
FALSE:不显示。
COSTS boolean 包括每个规划节点的估计总成本,以及估计的行数和每行的宽度。
取值范围:
TRUE(缺省值):显示估计总成本和宽度。
FALSE:不显示。
CPU boolean 打印CPU的使用情况的信息。需要结合ANALYZE选项一起使用。
取值范围:
TRUE(缺省值):显示CPU的使用情况。
FALSE:不显示。
DETAIL boolean 打印数据库节点上的信息。需要结合ANALYZE选项一起使用。
取值范围:
TRUE(缺省值):打印数据库节点的信息。
FALSE:不打印。
NODES boolean(仅分布式模式可用,集中式模式不可用)打印query执行的节点信息。
取值范围:
TRUE(缺省值):打印执行的节点的信息。
FALSE:不打印。
NUM_NODES boolean(仅分布式模式可用,集中式模式不可用)打印执行中的节点的个数信息。
取值范围:
TRUE(缺省值):打印数据库节点个数的信息。
FALSE:不打印。
BUFFERS boolean 包括缓冲区的使用情况的信息。需要结合ANALYZE选项一起使用。
取值范围:
TRUE:显示缓冲区的使用情况。
FALSE(缺省值):不显示。
TIMING boolean 包括实际的启动时间和花费在输出节点上的时间信息。需要结合ANALYZE选项一起使用。
取值范围:
TRUE(缺省值):显示启动时间和花费在输出节点上的时间信息。
FALSE:不显示。
PLAN 是否将执行计划存储在plan_table中。当该选项开启时,会将执行计划存储在plan_table中,不打印到当前屏幕,因此该选项为on时,不能与其他选项同时使用。
取值范围:
ON(缺省值):将执行计划存储在plan_table中,不打印到当前屏幕。执行成功返回EXPLAIN SUCCESS。
OFF:不存储执行计划,将执行计划打印到当前屏幕。BLOCKNAME boolean 是否显示计划的每个操作所处于的查询块。当该选项开启时,会将每个操作所处于的查询块的名字输出在Query Block列上,方便用户获取查询块名字,并使用Hint修改执行计划:
TRUE(缺省值):显示计划时,将每个操作所处于的查询块的名字输出在新增列Query Block列上。该选项需要在pretty模式下使用。
FALSE:不对计划显示产生影响。
OUTLINE boolean 是否显示计划的Outline Hint信息。
ON:显示计划时,将Outline Hint显示在计划下方 。
OFF(缺省值):不显示计划的Outline Hint信息。
ADAPTCOST boolean 在Normal模式下是否显示计划的基数估计方式信息。
ON(缺省值):Normal模式下,在计划节点上展示基数估计的方式,包含默认方式和反馈方式,不对预备语句生效。
OFF:不展示基数估计的方式信息。FORMAT指定输出格式。
取值范围:
TEXT,XML,JSON和YAML。默认值:TEXT。
PERFORMANCE 使用此选项时,即打印执行中的所有相关信息。下述为部分信息描述:
ex c/r:代表平均每行使用cpu周期数,等于(ex cyc)/(ex row)。
ex row:执行行数。
ex cyc:代表使用的cpu周期数。
inc cyc:代表包含子节点使用的总cpu周期数。
shared hit:代表算子的share buffer命中情况。
loops:算子循环执行次数。
total_calls:生成元素总数。
remote query poll time stream gather:算子用于侦听各DN数据到达CN的网络poll时间。
deserialize time:反序列化所需时间。
estimated time:估计时间。
OPTEVAL boolean 是否显示SCAN算子(当前仅支持seqscan、indexscan、indexonlyscan、bitmapheapscan)的代价淘汰明细,当开启此开关的时候,会在执行计划中显示一个名字为Cost Evaluation Info (identified by plan id)的计划块,该选项仅仅可以和COSTS、VERBOSE、FORMAT三个选项共存。
取值范围:
TRUE:显示SCAN算子的代价淘汰明细。
FALSE(缺省值):不显示。实际查看执行计划时,这些参数根据实际需要进行增加,绝大部分场景下使用EXPLAIN ANALYZE statement就行。
4、执行计划显示格式
GaussDB对执行计划提供了normal、pretty、summary、run四种显示格式:
normal:代表使用默认的打印格式。
pretty:代表使用GaussDB改进后的新显示格式。新的格式层次清晰,计划包含了plan node id,性能分析简单直接。summary:在pretty的基础上增加了对打印信息的分析。
run:在summary的基础上,将统计的信息输出到csv格式的文件中,以便于进一步分析。
pretty格式执行计划示例:
通过设置GUC参数explain_perf_mode,可以显示不同格式的执行计划。pretty格式是我们通常使用的。
5、查看执行计划
除了设置不同的执行计划显示格式外,还可以通过不同的EXPLAIN用法,显示不同详细程度的执行计划信息,常见有如下几种。
EXPLAIN statement:只生成执行计划,不实际执行。其中statement代表sql语句。
EXPLAIN ANALYZE statement:生成执行计划,进行执行,并显示执行的概要信息。显示中加入了实际的运行时间统计,包括在每个规划节点内部花费的总时间(以毫秒计)和它实际返回的行数。
EXPLAIN PERFORMANCE statement:生成执行计划,进行执行,并显示执行期间的全部信息。
6、执行信息
在sql调优过程中经常需要执行EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看sql语句实际执行信息,通过对比实际执行与优化器估算之间的差别来为优化提供依据。EXPLAIN PERFORMANCE相对于EXPLAIN ANALYZE增加了每个DN上的执行信息。
以如下sql语句为例:
css
select count(1)from t1;
执行EXPLAIN PERFORMANCE输出为:
上述示例中显示执行信息分为以下7个部分:
计划显示
以表格的形式将计划显示出来,包含有11个字段,分别是:id、operation、A-time、A-rows、E-rows、E-distinct、Peak Memory、E-memory、A-width、E-width和E-costs。其中计划类字段(id、operation以及E开头字段)的含义与执行EXPLAIN时的含义一致。A-time、A-rows、E-distinct、Peak Memory、A-width的含义说明如下:
A-time:表示当前算子执行完成时间,一般DN上执行的算子的A-time是由[]括起来的两个值,分别表示此算子在所有DN上完成的最短时间和最长时间。
A-rows:表示当前算子的实际输出元组数。
E-distinct:表示hashjoin算子的distinct估计值。
Peak Memory:此算子在每个DN上执行时使用的内存峰值。
A-width:表示当前算子每行元组的实际宽度,仅对于重内存使用算子会显示,包括:(Vec)HashJoin、(Vec)HashAgg、(Vec) HashSetOp、(Vec)Sort、(Vec)Materialize算子等,其中(Vec)HashJoin计算的宽度是其右子树算子的宽度,会显示在其右子树上。
Predicate Information (identified by plan id):
这一部分主要显示的是静态信息,即在整个计划执行过程中不会变的信息,主要是一些join条件和一些filter信息。
Memory Information (identified by plan id):
这一部分显示的是整个计划中会将内存的使用情况打印出来的算子的内存使用信息,主要是Hash、Sort算子,包括算子峰值内存(peak memory),控制内存(control memory),估算内存使用(operator memory),执行时实际宽度(width),内存使用自动扩展次数(auto spread num),是否提前下盘(early spilled),以及下盘信息,包括重复下盘次数(spill Time(s)),内外表下盘分区数(inner/outer partition spill num),下盘文件数(temp file num),下盘数据量及最小和最大分区的下盘数据量(written disk IO [min, max] )。
Targetlist Information (identified by plan id):
这一部分显示的是每一个算子输出的目标列。
DataNode Information (identified by plan id):
这一部分会将各个算子的执行时间、CPU、buffer的使用情况全部打印出来。
User Define Profiling:
这一部分显示的是CN和DN、DN和DN建连的时间,以及存储层的一些执行信息。
====== Query Summary =====:
这一部分主要打印总的执行时间和网络流量,包括了各个DN上初始化和结束阶段的最大最小执行时间、CN上的初始化、执行、结束阶段的时间,以及当前语句执行时系统可用内存、语句估算内存等信息。
说明:
rows和E-rows的差异体现了优化器估算和实际执行的偏差度。一般来说,偏差越大,优化器生成的计划越不可信,人工干预调优的必要性越大。
time中的两个值偏差越大,表明此算子的计算偏斜(在不同DN上执行时间差异)越大,人工干预调优的必要性越大。
Max Query Peak Memory经常用来估算sql语句耗费内存,也被用来作为sql语句调优时运行态内存参数设置的重要依据。一般会以EXPLAIN ANALYZE或EXPLAIN PERFORMANCE的输出作为进一步调优的输入。