@@ -333,13 +333,34 @@ learn_subplan_recurse(PlanState *p, aqo_obj_stat *ctx)
333333}
334334
335335static bool
336- should_learn (aqo_obj_stat * ctx ,double predicted ,double * nrows )
336+ should_learn (PlanState * ps ,AQOPlanNode * node ,aqo_obj_stat * ctx ,
337+ double predicted ,double * nrows )
337338{
338339if (ctx -> isTimedOut )
339340{
340341if (ctx -> learn && * nrows > predicted * 1.2 )
341342{
342- * nrows += (* nrows - predicted )* 10. ;
343+ /* This node s*/
344+ if (aqo_show_details )
345+ elog (NOTICE ,
346+ "[AQO] Learn on a plan node (%lu, %d), "
347+ "predicted rows: %.0lf, updated prediction: %.0lf" ,
348+ query_context .query_hash ,node -> fss ,predicted ,* nrows );
349+
350+ return true;
351+ }
352+
353+ /* Has the executor finished its work? */
354+ if (TupIsNull (ps -> ps_ResultTupleSlot )&&
355+ ps -> instrument -> nloops > 0. )/* Node was visited by executor at least once. */
356+ {
357+ /* This is much more reliable data. So we can correct our prediction. */
358+ if (ctx -> learn && aqo_show_details && fabs (* nrows - predicted ) /predicted > 0.2 )
359+ elog (NOTICE ,
360+ "[AQO] Learn on a finished plan node (%lu, %d), "
361+ "predicted rows: %.0lf, updated prediction: %.0lf" ,
362+ query_context .query_hash ,node -> fss ,predicted ,* nrows );
363+
343364return true;
344365}
345366}
@@ -509,12 +530,8 @@ learnOnPlanState(PlanState *p, void *context)
509530{
510531Assert (predicted >=1. && learn_rows >=1. );
511532
512- if (should_learn (ctx ,predicted ,& learn_rows ))
533+ if (should_learn (p , aqo_node , ctx ,predicted ,& learn_rows ))
513534{
514- if (ctx -> isTimedOut && aqo_show_details )
515- elog (NOTICE ,"[AQO] Learn on partially executed plan node. fs: %lu, fss: %d, predicted rows: %.0lf, updated prediction: %.0lf" ,
516- query_context .query_hash ,aqo_node -> fss ,predicted ,learn_rows );
517-
518535if (IsA (p ,AggState ))
519536learn_agg_sample (& SubplanCtx ,
520537aqo_node -> relids ,learn_rows ,