X-Git-Url: http://sigaev.ru/git/gitweb.cgi?a=blobdiff_plain;f=online_analyze.c;h=3051283d93ab2134897cb4d2c287abab012544da;hb=b51c5ba03f154a3a5bfafeb0cb962c2fd16975f9;hp=2ef4193306edc650716ce35d13b447793666475e;hpb=a99e7faa88748694900e81d84508cbe2d54e9689;p=online_analyze.git diff --git a/online_analyze.c b/online_analyze.c index 2ef4193..3051283 100644 --- a/online_analyze.c +++ b/online_analyze.c @@ -31,6 +31,7 @@ #include "pgstat.h" #include "access/transam.h" +#include "access/xact.h" #include "catalog/namespace.h" #include "commands/vacuum.h" #include "executor/executor.h" @@ -63,6 +64,7 @@ PG_MODULE_MAGIC; #endif static bool online_analyze_enable = true; +static bool online_analyze_local_tracking = false; static bool online_analyze_verbose = true; static double online_analyze_scale_factor = 0.1; static int online_analyze_threshold = 50; @@ -82,9 +84,13 @@ typedef enum CmdKind CK_INSERT = CMD_INSERT, CK_DELETE = CMD_DELETE, CK_TRUNCATE, - CK_CREATE + CK_FASTTRUNCATE, + CK_CREATE, + CK_ANALYZE, + CK_VACUUM } CmdKind; + typedef enum { OATT_ALL = 0x03, @@ -440,15 +446,31 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) rstat->tableid = relOid; newTable = true; } + else if (operation == CK_VACUUM) + { + /* force reread becouse vacuum could change n_tuples */ + rstat->rereadStat = true; + return; + } + else if (operation == CK_ANALYZE) + { + /* only analyze */ + rstat->changes_since_analyze = 0; + rstat->analyze_timestamp = now; + return; + } Assert(rstat->tableid == relOid); - elog(NOTICE,"makeAnalyze op:%d %u", operation, naffected); - - if (operation != CK_TRUNCATE && - (found == false || rstat->rereadStat == true)) + if ( + /* do not reread data if it was a truncation */ + operation != CK_TRUNCATE && operation != CK_FASTTRUNCATE && + /* read for persistent table and for temp teble if it allowed */ + (reltype == OATT_PERSISTENT || online_analyze_local_tracking == false) && + /* read only for new table or we know that it's needed */ + (newTable == true || rstat->rereadStat == true) + ) { - rstat->rereadStat = false; tabentry = pgstat_fetch_stat_tabentry(relOid); @@ -470,7 +492,7 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) } if (newTable || - /* force analyze from after truncate */ + /* force analyze after truncate, fasttruncate already did analyze */ operation == CK_TRUNCATE || ( /* do not analyze too often, if both stamps are exceeded the go */ TimestampDifferenceExceeds(rstat->analyze_timestamp, now, online_analyze_min_interval) && @@ -536,6 +558,9 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) #endif ); + /* Make changes visible to subsequent calls */ + CommandCounterIncrement(); + if (online_analyze_verbose) { long secs; @@ -553,20 +578,17 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) switch(operation) { + case CK_CREATE: case CK_INSERT: - rstat->n_tuples += naffected; - rstat->rereadStat = false; - break; case CK_UPDATE: rstat->n_tuples += naffected; - rstat->rereadStat = true; - break; case CK_DELETE: - rstat->rereadStat = true; + rstat->rereadStat = (reltype == OATT_PERSISTENT); break; case CK_TRUNCATE: - rstat->n_tuples = 0; + case CK_FASTTRUNCATE: rstat->rereadStat = false; + rstat->n_tuples = 0; break; default: break; @@ -592,6 +614,7 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) #endif switch(operation) { + case CK_CREATE: case CK_INSERT: rstat->changes_since_analyze += naffected; rstat->n_tuples += naffected; @@ -603,6 +626,7 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) rstat->changes_since_analyze += naffected; break; case CK_TRUNCATE: + case CK_FASTTRUNCATE: rstat->changes_since_analyze = 0; rstat->n_tuples = 0; break; @@ -628,8 +652,7 @@ isFastTruncateCall(QueryDesc *queryDesc) queryDesc->operation == CMD_SELECT && queryDesc->plannedstmt->planTree && queryDesc->plannedstmt->planTree->targetlist && - list_length(queryDesc->plannedstmt->planTree->targetlist) == 1 && - IsA(linitial(queryDesc->plannedstmt->planTree->targetlist), TargetEntry) + list_length(queryDesc->plannedstmt->planTree->targetlist) == 1 )) return NULL; @@ -646,8 +669,7 @@ isFastTruncateCall(QueryDesc *queryDesc) fe->funcretset == false && fe->funcresulttype == VOIDOID && fe->funcvariadic == false && - list_length(fe->args) == 1 && - IsA(linitial(fe->args), Const) + list_length(fe->args) == 1 )) return NULL; @@ -664,7 +686,6 @@ isFastTruncateCall(QueryDesc *queryDesc) } - extern PGDLLIMPORT void onlineAnalyzeHooker(QueryDesc *queryDesc); void onlineAnalyzeHooker(QueryDesc *queryDesc) @@ -675,6 +696,7 @@ onlineAnalyzeHooker(QueryDesc *queryDesc) if (queryDesc->estate) naffected = queryDesc->estate->es_processed; +#if PG_VERSION_NUM >= 90200 if (online_analyze_enable && (constval = isFastTruncateCall(queryDesc)) != NULL) { @@ -684,12 +706,11 @@ onlineAnalyzeHooker(QueryDesc *queryDesc) makeRangeVarFromNameList(stringToQualifiedNameList(tblname)); makeAnalyze(RangeVarGetRelid(tblvar, -#if PG_VERSION_NUM >= 90200 NoLock, -#endif false), - CK_TRUNCATE, -1); + CK_FASTTRUNCATE, -1); } +#endif if (online_analyze_enable && queryDesc->plannedstmt && (queryDesc->operation == CMD_INSERT || @@ -732,6 +753,37 @@ onlineAnalyzeHooker(QueryDesc *queryDesc) standard_ExecutorEnd(queryDesc); } +static List *toremove = NIL; + +/* + * removeTable called on transaction end, see call RegisterXactCallback() below + */ +static void +removeTable(XactEvent event, void *arg) +{ + ListCell *cell; + + switch(event) + { + case XACT_EVENT_COMMIT: + break; + case XACT_EVENT_ABORT: + toremove = NIL; + default: + return; + } + + foreach(cell, toremove) + { + Oid relOid = lfirst_oid(cell); + + hash_search(relstats, &relOid, HASH_REMOVE, NULL); + } + + toremove = NIL; +} + + #if PG_VERSION_NUM >= 90200 static void onlineAnalyzeHookerUtility( @@ -773,6 +825,66 @@ onlineAnalyzeHookerUtility( tblnames = list_copy(((TruncateStmt*)parsetree)->relations); op = CK_TRUNCATE; } + else if (IsA(parsetree, DropStmt) && + ((DropStmt*)parsetree)->removeType == OBJECT_TABLE) + { + ListCell *cell; + + foreach(cell, ((DropStmt*)parsetree)->objects) + { + List *relname = (List *) lfirst(cell); + RangeVar *rel = makeRangeVarFromNameList(relname); + Oid relOid = RangeVarGetRelid(rel, NoLock, true); + + if (OidIsValid(relOid)) + { + MemoryContext ctx; + + ctx = MemoryContextSwitchTo(TopTransactionContext); + toremove = lappend_oid(toremove, relOid); + MemoryContextSwitchTo(ctx); + } + } + } + else if (IsA(parsetree, VacuumStmt)) + { + VacuumStmt *vac = (VacuumStmt*)parsetree; + + if (vac->relation) + tblnames = list_make1(vac->relation); + + if (vac->options & (VACOPT_VACUUM | VACOPT_FULL | VACOPT_FREEZE)) + { + /* optionally with analyze */ + op = CK_VACUUM; + + /* drop all collected stat */ + if (tblnames == NIL) + relstatsInit(); + } + else if (vac->options & VACOPT_ANALYZE) + { + op = CK_ANALYZE; + + /* should reset all counters */ + if (tblnames == NIL) + { + HASH_SEQ_STATUS hs; + OnlineAnalyzeTableStat *rstat; + TimestampTz now = GetCurrentTimestamp(); + + hash_seq_init(&hs, relstats); + + while((rstat = hash_seq_search(&hs)) != NULL) + { + rstat->changes_since_analyze = 0; + rstat->analyze_timestamp = now; + } + } + } + else + tblnames = NIL; + } } #if PG_VERSION_NUM >= 100000 @@ -899,6 +1011,25 @@ _PG_init(void) NULL ); + DefineCustomBoolVariable( + "online_analyze.local_tracking", + "Per backend tracking", + "Per backend tracking for temp tables (do not use system statistic)", + &online_analyze_local_tracking, +#if PG_VERSION_NUM >= 80400 + online_analyze_local_tracking, +#endif + PGC_USERSET, +#if PG_VERSION_NUM >= 80400 + GUC_NOT_IN_SAMPLE, +#if PG_VERSION_NUM >= 90100 + NULL, +#endif +#endif + NULL, + NULL + ); + DefineCustomBoolVariable( "online_analyze.verbose", "Verbosity of on-line analyze", @@ -1081,6 +1212,7 @@ _PG_init(void) NULL ); + RegisterXactCallback(removeTable, NULL); } void _PG_fini(void);