版本号
PostgreSQL 8.3.23 (Greenplum Database 5.0.0 build dev)
设置gp_enable_query_metrics
gpconfig -c gp_enable_query_metrics -v on //设置
gpstop -r //重启
hook
query_info_collect_hook可用于获取queryDesc相关信息
相关代码
以"SELECT * from instrument_test where id>1000 order by id limit 1000;"为例
PortalStart
void
PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot,
const char *seqServerHost, int seqServerPort, QueryDispatchDesc *ddesc)
{
PG_TRY();
{
switch (portal->strategy)
{
case PORTAL_ONE_SELECT:
/*
* #define GP_INSTRUMENT_OPTS (gp_enable_query_metrics ? INSTRUMENT_ROWS : INSTRUMENT_NONE)
* 因为开启了 gp_enable_query_metrics, queryDesc->instrument_options被设置
* 此处可以在gdb上设置 set var queryDesc->instrument_options=INSTRUMENT_ALL(0x7FFFFFFF),
* 以查看greenplum的处理
*/
queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
portal->sourceText,
(gp_select_invisible ? SnapshotAny : ActiveSnapshot),
InvalidSnapshot,
None_Receiver,
params,
GP_INSTRUMENT_OPTS);
// 这是运行时可以修改queryDesc->instrument_options的hook
if (query_info_collect_hook)
(*query_info_collect_hook)(METRICS_QUERY_SUBMIT, queryDesc);
ExecutorStart(queryDesc, eflags);
portal->queryDesc = queryDesc;
}
}
}
ExecutorStart
void
ExecutorStart(QueryDesc *queryDesc, int eflags)
{
EState *estate;
// 同样是运行时可以修改queryDesc->instrument_options的hook
if (query_info_collect_hook)
(*query_info_collect_hook)(METRICS_QUERY_START, queryDesc);
// 把queryDesc->instrument_options赋值给estate->es_instrument
estate->es_instrument = queryDesc->instrument_options;
PG_TRY();
{
InitPlan(queryDesc, eflags);
}
}
InitPlan
static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
PlanState *planstate;
planstate = ExecInitNode(start_plan_node, estate, eflags);
queryDesc->planstate = planstate;
if (query_info_collect_hook)
(*query_info_collect_hook)(METRICS_PLAN_NODE_INITIALIZE, queryDesc);
}
ExecInitNode
PlanState *
ExecInitNode(Plan *node, EState *estate, int eflags)
{
PlanState *result;
// 如果前面设置了queryDesc->instrument_options,这里会为queryDesc->planstate->instrument分配内存
if (estate->es_instrument && result != NULL)
result->instrument = GpInstrAlloc(node, estate->es_instrument);
return result;
}
GpInstrAlloc
Instrumentation *
GpInstrAlloc(const Plan *node, int instrument_options)
{
Instrumentation *instr = NULL;
if (shouldPickInstrInShmem(nodeTag(node)))
instr = pickInstrFromShmem(node, instrument_options);
return instr;
}
pickInstrFromShmem
static Instrumentation *
pickInstrFromShmem(const Plan *plan, int instrument_options)
{
Instrumentation *instr = NULL;
// 此处省略instr的处理步骤
/*
* 如果前面设置了set var queryDesc->instrument_options=INSTRUMENT_ALL(0x7FFFFFFF),
* 则这里会设置need_timer=true;
* need_cdb用于EXPLAIN ANALYZE
*/
if (NULL != instr && instrument_options & (INSTRUMENT_TIMER | INSTRUMENT_CDB))
{
instr->need_timer = (instrument_options & INSTRUMENT_TIMER) != 0;
instr->need_cdb = (instrument_options & INSTRUMENT_CDB) != 0;
}
return instr;
}
PortalRun
bool
PortalRun(Portal portal, int64 count, bool isTopLevel,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
PG_TRY();
{
switch (portal->strategy)
{
case PORTAL_ONE_SELECT:
(void) PortalRunSelect(portal, true, count, dest);
}
}
}
PortalRunSelect
static int64
PortalRunSelect(Portal portal,
bool forward,
int64 count,
DestReceiver *dest)
{
uint64 nprocessed;
if (forward)
{
if (portal->holdStore)
else
{
ExecutorRun(queryDesc, direction, count);
}
}
}
ExecutorRun
TupleTableSlot *
ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction, long count)
{
TupleTableSlot *result = NULL;
PG_TRY();
{
else if (exec_identity == GP_ROOT_SLICE)
{
result = ExecutePlan(estate,
queryDesc->planstate,
operation,
count,
direction,
dest);
}
}
}
ExecutePlan
static TupleTableSlot *
ExecutePlan(EState *estate,
PlanState *planstate,
CmdType operation,
long numberTuples,
ScanDirection direction,
DestReceiver *dest)
{
for (;;)
{
if (estate->es_useEvalPlan)
{
}
else
planSlot = ExecProcNode(planstate);
}
}
ExecProcNode
TupleTableSlot *
ExecProcNode(PlanState *node)
{
/*
* 如果前面用gdb设置了queryDesc->instrument_options=0x7FFFFFFF,
* 此处在获取一行tuple之前设置instrument->starttime
*/
if (node->instrument)
INSTR_START_NODE(node->instrument);
/*
* 此处会将获取每行tuple的时间累加到node->instrument->counter
*/
if (node->instrument)
INSTR_STOP_NODE(node->instrument, TupIsNull(result) ? 0 : 1);
}
PortalDrop
void
PortalDrop(Portal portal, bool isTopCommit)
{
if (portal->cleanup)
(*portal->cleanup) (portal); // 通过回调进入PortalCleanup
}
PortalCleanup
void
PortalCleanup(Portal portal)
{
queryDesc = PortalGetQueryDesc(portal);
if (queryDesc)
{ // queryDesc被释放
portal->queryDesc = NULL;
PG_TRY();
{
ExecutorEnd(queryDesc);
}
}
}
ExecutorEnd
void
ExecutorEnd(QueryDesc *queryDesc)
{
// 通过hook这个可以获得相关的统计数据
if (query_info_collect_hook)
(*query_info_collect_hook)(METRICS_QUERY_DONE, queryDesc);
}