diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 6408d16..bc72bff 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -64,9 +64,15 @@ static void show_qual(List *qual, const char *qlabel, static void show_scan_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es); +static void show_instrumented_scan_qual(List *qual, const char *qlabel, + PlanState *planstate, double nremoved, + List *ancestors, ExplainState *es); static void show_upper_qual(List *qual, const char *qlabel, PlanState *planstate, List *ancestors, ExplainState *es); +static void show_instrumented_upper_qual(List *qual, const char *qlabel, + PlanState *planstate, double nremoved, + List *ancestors, ExplainState *es); static void show_sort_keys(SortState *sortstate, List *ancestors, ExplainState *es); static void show_merge_append_keys(MergeAppendState *mstate, List *ancestors, @@ -1002,29 +1008,37 @@ ExplainNode(PlanState *planstate, List *ancestors, "Index Cond", planstate, ancestors, es); show_scan_qual(((IndexScan *) plan)->indexorderbyorig, "Order By", planstate, ancestors, es); - show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_scan_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); break; case T_BitmapIndexScan: show_scan_qual(((BitmapIndexScan *) plan)->indexqualorig, "Index Cond", planstate, ancestors, es); break; case T_BitmapHeapScan: - show_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, - "Recheck Cond", planstate, ancestors, es); + show_instrumented_scan_qual(((BitmapHeapScan *) plan)->bitmapqualorig, + "Recheck Cond", planstate, + ((BitmapHeapScanState *) planstate)->bqonremoved, + ancestors, es); /* FALL THRU */ case T_SeqScan: case T_ValuesScan: case T_CteScan: case T_WorkTableScan: case T_SubqueryScan: - show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_scan_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); break; case T_FunctionScan: if (es->verbose) show_expression(((FunctionScan *) plan)->funcexpr, "Function Call", planstate, ancestors, es->verbose, es); - show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_scan_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); break; case T_TidScan: { @@ -1037,35 +1051,47 @@ ExplainNode(PlanState *planstate, List *ancestors, if (list_length(tidquals) > 1) tidquals = list_make1(make_orclause(tidquals)); show_scan_qual(tidquals, "TID Cond", planstate, ancestors, es); - show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_scan_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); } break; case T_ForeignScan: - show_scan_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_scan_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); show_foreignscan_info((ForeignScanState *) planstate, es); break; case T_NestLoop: show_upper_qual(((NestLoop *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); - show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_upper_qual(plan->qual, "Filter", planstate, + ((JoinState *) planstate)->js_oqnremoved, + ancestors, es); break; case T_MergeJoin: show_upper_qual(((MergeJoin *) plan)->mergeclauses, "Merge Cond", planstate, ancestors, es); show_upper_qual(((MergeJoin *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); - show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_upper_qual(plan->qual, "Filter", planstate, + ((JoinState *) planstate)->js_oqnremoved, + ancestors, es); break; case T_HashJoin: show_upper_qual(((HashJoin *) plan)->hashclauses, "Hash Cond", planstate, ancestors, es); show_upper_qual(((HashJoin *) plan)->join.joinqual, "Join Filter", planstate, ancestors, es); - show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_upper_qual(plan->qual, "Filter", planstate, + ((JoinState *) planstate)->js_oqnremoved, + ancestors, es); break; case T_Agg: case T_Group: - show_upper_qual(plan->qual, "Filter", planstate, ancestors, es); + show_instrumented_upper_qual(plan->qual, "Filter", planstate, + ((ScanState *) planstate)->ss_qualnremoved, + ancestors, es); break; case T_Sort: show_sort_keys((SortState *) planstate, ancestors, es); @@ -1356,6 +1382,26 @@ show_scan_qual(List *qual, const char *qlabel, } /* + * Show a qualifier expression and instrumentation information (if in EXPLAIN + * ANALYZE) for a scan plan node + */ +static void +show_instrumented_scan_qual(List *qual, const char *qlabel, + PlanState *planstate, double nremoved, + List *ancestors, ExplainState *es) +{ + show_scan_qual(qual, qlabel, planstate, ancestors, es); + + if (qual && es->analyze) + { + char buf[256]; + snprintf(buf, sizeof(buf), "Rows Removed by %s", qlabel); + ExplainPropertyFloat(buf, nremoved / planstate->instrument->nloops, 0, es); + } +} + + +/* * Show a qualifier expression for an upper-level plan node */ static void @@ -1369,6 +1415,21 @@ show_upper_qual(List *qual, const char *qlabel, show_qual(qual, qlabel, planstate, ancestors, useprefix, es); } +static void +show_instrumented_upper_qual(List *qual, const char *qlabel, + PlanState *planstate, double nremoved, + List *ancestors, ExplainState *es) +{ + show_upper_qual(qual, qlabel, planstate, ancestors, es); + + if (qual && es->analyze) + { + char buf[256]; + snprintf(buf, sizeof(buf), "Rows Removed by %s", qlabel); + ExplainPropertyFloat(buf, nremoved / planstate->instrument->nloops, 0, es); + } +} + /* * Show the sort keys for a Sort node. */ diff --git a/src/backend/executor/execScan.c b/src/backend/executor/execScan.c index e900588..2de6b56 100644 --- a/src/backend/executor/execScan.c +++ b/src/backend/executor/execScan.c @@ -223,6 +223,7 @@ ExecScan(ScanState *node, /* * Tuple fails qual, so free per-tuple memory and try again. */ + node->ss_qualnremoved += 1; ResetExprContext(econtext); } } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 13d7723..0249c63 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1204,6 +1204,8 @@ agg_retrieve_direct(AggState *aggstate) return result; } } + else + aggstate->ss.ss_qualnremoved += 1; } /* No more groups */ @@ -1354,6 +1356,8 @@ agg_retrieve_hash_table(AggState *aggstate) return result; } } + else + aggstate->ss.ss_qualnremoved += 1; } /* No more groups */ @@ -1387,6 +1391,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) aggstate = makeNode(AggState); aggstate->ss.ps.plan = (Plan *) node; aggstate->ss.ps.state = estate; + aggstate->ss.ss_qualnremoved = 0; aggstate->aggs = NIL; aggstate->numaggs = 0; diff --git a/src/backend/executor/nodeBitmapHeapscan.c b/src/backend/executor/nodeBitmapHeapscan.c index 8e50fb1..abb9ff4 100644 --- a/src/backend/executor/nodeBitmapHeapscan.c +++ b/src/backend/executor/nodeBitmapHeapscan.c @@ -278,6 +278,7 @@ BitmapHeapNext(BitmapHeapScanState *node) if (!ExecQual(node->bitmapqualorig, econtext, false)) { /* Fails recheck, so drop it and loop back for another */ + node->bqonremoved += 1; ExecClearTuple(slot); continue; } @@ -542,7 +543,10 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) scanstate = makeNode(BitmapHeapScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; + + scanstate->bqonremoved = 0; scanstate->tbm = NULL; scanstate->tbmiterator = NULL; scanstate->tbmres = NULL; diff --git a/src/backend/executor/nodeBitmapIndexscan.c b/src/backend/executor/nodeBitmapIndexscan.c index 9a56fd4..4dd1367 100644 --- a/src/backend/executor/nodeBitmapIndexscan.c +++ b/src/backend/executor/nodeBitmapIndexscan.c @@ -207,6 +207,7 @@ ExecInitBitmapIndexScan(BitmapIndexScan *node, EState *estate, int eflags) indexstate = makeNode(BitmapIndexScanState); indexstate->ss.ps.plan = (Plan *) node; indexstate->ss.ps.state = estate; + indexstate->ss.ss_qualnremoved = 0; /* normally we don't make the result bitmap till runtime */ indexstate->biss_result = NULL; diff --git a/src/backend/executor/nodeCtescan.c b/src/backend/executor/nodeCtescan.c index ec39f29..fdef1e8 100644 --- a/src/backend/executor/nodeCtescan.c +++ b/src/backend/executor/nodeCtescan.c @@ -191,6 +191,7 @@ ExecInitCteScan(CteScan *node, EState *estate, int eflags) scanstate = makeNode(CteScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; scanstate->eflags = eflags; scanstate->cte_table = NULL; scanstate->eof_cte = false; diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 841ae69..6a25fd7 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -114,6 +114,7 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) scanstate = makeNode(ForeignScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c index 5d5727e..894208c 100644 --- a/src/backend/executor/nodeFunctionscan.c +++ b/src/backend/executor/nodeFunctionscan.c @@ -133,6 +133,7 @@ ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags) scanstate = makeNode(FunctionScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; scanstate->eflags = eflags; /* diff --git a/src/backend/executor/nodeGroup.c b/src/backend/executor/nodeGroup.c index fa403e5..f167a39 100644 --- a/src/backend/executor/nodeGroup.c +++ b/src/backend/executor/nodeGroup.c @@ -118,6 +118,8 @@ ExecGroup(GroupState *node) return result; } } + else + node->ss.ss_qualnremoved += 1; } /* @@ -179,6 +181,8 @@ ExecGroup(GroupState *node) return result; } } + else + node->ss.ss_qualnremoved += 1; } /* NOTREACHED */ @@ -206,6 +210,7 @@ ExecInitGroup(Group *node, EState *estate, int eflags) grpstate = makeNode(GroupState); grpstate->ss.ps.plan = (Plan *) node; grpstate->ss.ps.state = estate; + grpstate->ss.ss_qualnremoved = 0; grpstate->grp_done = FALSE; /* diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 3a66981..11aa4a6 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -325,6 +325,8 @@ ExecHashJoin(HashJoinState *node) return result; } } + else + node->js.js_oqnremoved += 1; } break; @@ -360,6 +362,8 @@ ExecHashJoin(HashJoinState *node) return result; } } + else + node->js.js_oqnremoved += 1; } break; @@ -397,6 +401,8 @@ ExecHashJoin(HashJoinState *node) return result; } } + else + node->js.js_oqnremoved += 1; break; case HJ_NEED_NEW_BATCH: @@ -442,6 +448,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) hjstate = makeNode(HashJoinState); hjstate->js.ps.plan = (Plan *) node; hjstate->js.ps.state = estate; + hjstate->js.js_oqnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 955008e..cb705f4 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -468,6 +468,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) indexstate = makeNode(IndexScanState); indexstate->ss.ps.plan = (Plan *) node; indexstate->ss.ps.state = estate; + indexstate->ss.ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeMergejoin.c b/src/backend/executor/nodeMergejoin.c index e23dd6c..b3a1b10 100644 --- a/src/backend/executor/nodeMergejoin.c +++ b/src/backend/executor/nodeMergejoin.c @@ -893,6 +893,8 @@ ExecMergeJoin(MergeJoinState *node) return result; } } + else + node->js.js_oqnremoved += 1; } break; @@ -1503,6 +1505,7 @@ ExecInitMergeJoin(MergeJoin *node, EState *estate, int eflags) mergestate = makeNode(MergeJoinState); mergestate->js.ps.plan = (Plan *) node; mergestate->js.ps.state = estate; + mergestate->js.js_oqnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeNestloop.c b/src/backend/executor/nodeNestloop.c index e98bc0f..a4b9c92 100644 --- a/src/backend/executor/nodeNestloop.c +++ b/src/backend/executor/nodeNestloop.c @@ -214,6 +214,8 @@ ExecNestLoop(NestLoopState *node) return result; } } + else + node->js.js_oqnremoved += 1; } /* @@ -270,6 +272,8 @@ ExecNestLoop(NestLoopState *node) return result; } } + else + node->js.js_oqnremoved += 1; } /* @@ -302,6 +306,7 @@ ExecInitNestLoop(NestLoop *node, EState *estate, int eflags) nlstate = makeNode(NestLoopState); nlstate->js.ps.plan = (Plan *) node; nlstate->js.ps.state = estate; + nlstate->js.js_oqnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c index 5b652c9..7a115c9 100644 --- a/src/backend/executor/nodeSeqscan.c +++ b/src/backend/executor/nodeSeqscan.c @@ -169,6 +169,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) scanstate = makeNode(SeqScanState); scanstate->ps.plan = (Plan *) node; scanstate->ps.state = estate; + scanstate->ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 7e4d5de..26e0e70 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -109,6 +109,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) subquerystate = makeNode(SubqueryScanState); subquerystate->ss.ps.plan = (Plan *) node; subquerystate->ss.ps.state = estate; + subquerystate->ss.ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeTidscan.c b/src/backend/executor/nodeTidscan.c index 69f47ff..68d61b9 100644 --- a/src/backend/executor/nodeTidscan.c +++ b/src/backend/executor/nodeTidscan.c @@ -491,6 +491,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) tidstate = makeNode(TidScanState); tidstate->ss.ps.plan = (Plan *) node; tidstate->ss.ps.state = estate; + tidstate->ss.ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeValuesscan.c b/src/backend/executor/nodeValuesscan.c index d5260e4..5d474f6 100644 --- a/src/backend/executor/nodeValuesscan.c +++ b/src/backend/executor/nodeValuesscan.c @@ -205,6 +205,7 @@ ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags) scanstate = makeNode(ValuesScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; /* * Miscellaneous initialization diff --git a/src/backend/executor/nodeWorktablescan.c b/src/backend/executor/nodeWorktablescan.c index bdebb6d..762605f 100644 --- a/src/backend/executor/nodeWorktablescan.c +++ b/src/backend/executor/nodeWorktablescan.c @@ -146,6 +146,7 @@ ExecInitWorkTableScan(WorkTableScan *node, EState *estate, int eflags) scanstate = makeNode(WorkTableScanState); scanstate->ss.ps.plan = (Plan *) node; scanstate->ss.ps.state = estate; + scanstate->ss.ss_qualnremoved = 0; scanstate->rustate = NULL; /* we'll set this later */ /* diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index b3eed7d..7139e8c 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -1170,6 +1170,7 @@ typedef struct ScanState Relation ss_currentRelation; HeapScanDesc ss_currentScanDesc; TupleTableSlot *ss_ScanTupleSlot; + double ss_qualnremoved; /* number of rows removed by ps.qual */ } ScanState; /* @@ -1280,6 +1281,7 @@ typedef struct BitmapHeapScanState { ScanState ss; /* its first field is NodeTag */ List *bitmapqualorig; + double bqonremoved; /* number of rows removed by bitmapqualorig */ TIDBitmap *tbm; TBMIterator *tbmiterator; TBMIterateResult *tbmres; @@ -1438,6 +1440,7 @@ typedef struct JoinState PlanState ps; JoinType jointype; List *joinqual; /* JOIN quals (in addition to ps.qual) */ + double js_oqnremoved; /* number of rows removed by otherqual (ps.qual) */ } JoinState; /* ----------------