AutoAnalyze
- 概述
- [AutoAnaProcess 类](#AutoAnaProcess 类)
-
- [AutoAnaProcess 函数](#AutoAnaProcess 函数)
- [AutoAnaProcess::executeSQLCommand 函数](#AutoAnaProcess::executeSQLCommand 函数)
- [AutoAnaProcess::runAutoAnalyze 函数](#AutoAnaProcess::runAutoAnalyze 函数)
- [AutoAnaProcess::run 函数](#AutoAnaProcess::run 函数)
- [AutoAnaProcess::check_conditions 函数](#AutoAnaProcess::check_conditions 函数)
- [AutoAnaProcess::cancelAutoAnalyze 函数](#AutoAnaProcess::cancelAutoAnalyze 函数)
- [AutoAnaProcess::~AutoAnaProcess 函数](#AutoAnaProcess::~AutoAnaProcess 函数)
声明 :本文的部分内容参考了他人的文章。在编写过程中,我们尊重他人的知识产权和学术成果,力求遵循合理使用原则,并在适用的情况下注明引用来源。
本文主要参考了《PostgresSQL数据库内核分析》一书,OpenGauss1.1.0 的开源代码和《OpenGauss数据库源码解析》一书以及OpenGauss社区学习文档
概述
AutoAnalyze 是一种自动统计信息收集和优化功能 ,用于数据库管理系统 中。其主要目的是在数据库中定期收集表的统计信息,以便查询优化器能够生成更有效的执行计划。以下是有关 AutoAnalyze 的详细信息:
- 自动统计信息收集: AutoAnalyze 会自动定期检查数据库中的表 ,并确定哪些表需要更新统计信息 。这些统计信息 包括行数 、唯一值数量 、最小值 、最大值 等,这些信息对于查询优化非常重要。
- 查询优化: 收集的统计信息可帮助查询优化器 更好地估算查询成本 ,从而选择更优的执行计划 。这可以提高查询性能 ,减少查询的执行时间。
- 避免过度分析: AutoAnalyze 会智能地选择哪些表需要进行统计信息收集 ,以避免不必要的分析 。它通常会关注哪些表的数据发生了变化 ,以及哪些表的统计信息可能已经过时。
- 自动化: 一旦启用,AutoAnalyze 会自动在后台执行 ,无需手动干预。这使得数据库管理员的工作更加轻松,不需要手动分析每个表。
此外,我们先前学习过 ANALYZE, 该命令是一个手动命令 ,它允许数据库管理员明确指示系统去收集特定表的统计信息 。相比之下,AutoAnalyze 是自动执行的 ,系统会自动选择需要分析的表 ,并在后台进行统计信息收集 。
AutoAnalyze 通常用于处理大量表 ,以确保它们的统计信息保持最新 。而 ANALYZE 通常用于手动分析****那些特殊需要或数据分布变化较大的表 。本文,我们则来学习 AutoAnalyze 的相关源码实现。
AutoAnaProcess 类
AutoAnaProcess 类用于支持自动分析 (Auto-Analyze )功能,该功能用于执行表的自动统计信息收集和优化 。该类用于管理 和执行自动分析操作 ,它包含了与数据库连接 、SQL 查询命令的执行 以及资源管理相关的方法和属性 。
AutoAnaProcess 类函数源码如下:(路径:src/include/optimizer/autoanalyzer.h
)
c
/* Auto-Analyze */
// 自动分析进程类,用于处理自动分析操作
class AutoAnaProcess : public BaseObject {
public:
// 构造函数,接收一个关系对象作为参数
AutoAnaProcess(Relation rel);
// 析构函数
~AutoAnaProcess();
// 静态方法,用于执行自动分析操作,接收一个关系对象作为参数
static bool runAutoAnalyze(Relation rel);
// 静态方法,用于取消自动分析操作
static void cancelAutoAnalyze();
protected:
// PostgreSQL数据库连接对象
PGconn* m_pgconn;
// PostgreSQL查询结果对象
PGresult* m_res;
// 存储SQL查询命令的列表
List* m_query;
private:
// 静态方法,用于检查自动分析的条件,接收一个关系对象作为参数
static bool check_conditions(Relation rel);
// 执行自动分析操作的私有方法
bool run();
// 执行SQL查询命令的私有方法,接收一个SQL命令字符串作为参数
bool executeSQLCommand(char* cmd);
// 清理资源的静态方法
static void tear_down();
};
在这个类中,包含了类的构造函数 、析构函数 、runAutoAnalyze 静态方法 、cancelAutoAnalyze 静态方法 以及一些需要用到的属性 和方法。接下来我们分别来看一看该类中这些相关函数的实现吧。
AutoAnaProcess 函数
AutoAnaProcess 是AutoAnaProcess 类的构造函数 ,主要用于初始化自动分析处理对象的属性 和设置需要执行的自动分析相关的 SQL 命令。该函数的执行过程如下所示:
- AutoAnaProcess::AutoAnaProcess(Relation rel) : m_pgconn(NULL), m_res(NULL):
- 这是构造函数的定义 ,接受一个名为Relation rel 的参数,表示要执行自动分析的数据库表。
- m_pgconn 和 m_res 是 AutoAnaProcess 类的私有属性 ,用于管理与数据库连接和查询结果相关的信息。在构造函数中,它们都被初始化为 NULL。
- m_query = NIL;:
- m_query 是一个列表 ,用于存储将要执行的 SQL 查询命令。在构造函数中,它被初始化为空列表。
- StringInfoData str_lockwait_timeout;:
- str_lockwait_timeout 是一个 StringInfoData 结构,用于存储关于锁等待超时的配置信息。
- initStringInfo(&str_lockwait_timeout);:
- initStringInfo 是一个宏,用于初始化 str_lockwait_timeout ,使其可以存储字符串信息。
- appendStringInfo(&str_lockwait_timeout, "set lockwait_timeout=%d ;", AUTOANALYZE_LOCKWAIT_TIMEOUT);:
- appendStringInfo 用于将字符串 "set lockwait_timeout=某个值 ;" 添加到 str_lockwait_timeout 中,该值由常量 AUTOANALYZE_LOCKWAIT_TIMEOUT 决定。这个 SQL 命令用于设置锁等待超时时间。
- m_query = lappend(m_query, str_lockwait_timeout.data);:
- 这一行代码将 str_lockwait_timeout 中的 SQL 命令添加到 m_query 列表中。
- 类似的过程重复了两次,用于设置另外两个配置参数:
- str_allow_concurrent_tuple_update 用于设置是否允许并发元组更新。
- str_max_query_retry_times 用于设置最大查询重试次数。
- 最后,通过以下代码设置了执行自动分析的 SQL 命令:
cStringInfoData str_analyze_command; initStringInfo(&str_analyze_command); appendStringInfo(&str_analyze_command, "analyze %s.%s ;", quote_identifier(get_namespace_name(rel->rd_rel->relnamespace)), quote_identifier(NameStr(rel->rd_rel->relname))); m_query = lappend(m_query, str_analyze_command.data);
- 这部分代码构建了一个 analyze 命令,该命令用于执行自动分析操作。它包括了要分析的表的模式名和表名 ,通过调用 quote_identifier 函数来确保这些标识符的正确引用。
- 最后,这个 SQL 命令被添加到 m_query 列表中,以便后续执行。
函数源码如下所示:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
/* Constructor */
// 构造函数
AutoAnaProcess::AutoAnaProcess(Relation rel) : m_pgconn(NULL), m_res(NULL)
{
m_query = NIL; // 初始化查询命令列表为一个空列表
StringInfoData str_lockwait_timeout; // 创建一个用于存储锁等待超时配置的字符串信息结构
initStringInfo(&str_lockwait_timeout); // 初始化字符串信息结构
// 向字符串信息结构中追加锁等待超时的设置命令,AUTOANALYZE_LOCKWAIT_TIMEOUT是一个常量,表示锁等待超时的时间
appendStringInfo(&str_lockwait_timeout, "set lockwait_timeout=%d ;", AUTOANALYZE_LOCKWAIT_TIMEOUT);
m_query = lappend(m_query, str_lockwait_timeout.data); // 将设置命令添加到查询命令列表中
StringInfoData str_allow_concurrent_tuple_update; // 创建一个用于存储是否允许并发元组更新的字符串信息结构
initStringInfo(&str_allow_concurrent_tuple_update); // 初始化字符串信息结构
// 向字符串信息结构中追加允许并发元组更新的设置命令
appendStringInfo(&str_allow_concurrent_tuple_update, "set allow_concurrent_tuple_update='off';");
m_query = lappend(m_query, str_allow_concurrent_tuple_update.data); // 将设置命令添加到查询命令列表中
StringInfoData str_max_query_retry_times; // 创建一个用于存储最大查询重试次数的字符串信息结构
initStringInfo(&str_max_query_retry_times); // 初始化字符串信息结构
// 向字符串信息结构中追加最大查询重试次数的设置命令
appendStringInfo(&str_max_query_retry_times, "set max_query_retry_times=0;");
m_query = lappend(m_query, str_max_query_retry_times.data); // 将设置命令添加到查询命令列表中
StringInfoData str_analyze_command; // 创建一个用于存储执行自动分析的SQL命令的字符串信息结构
initStringInfo(&str_analyze_command); // 初始化字符串信息结构
// 构建执行自动分析的SQL命令,包括要分析的表的模式名和表名,通过quote_identifier函数确保标识符的正确引用
appendStringInfo(&str_analyze_command,
"analyze %s.%s ;",
quote_identifier(get_namespace_name(rel->rd_rel->relnamespace)),
quote_identifier(NameStr(rel->rd_rel->relname)));
m_query = lappend(m_query, str_analyze_command.data); // 将执行命令添加到查询命令列表中
}
AutoAnaProcess::executeSQLCommand 函数
executeSQLCommand 函数的主要作用是执行传入的 SQL 命令字符串,并返回执行结果的布尔值 。它还会记录执行成功或失败的信息 ,并在执行期间允许取消或终止请求的处理 。
函数首先保存当前线程的中断状态 ,以允许在等待期间处理取消或终止请求,然后执行 SQL 查询 ,检查执行结果的状态 ,如果成功则记录成功信息 ,如果失败则记录错误信息 ,并最后返回执行结果的布尔值 。这个函数通常用于执行数据库操作 ,如自动分析 (Auto-Analyze )等。
函数源码如下:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
bool AutoAnaProcess::executeSQLCommand(char* queryString)
{
// 初始化执行结果标志为false
bool result = false;
// 保存原始的ImmediateInterruptOK标志,用于在等待期间处理取消或终止请求
bool ImmediateInterruptOK_Old = t_thrd.int_cxt.ImmediateInterruptOK;
/* 允许在等待期间处理取消或终止请求 */
t_thrd.int_cxt.ImmediateInterruptOK = true;
// 检查是否有中断请求
CHECK_FOR_INTERRUPTS();
// 执行 SQL 查询并将结果存储在m_res中
m_res = PQexec(m_pgconn, queryString);
// 恢复原始的ImmediateInterruptOK标志
t_thrd.int_cxt.ImmediateInterruptOK = ImmediateInterruptOK_Old;
// 检查执行结果的状态
if (PQresultStatus(m_res) != PGRES_COMMAND_OK) {
// 如果执行失败,记录失败信息和错误信息
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze failed: %s, error: %s", queryString, PQerrorMessage(m_pgconn));
} else {
// 如果执行成功,设置执行结果标志为true,并记录成功信息
result = true;
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze success: %s", queryString);
}
// 清理执行结果对象
PQclear(m_res);
m_res = NULL;
// 返回执行结果的布尔值
return result;
}
以下是 ExecutorRun 函数的执行过程的解释:
- 首先,函数接收一个字符串参数 queryString ,该参数包含要执行的 SQL 命令。
- 函数开始时,初始化一个布尔型变量 result ,用于表示 SQL 命令的执行结果,默认值为 false。
- 接着,函数保存当前线程 的 ImmediateInterruptOK 标志的原始值 ,并将其设置为 true 。这允许在等待期间处理取消或终止请求。
- 然后,函数调用 CHECK_FOR_INTERRUPTS() 检查是否有中断请求,以确保可以响应取消请求。
- 接下来,函数使用 PQexec 函数执行传入的 queryString ,并将执行结果存储在成员变量 m_res 中 。这个结果可能是执行成功的命令返回的信息 ,或者执行失败的错误信息。
- 函数恢复原始的 ImmediateInterruptOK 标志值,以确保不再处理取消或终止请求。
- 接着,函数检查执行结果的状态。如果执行失败,函数记录失败信息和错误信息到日志中。
- 如果执行成功 ,函数将 result 设置为 true ,表示执行成功 ,并记录成功信息到日志中。
- 最后,函数清理执行结果对象 m_res ,将其置为 NULL。
- 最终,函数返回 result ,表示 SQL 命令的执行结果 ,如果执行成功 ,则为 true ;如果执行失败 ,则为 false。
AutoAnaProcess::runAutoAnalyze 函数
runAutoAnalyze 函数的主要作用是触发自动分析(Auto-Analyze)过程,用于更新数据库中表的统计信息以优化查询性能 。它检查是否满足自动分析的条件 ,获取可用的自动分析进程 ,执行自动分析 ,并记录自动分析的执行时间。函数的功能包括条件检查 、进程管理 、自动分析的执行 ,以及记录自动分析时间信息 。
runAutoAnalyze 函数非常重要 ,因为它实现了数据库自动分析(Auto-Analyze)的关键逻辑 。自动分析是数据库优化的一部分,它负责监测表的数据变化并定期进行统计信息的收集,以便查询优化器可以更好地选择执行计划。通过这个函数,数据库能够自动化地维护和更新这些统计信息 ,从而保持查询性能的稳定性和高效性。因此,该函数的正确执行对于数据库的性能和稳定性至关重要。
runAutoAnalyze 函数源码如下所示:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
bool AutoAnaProcess::runAutoAnalyze(Relation rel)
{
// 获取自动分析进程是否可用的标志
bool getProcess = false;
// 记录自动分析的执行结果
bool result = false;
// 记录自动分析开始的时间
TimestampTz start_time = 0;
// 如果需要在 EXPLAIN ANALYZE 中显示自动分析的执行时间
if (u_sess->analyze_cxt.autoanalyze_timeinfo) {
// 获取当前时间作为自动分析的开始时间
start_time = GetCurrentTimestamp();
}
// 第一步:检查是否满足自动分析的条件
if (!check_conditions(rel)) {
// 如果不满足条件,记录日志并返回执行结果为失败
elog(DEBUG2, "[AUTO-ANALYZE] 检查自动分析条件失败: 表 \"%s\"", NameStr(rel->rd_rel->relname));
return result;
}
// 第二步:获取可用的自动分析进程
(void)LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
if (autoAnalyzeFreeProcess > 0) {
// 如果存在可用进程,设置标志为可获取进程并减少可用进程数
getProcess = true;
autoAnalyzeFreeProcess--;
}
(void)LWLockRelease(AutoanalyzeLock);
// 如果没有可用进程,记录日志并返回执行结果为失败
if (!getProcess) {
elog(DEBUG2, "[AUTO-ANALYZE] 没有可用的自动分析进程");
return result;
}
// 第三步:执行自动分析
Assert(u_sess->analyze_cxt.autoanalyze_process == NULL);
// 创建自动分析进程
u_sess->analyze_cxt.autoanalyze_process = New(CurrentMemoryContext) AutoAnaProcess(rel);
// 执行自动分析,并记录执行结果
result = u_sess->analyze_cxt.autoanalyze_process->run();
// 清理自动分析进程资源
tear_down();
// 第四步:释放可用自动分析进程
LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
autoAnalyzeFreeProcess++;
LWLockRelease(AutoanalyzeLock);
// 第五步:如果需要,在 EXPLAIN ANALYZE 中记录自动分析的执行时间
if (u_sess->analyze_cxt.autoanalyze_timeinfo && result) {
// 计算自动分析的执行时间
long secs;
long msecs;
int usecs;
TimestampDifference(start_time, GetCurrentTimestamp(), &secs, &usecs);
msecs = usecs / 1000L;
msecs = secs * 1000 + msecs;
usecs = usecs % 1000;
// 将自动分析的执行时间信息添加到相应的字符串中
MemoryContext oldcontext = MemoryContextSwitchTo(u_sess->temp_mem_cxt);
appendStringInfo(u_sess->analyze_cxt.autoanalyze_timeinfo,
"\"%s.%s\" %ld.%03dms ",
get_namespace_name(rel->rd_rel->relnamespace),
NameStr(rel->rd_rel->relname),
msecs,
usecs);
(void)MemoryContextSwitchTo(oldcontext);
}
// 返回自动分析的执行结果
return result;
}
以下是函数的执行过程简述:
- 首先,函数接收一个参数 rel ,表示一个关系(表)。
- 函数初始化了一些局部变量 ,包括 getProcess (用于表示是否获取到了可用的 Auto-Analyze 进程)、result (用于表示 Auto-Analyze 的执行结果是否成功)、start_time (用于记录 Auto-Analyze 开始时间)。
- 如果当前会话的上下文 (
u_sess->analyze_cxt.autoanalyze_timeinfo
)允许记录自动分析时间信息 ,函数记录 Auto-Analyze 的开始时间。- 接着,函数调用 check_conditions(rel) 检查是否满足执行自动分析的条件,如果不满足条件,则函数返回执行结果 result 为 false。
- 如果条件满足 ,函数尝试获取一个可用的 Auto-Analyze 进程 。它首先获取了自动分析锁(AutoanalyzeLock),并检查是否还有可用的 Auto-Analyze 进程 。如果有可用的进程,则将 getProcess 设为 true ,并减少可用进程的数量。
- 如果没有可用的 Auto-Analyze 进程,函数返回执行结果 result 为 false ,并记录日志,表示没有可用的进程。
- 如果成功获取到 Auto-Analyze 进程,函数进入执行 Auto-Analyze 的步骤 。首先,它确保当前会话的 autoanalyze_process 为空,然后创建一个新的 AutoAnaProcess 实例 ,传入 rel ,并执行 Auto-Analyze。
- 执行完 Auto-Analyze 后,函数执行 tear_down() ,清理资源。
- 最后,函数释放 AutoanalyzeLock,增加可用 Auto-Analyze 进程的数量 ,并在成功执行 Auto-Analyze 且允许记录自动分析时间信息 的情况下,记录 Auto-Analyze 的耗时信息 到
u_sess->analyze_cxt.autoanalyze_timeinfo
。- 函数返回执行结果 result,表示 Auto-Analyze 的执行结果 ,如果执行成功 ,则为 true ;如果执行失败 或没有可用进程 ,则为 false。
AutoAnaProcess::run 函数
AutoAnaProcess::run 函数的作用是执行自动分析操作,其功能包括建立数据库连接 、执行一系列自动分析 操作的查询命令 、记录执行结果 ,并最终返回操作是否成功的结果 。其函数源码如下:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
bool AutoAnaProcess::run()
{
char conninfo[CHAR_BUF_SIZE]; // 存储数据库连接信息的字符数组
int ret; // 保存函数返回值
bool result = false; // 用于表示自动分析是否成功
ListCell* lc = NULL; // 用于遍历查询命令列表
// 遍历自动分析操作的查询命令列表
foreach (lc, m_query) {
char* cmd = (char*)lfirst(lc); // 获取当前查询命令字符串
// 记录自动分析操作的开始
elog(DEBUG2, "[AUTO-ANALYZE] autoanalyze start: %s", cmd);
}
// 构建数据库连接信息字符串
ret = snprintf_s(conninfo,
sizeof(conninfo),
sizeof(conninfo) - 1,
"dbname=%s port=%d application_name='auto_analyze' enable_ce=1 ",
get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true), // 获取当前数据库名
g_instance.attr.attr_network.PostPortNumber); // 获取数据库端口号
securec_check_ss_c(ret, "\0", "\0"); // 安全检查
// 连接数据库
m_pgconn = PQconnectdb(conninfo);
// 检查数据库连接是否成功
if (PQstatus(m_pgconn) == CONNECTION_OK) {
foreach (lc, m_query) {
char* cmd = (char*)lfirst(lc); // 获取当前查询命令字符串
// 执行自动分析操作的查询命令
result = executeSQLCommand(cmd);
if (!result) {
break;
}
}
} else {
// 记录连接数据库失败的信息
elog(DEBUG2, "[AUTO-ANALYZE] connection to database failed: %s", PQerrorMessage(m_pgconn));
}
// 清理资源
PQclear(m_res); // 清理查询结果
PQfinish(m_pgconn); // 关闭数据库连接
m_res = NULL;
m_pgconn = NULL;
return result; // 返回自动分析操作是否成功的结果
}
这个函数的作用是执行自动分析操作,其执行过程如下:
- 函数开始时,遍历 存储在 m_query 列表中的查询命令 ,将每个命令打印到日志中,以便跟踪执行进度。
- 然后,构建数据库连接信息字符串 conninfo,该字符串包括数据库名 、端口号 、应用程序名称以及其他参数。
- 使用 PQconnectdb 函数基于构建好的连接信息建立与数据库的连接(m_pgconn)。
- 检查与数据库的连接状态是否正常(
PQstatus(m_pgconn) == CONNECTION_OK
)。- 如果连接成功,继续遍历 m_query 列表中的每个查询命令,依次执行这些命令,同时记录执行结果。
- 如果某个查询命令执行失败 (executeSQLCommand 返回 false ),则中断执行 ,并将 result 设置为 false。
- 如果与数据库的连接失败 ,将错误信息 打印到日志中。
- 最后,清理资源 ,包括释放查询结果对象 (PQclear(m_res) )、关闭与数据库的连接 (PQfinish(m_pgconn) ),并将 m_res 和 m_pgconn 置为 NULL。
- 返回执行的结果,如果所有查询都成功执行,则 result 为 true ,否则为 false。
AutoAnaProcess::check_conditions 函数
在 AutoAnaProcess::runAutoAnalyze 函数中采用 AutoAnaProcess::check_conditions 函数检查是否满足自动分析的条件。该函数主要用于确保执行自动分析的用户有足够的权限 ,并且不分析临时表以及在只读模式下的表。如果满足这些条件,函数返回 true ,允许执行自动分析操作 。否则,返回 false ,不执行自动分析 。
AutoAnaProcess::runAutoAnalyze 函数源码如下:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
/*
* check_conditions
* 检查执行自动分析的用户权限以及表是否为临时表
*/
bool AutoAnaProcess::check_conditions(Relation rel)
{
/* 如果传入的关系(表)是无效的,直接返回false */
if (!rel)
return false;
/* 如果传入的关系是临时表,直接返回false */
if (RelationIsLocalTemp(rel))
return false;
/*
* 如果关系处于只读模式(非数据重分布的情况),我们跳过对该关系的分析。
*/
if (!u_sess->attr.attr_sql.enable_cluster_resize && RelationInClusterResizingReadOnly(rel))
return false;
// 使用ACL检查当前用户是否有执行VACUUM操作的权限
AclResult aclresult = pg_class_aclcheck(RelationGetRelid(rel), GetUserId(), ACL_VACUUM);
if (aclresult != ACLCHECK_OK && !(pg_class_ownercheck(RelationGetRelid(rel), GetUserId()) ||
(pg_database_ownercheck(u_sess->proc_cxt.MyDatabaseId, GetUserId()) && !rel->rd_rel->relisshared))) {
return false;
}
return true; // 如果所有条件都满足,返回true表示可以执行自动分析
}
以下是函数的执行过程简述:
- 首先,函数接收一个名为 rel 的参数,这个参数是一个数据库表(关系)的指针 ,用于表示要进行自动分析的表。
- 函数开始执行时,首先检查传入的表是否为无效表,如果是无效表(即空指针),则直接返回 false ,表示不满足执行自动分析的条件。
- 接下来,函数检查传入的表是否为临时表,如果是临时表 ,则同样返回 false ,因为临时表通常不需要进行自动分析。
- 如果传入的表不是临时表 ,函数会继续检查是否处于只读模式。如果表处于只读模式 ,通常意味着它是分布式数据库中的只读副本 ,不需要进行自动分析 。如果在只读模式下,函数也会返回 false。
- 最后,函数会进行访问控制列表(ACL)检查 ,以确保当前用户具有执行 VACUUM 操作的权限。如果用户没有这个权限,并且用户不是表的所有者 ,也不是数据库的所有者(只有在表不是共享表的情况下),则函数返回 false。
- 如果所有条件都满足,即表有效 、不是临时表 、不处于只读模式,且用户有足够的权限,函数将返回 true ,表示可以执行自动分析操作。
AutoAnaProcess::cancelAutoAnalyze 函数
AutoAnaProcess::cancelAutoAnalyze 函数的作用是取消正在执行的自动分析过程。它通过释放相关资源 、增加可用的自动分析进程数量 ,以及清除执行计划信息来中止自动分析 ,从而管理和控制自动分析的执行 。
cancelAutoAnalyze 函数源码如下:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
void AutoAnaProcess::cancelAutoAnalyze()
{
/* 如果当前存在正在执行的自动分析进程 */
if (u_sess->analyze_cxt.autoanalyze_process != NULL) {
/* 执行资源清理操作 */
tear_down();
/* 释放自动分析进程资源,增加可用的自动分析进程数量 */
(void)LWLockAcquire(AutoanalyzeLock, LW_EXCLUSIVE);
autoAnalyzeFreeProcess++;
LWLockRelease(AutoanalyzeLock);
}
/* 清除自动分析的执行计划信息,如果存在的话 */
if (u_sess->analyze_cxt.autoanalyze_timeinfo != NULL) {
/* 释放执行计划信息的内存 */
pfree_ext(u_sess->analyze_cxt.autoanalyze_timeinfo->data);
pfree_ext(u_sess->analyze_cxt.autoanalyze_timeinfo);
u_sess->analyze_cxt.autoanalyze_timeinfo = NULL;
}
}
该函数用于取消正在执行的自动分析过程,其执行过程如下:
- 首先检查是否存在正在执行的自动分析进程 (
u_sess->analyze_cxt.autoanalyze_process
不为空)。- 如果存在正在执行的自动分析进程 ,执行资源清理操作 (tear_down 函数),包括关闭与数据库的连接等。
- 释放自动分析进程资源 ,并增加可用的自动分析进程数量 (通过获取和释放锁 AutoanalyzeLock 来实现并发安全性)。
- 接着,检查是否存在自动分析的执行计划信息 (
u_sess->analyze_cxt.autoanalyze_timeinfo
不为空)。- 如果存在执行计划信息 ,释放执行计划信息的内存 ,将其清空。
AutoAnaProcess::~AutoAnaProcess 函数
~AutoAnaProcess 为析构函数 ,用于释放AutoAnaProcess 对象所占用的资源,包括关闭数据库连接 、清理查询结果 、释放查询命令列表的资源 ,并将相关指针和列表重置为空或 NULL ,以确保资源的正确释放 和避免内存泄漏 。函数源码如下:(路径:src/gausskernel/optimizer/util/autoanalyzer.cpp
)
c
AutoAnaProcess::~AutoAnaProcess()
{
if (t_thrd.utils_cxt.CurrentResourceOwner == NULL) {
m_res = NULL;
}
PQclear(m_res); // 清理查询结果
PQfinish(m_pgconn); // 关闭数据库连接
if (m_query != NIL) {
list_free_deep(m_query); // 递归释放查询命令列表的资源
}
m_pgconn = NULL; // 重置数据库连接指针
m_res = NULL; // 重置查询结果指针
m_query = NIL; // 重置查询命令列表
}