4 #include "catalog/namespace.h"
5 #include "commands/vacuum.h"
6 #include "executor/executor.h"
7 #include "nodes/nodes.h"
8 #include "nodes/parsenodes.h"
9 #include "storage/bufmgr.h"
10 #include "utils/lsyscache.h"
11 #include "utils/guc.h"
13 #ifdef PG_MODULE_MAGIC
17 static bool online_analyze_enable = true;
18 static bool online_analyze_verbose = true;
19 static double online_analyze_scale_factor = 0.1;
20 static int online_analyze_threshold = 50;
21 static double online_analyze_min_interval = 10000;
23 static ExecutorEnd_hook_type oldhook = NULL;
26 makeAnalyze(Oid relOid, CmdType operation, uint32 naffected)
28 PgStat_StatTabEntry *tabentry;
29 TimestampTz now = GetCurrentTimestamp();
31 if (relOid == InvalidOid)
34 tabentry = pgstat_fetch_stat_tabentry(relOid);
36 #if PG_VERSION_NUM >= 90000
37 #define changes_since_analyze(t) ((t)->changes_since_analyze)
39 #define changes_since_analyze(t) ((t)->n_live_tuples + (t)->n_dead_tuples - (t)->last_anl_tuples)
43 tabentry == NULL /* a new table */ ||
45 /* do not analyze too often, if both stamps are exceeded the go */
46 TimestampDifferenceExceeds(tabentry->analyze_timestamp, now, online_analyze_min_interval) &&
47 TimestampDifferenceExceeds(tabentry->autovac_analyze_timestamp, now, online_analyze_min_interval) &&
48 /* be in sync with relation_needs_vacanalyze */
49 ((double)(changes_since_analyze(tabentry) + naffected)) >=
50 online_analyze_scale_factor * ((double)(tabentry->n_dead_tuples + tabentry->n_live_tuples)) +
51 (double)online_analyze_threshold
56 TimestampTz startStamp, endStamp;
58 vacstmt.type = T_VacuumStmt;
59 vacstmt.freeze_min_age = -1;
60 vacstmt.freeze_table_age = -1; /* ??? */
61 vacstmt.relation = NULL;
62 vacstmt.va_cols = NIL;
64 #if PG_VERSION_NUM >= 90000
65 vacstmt.options = VACOPT_ANALYZE;
66 if (online_analyze_verbose)
67 vacstmt.options |= VACOPT_VERBOSE;
69 vacstmt.vacuum = vacstmt.full = false;
70 vacstmt.analyze = true;
71 vacstmt.verbose = online_analyze_verbose;
74 if (online_analyze_verbose)
75 startStamp = GetCurrentTimestamp();
77 analyze_rel(relOid, &vacstmt, GetAccessStrategy(BAS_VACUUM)
78 #if (PG_VERSION_NUM < 90004) && (PG_VERSION_NUM >= 90000)
83 if (online_analyze_verbose)
88 endStamp = GetCurrentTimestamp();
89 TimestampDifference(startStamp, endStamp, &secs, µsecs);
90 elog(INFO, "analyze \"%s\" took %.02f seconds", get_rel_name(relOid), ((double)secs) + ((double)microsecs)/1.0e6);
97 pgstat_clear_snapshot();
101 /* update last analyze timestamp in local memory of backend */
102 tabentry->analyze_timestamp = now;
105 #if PG_VERSION_NUM >= 90000
106 else if (tabentry != NULL)
108 tabentry->changes_since_analyze += naffected;
113 extern PGDLLIMPORT void onlineAnalyzeHooker(QueryDesc *queryDesc);
115 onlineAnalyzeHooker(QueryDesc *queryDesc)
117 uint32 naffected = 0;
119 if (queryDesc->estate)
120 naffected = queryDesc->estate->es_processed;
122 if (online_analyze_enable && queryDesc->plannedstmt &&
123 (queryDesc->operation == CMD_INSERT ||
124 queryDesc->operation == CMD_UPDATE ||
125 queryDesc->operation == CMD_DELETE ||
126 (queryDesc->operation == CMD_SELECT && queryDesc->plannedstmt->intoClause)))
128 if (queryDesc->plannedstmt->intoClause)
130 Oid relOid = RangeVarGetRelid(queryDesc->plannedstmt->intoClause->rel, true);
132 makeAnalyze(relOid, queryDesc->operation, naffected);
134 else if (queryDesc->plannedstmt->resultRelations &&
135 queryDesc->plannedstmt->rtable)
139 foreach(l, queryDesc->plannedstmt->resultRelations)
141 int n = lfirst_int(l);
142 RangeTblEntry *rte = list_nth(queryDesc->plannedstmt->rtable, n-1);
144 if (rte->rtekind == RTE_RELATION)
145 makeAnalyze(rte->relid, queryDesc->operation, naffected);
151 (*oldhook)(queryDesc);
153 standard_ExecutorEnd(queryDesc);
160 oldhook = ExecutorEnd_hook;
162 ExecutorEnd_hook = onlineAnalyzeHooker;
164 DefineCustomBoolVariable(
165 "online_analyze.enable",
166 "Enable on-line analyze",
167 "Enables analyze of table directly after insert/update/delete/select into",
168 &online_analyze_enable,
169 #if PG_VERSION_NUM >= 80400
170 online_analyze_enable,
173 #if PG_VERSION_NUM >= 80400
175 #if PG_VERSION_NUM >= 90100
183 DefineCustomBoolVariable(
184 "online_analyze.verbose",
185 "Verbosity of on-line analyze",
186 "Make ANALYZE VERBOSE after table's changes",
187 &online_analyze_verbose,
188 #if PG_VERSION_NUM >= 80400
189 online_analyze_verbose,
192 #if PG_VERSION_NUM >= 80400
194 #if PG_VERSION_NUM >= 90100
202 DefineCustomRealVariable(
203 "online_analyze.scale_factor",
204 "fraction of table size to start on-line analyze",
205 "fraction of table size to start on-line analyze",
206 &online_analyze_scale_factor,
207 #if PG_VERSION_NUM >= 80400
208 online_analyze_scale_factor,
213 #if PG_VERSION_NUM >= 80400
215 #if PG_VERSION_NUM >= 90100
223 DefineCustomIntVariable(
224 "online_analyze.threshold",
225 "min number of row updates before on-line analyze",
226 "min number of row updates before on-line analyze",
227 &online_analyze_threshold,
228 #if PG_VERSION_NUM >= 80400
229 online_analyze_threshold,
234 #if PG_VERSION_NUM >= 80400
236 #if PG_VERSION_NUM >= 90100
244 DefineCustomRealVariable(
245 "online_analyze.min_interval",
246 "minimum time interval between analyze call (in milliseconds)",
247 "minimum time interval between analyze call (in milliseconds)",
248 &online_analyze_scale_factor,
249 #if PG_VERSION_NUM >= 80400
250 online_analyze_min_interval,
255 #if PG_VERSION_NUM >= 80400
257 #if PG_VERSION_NUM >= 90100
271 ExecutorEnd_hook = oldhook;