X-Git-Url: http://sigaev.ru/git/gitweb.cgi?a=blobdiff_plain;f=online_analyze.c;h=20b0e82f04bd29d6cf9eee19831b77a9f30be834;hb=31796cdacc6581574928d3ae6b1010d7700e456f;hp=dba4226e9c784aafb698acaaced999c3dc8561f8;hpb=c9269992af6697609f1f5cb549ade03bab4cf1ba;p=online_analyze.git diff --git a/online_analyze.c b/online_analyze.c index dba4226..20b0e82 100644 --- a/online_analyze.c +++ b/online_analyze.c @@ -30,6 +30,8 @@ #include "postgres.h" #include "pgstat.h" +#include "access/transam.h" +#include "access/xact.h" #include "catalog/namespace.h" #include "commands/vacuum.h" #include "executor/executor.h" @@ -62,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; @@ -81,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, @@ -439,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); @@ -469,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) && @@ -535,6 +558,9 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) #endif ); + /* Make changes visible to subsequent calls */ + CommandCounterIncrement(); + if (online_analyze_verbose) { long secs; @@ -552,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; @@ -591,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; @@ -602,7 +626,8 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) rstat->changes_since_analyze += naffected; break; case CK_TRUNCATE: - rstat->changes_since_analyze = rstat->n_tuples; + case CK_FASTTRUNCATE: + rstat->changes_since_analyze = 0; rstat->n_tuples = 0; break; default: @@ -615,15 +640,78 @@ makeAnalyze(Oid relOid, CmdKind operation, int64 naffected) relstatsInit(); } +static Const* +isFastTruncateCall(QueryDesc *queryDesc) +{ + TargetEntry *te; + FuncExpr *fe; + Const *constval; + + if (!( + queryDesc->plannedstmt && + queryDesc->operation == CMD_SELECT && + queryDesc->plannedstmt->planTree && + queryDesc->plannedstmt->planTree->targetlist && + list_length(queryDesc->plannedstmt->planTree->targetlist) == 1 + )) + return NULL; + + te = linitial(queryDesc->plannedstmt->planTree->targetlist); + + if (!IsA(te, TargetEntry)) + return NULL; + + fe = (FuncExpr*)te->expr; + + if (!( + fe && IsA(fe, FuncExpr) && + fe->funcid >= FirstNormalObjectId && + fe->funcretset == false && + fe->funcresulttype == VOIDOID && + fe->funcvariadic == false && + list_length(fe->args) == 1 + )) + return NULL; + + constval = linitial(fe->args); + + if (!( + IsA(constval,Const) && + constval->consttype == TEXTOID && + strcmp(get_func_name(fe->funcid), "fasttruncate") == 0 + )) + return NULL; + + return constval; +} + + extern PGDLLIMPORT void onlineAnalyzeHooker(QueryDesc *queryDesc); void onlineAnalyzeHooker(QueryDesc *queryDesc) { int64 naffected = -1; + Const *constval; if (queryDesc->estate) naffected = queryDesc->estate->es_processed; +#if PG_VERSION_NUM >= 90200 + if (online_analyze_enable && + (constval = isFastTruncateCall(queryDesc)) != NULL) + { + Datum tblnamed = constval->constvalue; + char *tblname = text_to_cstring(DatumGetTextP(tblnamed)); + RangeVar *tblvar = + makeRangeVarFromNameList(stringToQualifiedNameList(tblname)); + + makeAnalyze(RangeVarGetRelid(tblvar, + NoLock, + false), + CK_FASTTRUNCATE, -1); + } +#endif + if (online_analyze_enable && queryDesc->plannedstmt && (queryDesc->operation == CMD_INSERT || queryDesc->operation == CMD_UPDATE || @@ -665,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( @@ -706,6 +825,70 @@ 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 PG_VERSION_NUM >= 110000 + tblnames = vac->rels; +#else + if (vac->relation) + tblnames = list_make1(vac->relation); +#endif + + 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 @@ -832,6 +1015,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", @@ -1014,6 +1216,7 @@ _PG_init(void) NULL ); + RegisterXactCallback(removeTable, NULL); } void _PG_fini(void);