为了更好地支持Hologres用户丰富的使用场景,Hologres提供一些GUC参数。本文将介绍Hologres中GUC参数的含义以及如何使用。
使用限制
GUC参数对系统表不生效。
GUC参数一览表
GUC名称 | 适用场景 | 说明 | 使用示例 |
hg_enable_start_auto_analyze_worker | 开启Auto Analyze,以及Auto Analyze相关配置,详情请参见ANALYZE和AUTO ANALYZE。 | HologresV1.1及以上版本默认开启,值为 | set hg_enable_start_auto_analyze_worker = on; |
hg_auto_check_table_changes_interval | 默认值为 | set hg_auto_check_table_changes_interval = '10min'; | |
hg_auto_check_foreign_table_changes_interval | 默认值为 | set hg_auto_check_foreign_table_changes_interval = '4h'; | |
hg_auto_analyze_max_sample_row_count | 默认值为 | set hg_auto_analyze_max_sample_row_count = 16777216; | |
hg_fixed_api_modify_max_delay_interval | 默认值为 | set hg_fixed_api_modify_max_delay_interval = '3day'; | |
hg_foreign_table_max_partition_limit | 查MaxCompute外部表分区限制。如需调整限制可通过该GUC参数进行设置。 |
| set hg_foreign_table_max_partition_limit = 128; |
hg_experimental_query_batch_size | MaxCompute性能调优参数,详情请参见优化MaxCompute外部表的查询性能。 | 默认值为 | set hg_experimental_query_batch_size = 4096; |
hg_foreign_table_split_size | 默认值为 | set hg_foreign_table_split_size = 128; | |
hg_foreign_table_executor_max_dop | 默认值调整为与实例Core数相同,最大为 | set hg_foreign_table_executor_max_dop = 32; | |
hg_foreign_table_executor_dml_max_dop | 默认值为 | set hg_foreign_table_executor_dml_max_dop = 16; | |
hg_enable_access_odps_orc_via_holo | HologresV1.1及以上版本默认开启,值为 | set hg_enable_access_odps_orc_via_holo = on; | |
hg_experimental_enable_result_cache | 查询结果缓存。 | 默认值为 | set hg_experimental_enable_result_cache = on; |
optimizer_join_order | 内部性能调优参数,详情请参见优化查询性能。 | 默认值为 | set optimizer_join_order = query; |
optimizer_force_multistage_agg | 默认值为 | set optimizer_force_multistage_agg = on; | |
hg_anon_enable | 数据脱敏函数,详情请参见数据脱敏。 | 默认值为 | alter database <DB_NAME> set hg_anon_enable = on; |
hg_experimental_encryption_options | 数据加密规格设置,详情请参见数据存储加密。 | 默认值为 | alter database <DB_NAME> set hg_experimental_encryption_options='AES256,623c26ee-xxxx-xxxx-xxxx-91d323cc4855,AliyunHologresEncryptionDefaultRole,187xxxxxxxxxxxxx'; |
statement_timeout | 活跃query超时时间,详情请参见管理Query。 | 默认值为 | set statement_timeout = 5000 ; |
idle_in_transaction_session_timeout | 空闲事务的超时时间,详情请参见管理Query。 | 默认值为 | alter database db_name set idle_in_transaction_session_timeout=300000; |
idle_session_timeout | 自动释放空闲连接超时时间,详情请参见连接数管理。 | 默认值为 | alter database <DB_NAME> SET idle_session_timeout = 600000; |
hg_experimental_functions_use_pg_implementation | 时间范围扩展。 | HologresV1.1.31版本开始支持,设置后支持时间范围为 | set hg_experimental_functions_use_pg_implementation = 'to_char'; |
hg_experimental_approx_count_distinct_precision | 调整APPROX_COUNT_DISTINCT误差率,详情请参见APPROX_COUNT_DISTINCT。 | 默认值为 | set hg_experimental_approx_count_distinct_precision = 20; |
timezone | 时区设置。 | 默认值为 | set timezone='GMT-8:00'; |
hg_experimental_enable_create_table_like_properties | 复制表时同时复制表属性(主键、索引等),详情请参见CREATE TABLE LIKE。 | 默认值为 | set hg_experimental_enable_create_table_like_properties=true; |
hg_experimental_affect_row_multiple_times_keep_first | 使用 | 默认值为 | set hg_experimental_affect_row_multiple_times_keep_first = on; |
hg_experimental_affect_row_multiple_times_keep_last | set hg_experimental_affect_row_multiple_times_keep_last = on; | ||
hg_experimental_enable_read_replica | 单实例多副本高可用以及相关配置,详情请参见单实例Shard级多副本。 | 默认值为 | set hg_experimental_enable_read_replica = on; |
hg_experimental_display_query_id | 通过NOTICE消息在客户端打印Query ID,用于在 | 默认值为 | set hg_experimental_display_query_id = on; |
查看当前GUC参数的状态或默认值
通过show命令语句可以查看某个GUC参数的状态或者默认值,使用示例如下。
查看是否开启Auto Analyze。
show hg_enable_start_auto_analyze_worker;查看读取MaxCompute分区限制大小。
show hg_foreign_table_max_partition_limit;查看是否开启Query ID回显。
show hg_experimental_display_query_id;
设置GUC参数
GUC在使用时,可以设置为session级别或者数据库级别生效。
具体是session级别还是数据库级别,需要根据业务场景以及参数的详情合理评估,不建议所有的参数都设置为数据库级别。
session级别
通过
set命令可以在session级别设置GUC参数。session级别的参数只在当前session生效,当连接断开之后,将会失效,建议加在SQL前一起执行。语法示例如下。
set <GUC_NAME> = <VALUE>;GUC_NAME为GUC参数的名称,VALUE为GUC参数的值。
使用示例如下。
-- 开启Auto Analyze set hg_enable_start_auto_analyze_worker = on; -- 读取MaxCompute的分区限制变为1024 set hg_foreign_table_max_partition_limit =1024; -- 开启Query ID回显 set hg_experimental_display_query_id = on;
数据库级别
可以通过
alter database xx set xxx命令来设置DB级别的GUC参数,执行完成后在整个DB级别生效,设置完成后当前连接需要重新断开连接才能生效。新建DB不会生效,需要重新手动设置。语法示例如下。
alter database <DB_NAME> set <GUC_NAME> = <VALUE>;DB_NAME为数据库名称,GUC_NAME为GUC参数的名称,VALUE为GUC参数的值。
使用示例如下。
-- DB级别开启Auto Analyze alter database testdb set hg_enable_start_auto_analyze_worker = on; -- DB级别读取MaxCompute的分区限制变为1024 alter database testdb set hg_foreign_table_max_partition_limit =1024;
获取Query ID
Query ID是Hologres中每条Query的唯一标识,也是慢Query日志hologres.hg_query_log的主键之一。获取某条SQL对应的Query ID后,即可精确反查该Query的耗时、状态、读取行数等执行详情,是问题排查的关键入口。
Query ID默认不返回给客户端。开启hg_experimental_display_query_id后,服务端会在执行SQL时通过NOTICE消息将Query ID回显给客户端。
参数说明
项目 | 说明 |
参数名称 |
|
作用 | 执行SQL时通过NOTICE消息在客户端打印Query ID。 |
默认值 |
|
取值 |
|
生效粒度 | session级别或数据库级别。 |
返回形式 | NOTICE消息,格式为 |
使用该参数时,请注意以下两项机制:
Query ID通过NOTICE消息返回,而非结果集中的一列。在程序化客户端中,仅读取查询结果(如
fetchall())无法获取Query ID,必须通过客户端驱动提供的NOTICE获取机制读取。该参数按session生效,连接断开后失效,每建立一个新连接都需要重新设置一次。使用连接池时需特别注意,应将set语句配置到连接初始化环节,详情请参见连接池场景。
开启Query ID回显
-- session级别开启,建议与业务SQL一起执行
set hg_experimental_display_query_id = on;
-- 查看当前状态
show hg_experimental_display_query_id;
-- 数据库级别开启,对该数据库的新建连接生效,已有连接需重新建立
alter database <DB_NAME> set hg_experimental_display_query_id = on;在客户端中获取Query ID
Java(JDBC)
在JDBC中,NOTICE以SQLWarning链的形式返回,需要在SQL执行后通过statement.getWarnings()遍历获取并解析出Query ID,结果集ResultSet中不包含Query ID。完整示例如下。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HologresQueryIdDemo {
// 匹配NOTICE中的 "QueryID: <QUERY_ID>"
private static final Pattern QUERY_ID_PATTERN = Pattern.compile(
"query[_ ]?id\\s*(?:is\\b|[=:])?\\s*([0-9a-zA-Z_\\-]{6,})", Pattern.CASE_INSENSITIVE);
public static void main(String[] args) throws Exception {
// Endpoint请选择与运行环境匹配的网络地址(公网或VPC),在控制台的实例详情页获取
String url = "jdbc:postgresql://<ENDPOINT>:80/<DB_NAME>";
String user = "<ACCESS_KEY_ID>";
String password = "<ACCESS_KEY_SECRET>";
try (Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement()) {
// 开启Query ID回显,该参数默认为off且仅在当前session生效
stmt.execute("set hg_experimental_display_query_id = on;");
String sql = "select count(*), sum(id) from holo_query_id_demo;";
// 执行前清空上一条SQL残留的Warning,确保Query ID与SQL一一对应
stmt.clearWarnings();
boolean hasResultSet = stmt.execute(sql);
// 读取结果集,Query ID不在结果集中
if (hasResultSet) {
try (ResultSet rs = stmt.getResultSet()) {
while (rs.next()) {
System.out.println("rows : (" + rs.getLong(1) + ", " + rs.getLong(2) + ")");
}
}
}
// NOTICE以SQLWarning链的形式返回,遍历并解析出Query ID
String queryId = null;
List<String> notices = new ArrayList<>();
for (SQLWarning w = stmt.getWarnings(); w != null; w = w.getNextWarning()) {
notices.add(w.getMessage());
Matcher m = QUERY_ID_PATTERN.matcher(w.getMessage());
if (m.find()) {
queryId = m.group(1);
}
}
System.out.println("query_id : " + queryId);
System.out.println("notices : " + notices);
}
}
}返回结果示例如下。
rows : (1000, 500500)
query_id : 1002002606817139331
notices : [One or more columns in the following table(s) do not have statistics: holo_query_id_demo, QueryID: 1002002606817139331]使用时请注意以下三点:
PreparedStatement的用法相同,执行后调用pstmt.getWarnings()遍历即可。每次执行新的SQL前先调用
clearWarnings(),否则Warning会在同一Statement对象上累积,导致Query ID与SQL无法一一对应。NOTICE中可能混有其他消息(例如统计信息缺失的提示),解析时应按
QueryID:前缀匹配。
Python(Psycopg 3)
Hologres兼容PostgreSQL 11,推荐使用Psycopg 3驱动(通过pip install "psycopg[binary]"安装)。NOTICE需通过conn.add_notice_handler()注册回调获取,cur.fetchall()的返回结果中不包含Query ID。完整示例如下。
import re
import psycopg
NOTICES = []
QUERY_IDS = []
QUERY_ID_PATTERN = re.compile(
r"query[_ ]?id\s*(?:is\b|[=:])?\s*([0-9a-zA-Z_\-]{6,})", re.IGNORECASE
)
def notice_handler(diag):
"""服务端每发送一条NOTICE都会回调一次,从中解析Query ID。"""
text = diag.message_primary or ""
NOTICES.append(text)
match = QUERY_ID_PATTERN.search(text)
if match:
QUERY_IDS.append(match.group(1))
conn = psycopg.connect(
host="<ENDPOINT>", # 在控制台的实例详情页获取
port=80,
dbname="<DB_NAME>",
user="<ACCESS_KEY_ID>",
password="<ACCESS_KEY_SECRET>",
)
conn.autocommit = True
conn.add_notice_handler(notice_handler) # 注册NOTICE回调
cur = conn.cursor()
# 开启Query ID回显,该参数默认为off且仅在当前session生效
cur.execute("set hg_experimental_display_query_id = on;")
def run_sql(sql, params=None, fetch=True):
"""执行SQL并返回 (结果集, Query ID, 原始NOTICE列表)。无结果集时结果集为None。"""
NOTICES.clear()
QUERY_IDS.clear()
cur.execute(sql, params)
rows = None
if fetch and cur.description is not None:
rows = cur.fetchall()
query_id = QUERY_IDS[-1] if QUERY_IDS else None
return rows, query_id, list(NOTICES)
rows, query_id, notices = run_sql("select count(*) from holo_query_id_demo;")
print("rows:", rows)
print("query_id:", query_id)返回结果示例如下,DML与DQL均可获取Query ID。
SQL : insert into holo_query_id_demo select i, 'v' || i from generate_series(1, 1000) i;
query_id : 1002002606817130830
notices : ['QueryID: 1002002606817130830']
SQL : select count(*), sum(id) from holo_query_id_demo;
query_id : 1002002606817139331
rows : [(1000, 500500)]
notices : ['One or more columns in the following table(s) do not have statistics: holo_query_id_demo', 'QueryID: 1002002606817139331']连接池场景
该参数按session生效,每条物理连接都需要设置一次。使用连接池时,应将set语句配置到连接建立(初始化)环节,而不是在每次查询前手动执行。
Python以psycopg_pool为例,示例如下。
# 需先执行 pip install psycopg_pool
from psycopg_pool import ConnectionPool
def configure(conn):
conn.autocommit = True
conn.add_notice_handler(notice_handler)
conn.execute("set hg_experimental_display_query_id = on;")
pool = ConnectionPool(kwargs=CONN_INFO, configure=configure, min_size=1, max_size=4)
with pool.connection() as conn:
conn.execute("select 1;").fetchall()Java通过连接池的初始化SQL配置,保证每条物理连接建立时都已开启该参数。以HikariCP和Druid为例,示例如下。
// HikariCP:connectionInitSql在每条物理连接建立时执行
HikariConfig config = new HikariConfig();
config.setJdbcUrl(url);
config.setUsername(user);
config.setPassword(password);
config.setConnectionInitSql("set hg_experimental_display_query_id = on;");
HikariDataSource dataSource = new HikariDataSource(config);
// Druid:connectionInitSqls支持配置多条初始化SQL
DruidDataSource druid = new DruidDataSource();
druid.setUrl(url);
druid.setUsername(user);
druid.setPassword(password);
druid.setConnectionInitSqls(Collections.singletonList("set hg_experimental_display_query_id = on;"));从连接池获取连接后,仍需在每次执行SQL后通过statement.getWarnings()获取Query ID,获取方式请参见Java(JDBC)。
通过Query ID反查执行详情
获取Query ID后,可在慢Query日志中按query_id精确定位该Query的耗时、状态、读取行数等信息。
select query_id, status, duration, query_start, application_name, command_tag
from hologres.hg_query_log
where query_id = '<QUERY_ID>';hologres.hg_query_log存在约1分钟的写入延迟,Query刚执行完可能查询不到,请稍后重试。
注意事项
该参数按session生效,连接断开后失效。每建立一个新连接都必须重新执行
set hg_experimental_display_query_id = on;,否则该连接上的Query不会回显Query ID。并非所有语句都会返回Query ID。DDL语句(如
CREATE TABLE、DROP TABLE)以及不涉及计算引擎的简单查询(如select 1;)不返回Query ID,属于预期行为;DML语句(如INSERT)与常规查询(如SELECT)可正常返回。NOTICE中可能同时包含其他提示消息(例如统计信息缺失的警告),程序解析时应按
QueryID:前缀精确匹配,避免误取。
无法获取Query ID时如何排查
请按以下顺序确认。
执行
show hg_experimental_display_query_id;确认参数是否为on。若为off,说明当前连接未执行过set(使用连接池时可能已切换到其他连接),请重新设置或检查连接初始化逻辑。检查NOTICE缓冲区是否为空。若为空,说明服务端未发送NOTICE,请确认实例版本是否支持该参数,或确认该语句类型是否会产生Query ID。
若NOTICE有内容但未解析出Query ID,说明消息措辞与解析规则不匹配,请打印NOTICE原始文本,并按实例实际返回的格式调整解析逻辑。
使用连接池时,请确认set语句已配置到连接初始化环节,保证每条物理连接都已执行。