Fix REFRESH MATERIALIZED VIEW to report activity to the stats collector.
The non-concurrent code path for REFRESH MATERIALIZED VIEW failed to report its updates to the stats collector. This is bad since it means auto-analyze doesn't know there's any work to be done. Adjust it to report the refresh as a table truncate followed by insertion of an appropriate number of rows. Since a matview could contain more than INT_MAX rows, change the signature of pgstat_count_heap_insert() to accept an int64 rowcount. (The accumulator it's adding into is already int64, but existing callers could not insert more than a small number of rows at once, so the argument had been declared just "int n".) This is surely a bug fix, but changing pgstat_count_heap_insert()'s API seems too risky for the back branches. Given the lack of previous complaints, I'm not sure it's a big enough problem to justify a kluge solution that would avoid that. So, no back-patch, at least for now. Jim Mlodgenski, adjusted a bit by me Discussion: https://postgr.es/m/CAB_5SRchSz7-WmdO5szdiknG8Oj_GGqJytrk1KRd11yhcMs1KQ@mail.gmail.com
This commit is contained in:
parent
27f1f585fd
commit
17f8ffa1e3
@ -30,6 +30,7 @@
|
|||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "parser/parse_relation.h"
|
#include "parser/parse_relation.h"
|
||||||
|
#include "pgstat.h"
|
||||||
#include "rewrite/rewriteHandler.h"
|
#include "rewrite/rewriteHandler.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/smgr.h"
|
#include "storage/smgr.h"
|
||||||
@ -59,7 +60,7 @@ static void transientrel_startup(DestReceiver *self, int operation, TupleDesc ty
|
|||||||
static bool transientrel_receive(TupleTableSlot *slot, DestReceiver *self);
|
static bool transientrel_receive(TupleTableSlot *slot, DestReceiver *self);
|
||||||
static void transientrel_shutdown(DestReceiver *self);
|
static void transientrel_shutdown(DestReceiver *self);
|
||||||
static void transientrel_destroy(DestReceiver *self);
|
static void transientrel_destroy(DestReceiver *self);
|
||||||
static void refresh_matview_datafill(DestReceiver *dest, Query *query,
|
static uint64 refresh_matview_datafill(DestReceiver *dest, Query *query,
|
||||||
const char *queryString);
|
const char *queryString);
|
||||||
|
|
||||||
static char *make_temptable_name_n(char *tempname, int n);
|
static char *make_temptable_name_n(char *tempname, int n);
|
||||||
@ -145,6 +146,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||||||
Oid relowner;
|
Oid relowner;
|
||||||
Oid OIDNewHeap;
|
Oid OIDNewHeap;
|
||||||
DestReceiver *dest;
|
DestReceiver *dest;
|
||||||
|
uint64 processed = 0;
|
||||||
bool concurrent;
|
bool concurrent;
|
||||||
LOCKMODE lockmode;
|
LOCKMODE lockmode;
|
||||||
char relpersistence;
|
char relpersistence;
|
||||||
@ -322,7 +324,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||||||
|
|
||||||
/* Generate the data, if wanted. */
|
/* Generate the data, if wanted. */
|
||||||
if (!stmt->skipData)
|
if (!stmt->skipData)
|
||||||
refresh_matview_datafill(dest, dataQuery, queryString);
|
processed = refresh_matview_datafill(dest, dataQuery, queryString);
|
||||||
|
|
||||||
heap_close(matviewRel, NoLock);
|
heap_close(matviewRel, NoLock);
|
||||||
|
|
||||||
@ -345,8 +347,20 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||||||
Assert(matview_maintenance_depth == old_depth);
|
Assert(matview_maintenance_depth == old_depth);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
|
refresh_by_heap_swap(matviewOid, OIDNewHeap, relpersistence);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inform stats collector about our activity: basically, we truncated
|
||||||
|
* the matview and inserted some new data. (The concurrent code path
|
||||||
|
* above doesn't need to worry about this because the inserts and
|
||||||
|
* deletes it issues get counted by lower-level code.)
|
||||||
|
*/
|
||||||
|
pgstat_count_truncate(matviewRel);
|
||||||
|
if (!stmt->skipData)
|
||||||
|
pgstat_count_heap_insert(matviewRel, processed);
|
||||||
|
}
|
||||||
|
|
||||||
/* Roll back any GUC changes */
|
/* Roll back any GUC changes */
|
||||||
AtEOXact_GUC(false, save_nestlevel);
|
AtEOXact_GUC(false, save_nestlevel);
|
||||||
|
|
||||||
@ -360,8 +374,13 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* refresh_matview_datafill
|
* refresh_matview_datafill
|
||||||
|
*
|
||||||
|
* Execute the given query, sending result rows to "dest" (which will
|
||||||
|
* insert them into the target matview).
|
||||||
|
*
|
||||||
|
* Returns number of rows inserted.
|
||||||
*/
|
*/
|
||||||
static void
|
static uint64
|
||||||
refresh_matview_datafill(DestReceiver *dest, Query *query,
|
refresh_matview_datafill(DestReceiver *dest, Query *query,
|
||||||
const char *queryString)
|
const char *queryString)
|
||||||
{
|
{
|
||||||
@ -369,6 +388,7 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
|
|||||||
PlannedStmt *plan;
|
PlannedStmt *plan;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
Query *copied_query;
|
Query *copied_query;
|
||||||
|
uint64 processed;
|
||||||
|
|
||||||
/* Lock and rewrite, using a copy to preserve the original query. */
|
/* Lock and rewrite, using a copy to preserve the original query. */
|
||||||
copied_query = copyObject(query);
|
copied_query = copyObject(query);
|
||||||
@ -406,6 +426,8 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
|
|||||||
/* run the plan */
|
/* run the plan */
|
||||||
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
|
||||||
|
|
||||||
|
processed = queryDesc->estate->es_processed;
|
||||||
|
|
||||||
/* and clean up */
|
/* and clean up */
|
||||||
ExecutorFinish(queryDesc);
|
ExecutorFinish(queryDesc);
|
||||||
ExecutorEnd(queryDesc);
|
ExecutorEnd(queryDesc);
|
||||||
@ -413,6 +435,8 @@ refresh_matview_datafill(DestReceiver *dest, Query *query,
|
|||||||
FreeQueryDesc(queryDesc);
|
FreeQueryDesc(queryDesc);
|
||||||
|
|
||||||
PopActiveSnapshot();
|
PopActiveSnapshot();
|
||||||
|
|
||||||
|
return processed;
|
||||||
}
|
}
|
||||||
|
|
||||||
DestReceiver *
|
DestReceiver *
|
||||||
|
@ -1803,7 +1803,7 @@ add_tabstat_xact_level(PgStat_TableStatus *pgstat_info, int nest_level)
|
|||||||
* pgstat_count_heap_insert - count a tuple insertion of n tuples
|
* pgstat_count_heap_insert - count a tuple insertion of n tuples
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
pgstat_count_heap_insert(Relation rel, int n)
|
pgstat_count_heap_insert(Relation rel, PgStat_Counter n)
|
||||||
{
|
{
|
||||||
PgStat_TableStatus *pgstat_info = rel->pgstat_info;
|
PgStat_TableStatus *pgstat_info = rel->pgstat_info;
|
||||||
|
|
||||||
|
@ -1256,7 +1256,7 @@ pgstat_report_wait_end(void)
|
|||||||
#define pgstat_count_buffer_write_time(n) \
|
#define pgstat_count_buffer_write_time(n) \
|
||||||
(pgStatBlockWriteTime += (n))
|
(pgStatBlockWriteTime += (n))
|
||||||
|
|
||||||
extern void pgstat_count_heap_insert(Relation rel, int n);
|
extern void pgstat_count_heap_insert(Relation rel, PgStat_Counter n);
|
||||||
extern void pgstat_count_heap_update(Relation rel, bool hot);
|
extern void pgstat_count_heap_update(Relation rel, bool hot);
|
||||||
extern void pgstat_count_heap_delete(Relation rel);
|
extern void pgstat_count_heap_delete(Relation rel);
|
||||||
extern void pgstat_count_truncate(Relation rel);
|
extern void pgstat_count_truncate(Relation rel);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user