云服务器内容精选

  • 算子级调优介绍 一个查询语句要经过多个算子步骤才会输出最终的结果。由于个别算子耗时过长导致整体查询性能下降的情况比较常见。这些算子是整个查询的瓶颈算子。通用的优化手段是EXPLAIN ANALYZE/PERFORMANCE命令查看执行过程的瓶颈算子,然后进行针对性优化。 如下面的执行过程信息中,Hashagg算子的执行时间占总时间的:(51016-13535)/ 56476 ≈66%,此处Hashagg算子就是这个查询的瓶颈算子,在进行性能优化时应当优先考虑此算子的优化。
  • 操作步骤 收集SQL中涉及到的所有表的统计信息。在数据库中,统计信息是优化器生成计划的源数据。没有收集统计信息或者统计信息陈旧往往会造成执行计划严重劣化,从而导致性能问题。从经验数据来看,10%左右性能问题是因为没有收集统计信息。具体请参见更新统计信息。 通过查看执行计划来查找原因。如果SQL长时间运行未结束,通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出结果,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及实际运行情况,以便更精确地定位问题原因。有关执行计划的详细介绍请参见SQL执行计划介绍。 审视和修改表定义。 针对EXPLAIN或EXPLAIN PERFORMANCE信息,定位SQL慢的具体原因以及改进措施,具体请参见典型SQL调优点。 通常情况下,有些SQL语句可以通过查询重写转换成等价的,或特定场景下等价的语句。重写后的语句比原语句更简单,且可以简化某些执行步骤达到提升性能的目的。查询重写方法在各个数据库中基本是通用的。经验总结:SQL语句改写规则介绍了几种常用的通过改写SQL进行调优的方法。
  • 长查询和长事务调优 长查询或长事务将影响autovacuum对旧版本的清理,数据更新操作产生的旧版本将不能被及时清理。 数据访问时,需要遍历旧版本进行可见性判断,以便确定对当前查询快照可见的版本。长查询或长事务持续的时间越久,不能及时清理的旧版本就越多,对访问性能的影响也越大。极端场景下,例如考察基于较小数据量的索引点查吞吐的场景,旧版本增多将导致吞吐下降明显,性能受损可能在50%以上。 另外,不能及时清理旧版本,也会导致额外的存储空间占用,出现表膨胀、索引膨胀现象,数据访问时,额外的IO增加,也将会对性能产生一定影响。 Astore索引和表数据都采用非原地更新,更新索引键或非索引键,将产生索引旧版本和数据旧版本。Ustore索引采用非原地更新、数据采用原地更新,更新索引键将产生索引旧版本和数据旧版本,更新非索引键只产生数据旧版本。 长查询和长事务会Astore和Ustore的访问性能都会产生影响。 用户在业务实现上,应尽量避免长查询或长事务,可通过访问pg_stat_activity、pg_running_xacts观察系统中是否存在长查询或长事务,然后利用pg_cancel_backend(pid int)、pg_terminate_backend(pid int)函数取消掉长查询或长事务。 父主题: 典型SQL调优点
  • 更多优化示例 示例1:修改基表为replication表,并且在过滤列上创建索引。 1 2 3 create table master_table (a int); create table sub_table(a int, b int); select a from master_table group by a having a in (select a from sub_table); 上述事例中存在一个相关性子查询,为了提升查询的性能,建表时,可以将sub_table修改为一个replication表,并且在字段a上创建一个index。
  • 规格约束 告警字符串长度上限为2048。如果告警信息超过这个长度(例如存在大量未收集统计信息的超长表名、列名等信息)则不告警,只上报warning: WARNING, "Planner issue report is truncated, the rest of planner issues will be skipped" 如果query存在limit节点(即查询语句中包含limit),则不会上报limit节点以下的Operator级别的告警。 对于“数据倾斜”和“估算不准”两种类型告警,在某一个plan树结构下,只上报下层节点的告警,上层节点不再重复告警。主要是因为这两种类型的告警可能是因为底层触发上层的。例如,如果在scan节点已经存在数据倾斜,那么在上层的hashagg等其他算子很可能也出现数据倾斜。
  • 告警场景 目前支持对以下7种导致性能问题的场景上报告警。 多列/单列统计信息未收集 如果存在单列或者多列统计信息未收集,则上报相关告警。 告警信息示例: 整表的统计信息未收集: Statistic Not Collect: schema_test.t1 单列统计信息未收集: Statistic Not Collect: schema_test.t2(c1,c2) 多列统计信息未收集: Statistic Not Collect: schema_test.t3((c1,c2)) 单列和多列统计信息未收集: Statistic Not Collect: schema_test.t4(c1,c2) schema_test.t4((c1,c2)) SQL不下推 对于不下推的SQL,尽可能详细上报导致不下推的原因。调优方法请参见语句下推调优。 对于函数导致的不下推,告警导致不下推的函数名信息; 对于不支持下推的语法,会告警对应语法不支持下推,例如:含有With Recursive、Distinct On、row表达式和返回值为record类型的,会告警相应语法不支持下推等。 告警信息示例: SQL is not plan-shipping, reason : "With Recursive" can not be shipped" SQL is not plan-shipping, reason : "Function now() can not be shipped" SQL is not plan-shipping, reason : "Function string_agg() can not be shipped" HashJoin中大表做内表 如果在表连接过程中使用了Hashjoin,且连接的内表行数是外表行数的10倍或以上,同时内表在每个DN上的平均行数大于10万行,且发生了下盘,则上报相关告警。调优方法请参见使用plan hint调优执行计划。 告警信息示例: PlanNode[7] Large Table is INNER in HashJoin “Vector Hash Aggregate” 大表等值连接使用Nestloop 如果在表连接过程中使用了nestloop,并且两个表中较大表的行数平均每个DN上的行数大于10万行,表的连接中存在等值连接,则上报相关告警。调优方法请参见使用plan hint调优执行计划。 告警信息示例: PlanNode[5] Large Table with Equal-Condition use Nestloop"Nested Loop" 大表Broadcast 如果在Broadcast算子中,平均每DN的行数大于10万行,则告警大表broadcast。调优方法请参见使用plan hint调优执行计划。 告警信息示例: PlanNode[5] Large Table in Broadcast "Streaming(type: BROADCAST dop: 1/2)" 数据倾斜 某表在各DN上的分布,存在某DN上的行数是另一DN上行数的10倍或以上,且有DN中的行数大于10万行,则上报相关告警。 告警信息示例: PlanNode[6] DataSkew:"Seq Scan", min_dn_tuples:0, max_dn_tuples:524288 估算不准 如果优化器的估算行数和实际行数中的较大值平均每DN行数大于10万行,并且估算行数和实际行数中较大值是较小值的10倍或以上,则上报相关告警。调优方法请参见使用plan hint调优执行计划。 告警信息示例: PlanNode[5] Inaccurate Estimation-Rows: "Hash Join" A-Rows:0, E-Rows:52488
  • 相关链接 SQL PATCH相关系统函数、系统表、系统视图和接口函数见表1 SQL PATCH相关系统函数、系统表、系统视图和接口函数介绍。 表1 SQL PATCH相关系统函数、系统表、系统视图和接口函数介绍 类别 名称 说明 系统函数 global_sql_patch_func() 全局各个节点上的SQL PATCH信息,用于返回global_sql_patch视图的结果。 系统表 GS_SQL_PATCH GS_SQL_PATCH系统表存储所有SQL_PATCH的状态信息。 系统视图 GLOBAL_SQL_PATCH GLOBAL_SQL_PATCH视图存放所有SQL PATCH的信息,该视图仅在pg_catalog模式下存在。 接口函数 DBE_SQL_UTIL Schema DBE_SQL_UTIL.create_hint_sql_patch create_hint_sql_patch是用于在当前建连的CN上创建调优SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.create_abort_sql_patch create_abort_sql_patch是用于在当前建连的CN上创建避险SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.drop_sql_patch drop_sql_patch是用于在当前建连的CN上删除SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.enable_sql_patch enable_sql_patch是用于在当前建连的CN上开启SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.disable_sql_patch disable_sql_patch是用于在当前建连的CN上禁用SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.show_sql_patch show_sql_patch是用于显示给定patch_name对应SQL PATCH的接口函数,返回运行结果。 DBE_SQL_UTIL.create_hint_sql_patch create_hint_sql_patch是用于创建调优SQL PATCH的接口函数,返回执行是否成功。本函数是原函数的重载函数,支持通过parent_unique_sql_id值限制hint patch的生效范围。 DBE_SQL_UTIL.create_abort_sql_patch create_abort_sql_patch是用于创建避险SQL PATCH的接口函数,返回执行是否成功。本函数是原函数的重载函数,支持通过parent_unique_sql_id值限制abort patch的生效范围。 DBE_SQL_UTIL.create_remote_hint_sql_patch create_remote_hint_sql_patch是用于指定CN创建调优SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.create_remote_abort_sql_patch create_remote_abort_sql_patch是用于指定CN创建避险SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.drop_remote_sql_patch drop_remote_sql_patch是用于指定CN删除SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.enable_remote_sql_patch enable_remote_sql_patch是用于指定CN开启SQL PATCH的接口函数,返回执行是否成功。 DBE_SQL_UTIL.disable_remote_sql_patch disable_remote_sql_patch是用于指定CN禁用SQL PATCH的接口函数,返回执行是否成功。
  • 特性约束 仅支持针对Unique SQL ID添加补丁,如果存在Unique SQL ID冲突,用于hint调优的SQL PATCH可能影响性能,但不影响语义正确性。 仅支持不改变SQL语义的hint作为PATCH,不支持SQL改写。 不支持逻辑备份、恢复。 不支持在DN上创建SQL PATCH。 仅初始用户、运维管理员、监控管理员、系统管理员用户有权限执行。 库之间不共享,创建SQL PATCH时需要连接目标库。如果创建SQL PATCH的CN被剔除并触发全量Build,则会继承全量Build的目标CN中的SQL PATCH,因此建议在各个CN上尽量都创建对应的SQL PATCH。 CN之间由于Unique SQL ID不同,不共享SQL PATCH,需要用户手动在不同的CN上创建对应的SQL PATCH。 限制在存储过程内的SQL PATCH和全局的SQL PATCH不允许同时存在。 使用PREPARE + EXECUTE语法执行的预编译语句执行不支持使用SQL PATCH。存在特殊情况,请参见特殊说明。 SQL PATCH不建议在数据库中长期使用,只应该作为临时规避方法。遇到内核问题所导致的特定语句触发数据库服务不可用问题,以及使用hint进行调优的场景,需要尽快修改业务或升级内核版本解决问题。并且升级后由于Unique SQL ID生成方法可能变化,可能导致规避方法失效。 当前,除DML语句之外,其他SQL语句(如CREATE TABLE等)的Unique SQL ID是对语句文本直接哈希生成的,所以对于此类语句,SQL PATCH对大小写、空格、换行等敏感,即不同文本的语句,即使语义相同,仍然需要对应不同的SQL PATCH。对于DML,则同一个SQL PATCH可以对不同入参的语句生效,并且忽略大小写和空格。
  • 统计信息调优介绍 GaussDB 是基于代价估算生成的最优执行计划。优化器需要根据analyze收集的统计信息进行行数估算和代价估算,因此统计信息对优化器行数估算和代价估算起着至关重要的作用。通过analyze收集全局统计信息,主要包括:PG_CLASS系统表中的relpages和reltuples,pg_statistic表中的stadistinct、stanullfrac、stanumbersN、stavaluesN、histogram_bounds等。
  • 操作步骤 收集SQL中涉及到的所有表的统计信息。在数据库中,统计信息是优化器生成计划的源数据。没有收集统计信息或者统计信息陈旧往往会造成执行计划严重劣化,从而导致性能问题。从经验数据来看,10%左右性能问题是因为没有收集统计信息。具体请参见更新统计信息。 通过查看执行计划来查找原因。如果SQL长时间运行未结束,通过EXPLAIN命令查看执行计划,进行初步定位。如果SQL可以运行出结果,则推荐使用EXPLAIN ANALYZE或EXPLAIN PERFORMANCE查看执行计划及实际运行情况,以便更精确地定位问题原因。有关执行计划的详细介绍请参见SQL执行计划介绍。 审视和修改表定义。 针对EXPLAIN或EXPLAIN PERFORMANCE信息,定位SQL慢的具体原因以及改进措施,具体请参见典型SQL调优点。 通常情况下,有些SQL语句可以通过查询重写转换成等价的,或特定场景下等价的语句。重写后的语句比原语句更简单,且可以简化某些执行步骤达到提升性能的目的。查询重写方法在各个数据库中基本是通用的。经验总结:SQL语句改写规则介绍了几种常用的通过改写SQL进行调优的方法。 如果使用上述常规手段无法分析慢SQL根因的场景,还可以通过使用plan trace特性来分析慢SQL根因,具体请参见PLAN TRACE使用介绍。
  • 背景信息 ANALYZE语句可收集与数据库中表内容相关的统计信息,统计结果存储在系统表PG_STATISTIC中。查询优化器会使用这些统计数据,以生成最有效的执行计划。ANALYZE语句操作请参见ANALYZE | ANALYSE。 建议在执行了大批量插入/删除操作后,例行对表或全库执行ANALYZE语句更新统计信息。目前默认收集统计信息的采样比例是30000行(即:GUC参数default_statistics_target默认设置为100),如果表的总行数超过一定行数(大于1600000),建议设置GUC参数default_statistics_target为-2,即按2%收集样本估算统计信息。 对于在批处理脚本或者存储过程中生成的中间表,也需要在完成数据生成之后显式地调用ANALYZE。 对于表中多个列有相关性且查询中有同时基于这些列的条件或分组操作的情况,可尝试收集多列统计信息,以便查询优化器可以更准确地估算行数,并生成更有效的执行计划。 若表上存在全局二级索引,则需要对基表执行ANALYZE之后再对全局二级索引执行ANALYZE。
  • 调优手段之GUC参数 查询优化的主要目的是为查询语句选择高效的执行方式。 如下SQL语句: 1 2 select count(1) from customer inner join store_sales on (ss_customer_sk = c_customer_sk); 在执行customer inner join store_sales的时候,GaussDB支持Nested Loop、Merge Join和Hash Join三种不同的Join方式。优化器会根据表customer和表store_sales的统计信息估算结果集的大小以及每种Join方式的执行代价,然后对比选出执行代价最小的执行计划。 正如前面所说,执行代价计算都是基于一定的模型和统计信息进行估算,当因为某些原因代价估算不能反映真实的cost的时候,就需要通过GUC参数设置的方式让执行计划倾向更优规划。例如:random_page_cost参数表示优化器计算一次非顺序抓取磁盘页面的开销,该参数默认值为4。当机器磁盘随机读取的速度较快时,比如SSD设备,可以将该参数的值适当调小,更改后,索引扫描的代价降低,生成计划时更倾向于选择索引扫描的方式。
  • 调优手段之统计信息 GaussDB优化器是典型的基于代价的优化(Cost-Based Optimization,简称CBO)。在这种优化器模型下,数据库根据表的元组数、字段宽度、NULL记录比率、distinct值、MCV值、HB值等表的特征值,以及一定的代价计算模型,计算出每一个执行步骤的不同执行方式的输出元组数和执行代价(cost),进而选出整体执行代价最小/首元组返回代价最小的执行方式进行执行。这些特征值就是统计信息。从上面描述可以看出统计信息是查询优化的核心输入,准确的统计信息将帮助优化器选择最合适的查询规划,一般来说通过ANALYZE语法收集整个表或者表的若干个字段的统计信息,周期性地运行ANALYZE,或者在对表的大部分内容做了更改之后马上运行它是个好习惯。 注意,DDL可能会导致统计信息发生变化,进而导致计划跳变。当表上做了DDL操作后,应注意统计信息是否需要重新收集。
  • 调优手段之GUC参数 查询优化的主要目的是为查询语句选择高效的执行方式。 如下SQL语句: 1 2 select count(1) from customer inner join store_sales on (ss_customer_sk = c_customer_sk); 在执行customer inner join store_sales的时候,GaussDB支持Nested Loop、Merge Join和Hash Join三种不同的Join方式。优化器会根据表customer和表store_sales的统计信息估算结果集的大小以及每种Join方式的执行代价,然后对比选出执行代价最小的执行计划。 正如前面所说,执行代价计算都是基于一定的模型和统计信息进行估算,当因为某些原因代价估算不能反映真实的cost的时候,就需要通过GUC参数设置的方式让执行计划倾向更优规划。例如:random_page_cost参数表示优化器计算一次非顺序抓取磁盘页面的开销,该参数默认值为4。当机器磁盘随机读取的速度较快时,比如SSD设备,可以将该参数的值适当调小,更改后,索引扫描的代价降低,生成计划时更倾向于选择索引扫描的方式。
  • 调优手段之统计信息 GaussDB优化器是典型的基于代价的优化(Cost-Based Optimization,简称CBO)。在这种优化器模型下,数据库根据表的元组数、字段宽度、NULL记录比率、distinct值、MCV值、HB值等表的特征值,以及一定的代价计算模型,计算出每一个执行步骤的不同执行方式的输出元组数和执行代价(cost),进而选出整体执行代价最小/首元组返回代价最小的执行方式进行执行。这些特征值就是统计信息。从上面描述可以看出统计信息是查询优化的核心输入,准确的统计信息将帮助优化器选择最合适的查询规划,一般来说通过ANALYZE语法收集整个表或者表的若干个字段的统计信息,周期性地运行ANALYZE,或者在对表的大部分内容做了更改之后马上运行它是个好习惯。 注意,DDL可能会导致统计信息发生变化,进而导致计划跳变。当表上做了DDL操作后,应注意统计信息是否需要重新收集。