Automatically trigger ANALYZE (COORDINATOR) on remote coordinators
authorPavan Deolasee <[email protected]>
Thu, 9 Aug 2018 08:25:05 +0000 (13:55 +0530)
committerPavan Deolasee <[email protected]>
Thu, 9 Aug 2018 08:25:05 +0000 (13:55 +0530)
One of the long standing problems in multi-coordinator setup is that when a
table is either manually ANALYZEd or auto-analyzed on a coordinator, the other
coordinators don't update their planner statistics automatically. This is even
a bigger problem with auto-analyze because a coordinator which is not involved
in any DMLs, may not be even aware about the changes to the table and hence it
will not pick up the table for auto-analyze, thus often generating very poor
query plans.

We now fix that by automatically running ANALYZE (COORDINATOR) command on the
remote coordinators when a table is either manually or automatically analyzed
on one coordinator. ANALYZE (COORDINATOR) does not force a ANALYZE on the
datanodes, but only rebuilts coordinator side stats using the current stats
available on the datanodes.

One problem with running ANALYZE on the remote coordinators in auto-analyze
process is that if one of the coordinators is down or not reachable, then it
will fail. This seems a bit too harsh because the worst that can happen is that
the unreachably coordinator will be left with stale stats. But that seems
better than letting auto-analyze fail on a running coordinator. We address this
by introducing a new mechanism by which a coordinator can execute a
command/query only on the currently available remote coordinators. We consult
the health-map to decide which coordinators are currently reachable. Since the
health-map itself can be stale for some short duration, there is a risk that
auto-analyze may still fail. But it shouldn't fail forever because the node
will be skipped next time.

src/backend/commands/analyze.c
src/backend/pgxc/locator/locator.c
src/backend/pgxc/pool/execRemote.c
src/include/pgxc/locator.h
src/include/pgxc/planner.h

index 5d5bfa1afb5e775908038d516298b606bd3da8d6..c439ff6cd25d1b967523abded7929ffcea7399a8 100644 (file)
@@ -117,6 +117,7 @@ static Datum ind_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
 static void analyze_rel_coordinator(Relation onerel, bool inh, int attr_cnt,
                                                VacAttrStats **vacattrstats, int nindexes,
                                                Relation *indexes, AnlIndexData *indexdata);
+static void analyze_remote_coordinators(Relation onerel);
 #endif
 
 /*
@@ -512,6 +513,11 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params,
                analyze_rel_coordinator(onerel, inh, attr_cnt, vacattrstats,
                                                                nindexes, Irel, indexdata);
 
+               /*
+                * Run ANALYZE on remote coordinators as well.
+                */
+               analyze_remote_coordinators(onerel);
+
                /*
                 * Skip acquiring local stats. Coordinator does not store data of
                 * distributed tables.
@@ -3611,4 +3617,37 @@ analyze_rel_coordinator(Relation onerel, bool inh, int attr_cnt,
        /* extended statistics (pg_statistic) for the relation */
        coord_collect_extended_stats(onerel, attr_cnt);
 }
+
+static void
+analyze_remote_coordinators(Relation onerel)
+{
+       RemoteQuery             *step;
+       StringInfoData  sql;
+
+       if (IsConnFromCoord())
+               return;
+
+       /*
+        * Temporary tables are not available on remote coordinators.
+        */
+       if (onerel->rd_rel->relpersistence == RELPERSISTENCE_TEMP)
+               return;
+
+       initStringInfo(&sql);
+       appendStringInfo(&sql, "ANALYZE (COORDINATOR) %s",
+                       quote_identifier(RelationGetRelationName(onerel)));
+
+       step = makeNode(RemoteQuery);
+       step->combine_type = COMBINE_TYPE_SAME;
+       step->exec_nodes = NULL;
+       step->exec_type = EXEC_ON_AVAILABLE_COORDS;
+       step->sql_statement = pstrdup(sql.data);
+
+       ExecRemoteUtility(step);
+       pfree(step->sql_statement);
+       pfree(step);
+
+       /* Be sure to advance the command counter after the last command */
+       CommandCounterIncrement();
+}
 #endif
index f7155efee383152f6eb70674a6471f08a11c63dd..7919bce606e8f3dfa6ffa5b9a704956bdb11a234 100644 (file)
@@ -505,6 +505,37 @@ GetAllCoordNodes(void)
 }
 
 
+/*
+ * Return a list of all currently available Coordinators. This is used to send
+ * commands to only those coordinators which are currently reachable per the
+ * health map, thus avoiding possible connection errors. Non-critical functions
+ * may use this list.
+ */
+List *
+GetAvailableCoordNodes(void)
+{
+       int                     i;
+       List       *nodeList = NIL;
+       Oid                     coOids[MaxCoords];
+       bool            coHealthMap[MaxCoords];
+       int                     numCo;
+       
+       PgxcNodeGetHealthMap(coOids, NULL, &numCo, NULL, coHealthMap, NULL);
+
+       for (i = 0; i < numCo; i++)
+       {
+               /*
+                * Do not put in list the Coordinator we are on,
+                * it doesn't make sense to connect to the local Coordinator.
+                */
+
+               if ((i != PGXCNodeId - 1) && coHealthMap[i])
+                       nodeList = lappend_int(nodeList, i);
+       }
+
+       return nodeList;
+}
+
 /*
  * Build locator information associated with the specified relation.
  */
index 1b547b21be28034276c2dc639ea525258fa7e6fb..c8bc3276fab39351efc2ad42b47dedba5d0b1132 100644 (file)
@@ -3285,6 +3285,12 @@ get_exec_connections(RemoteQueryState *planstate,
                coordlist = GetAllCoordNodes();
                co_conn_count = list_length(coordlist);
        }
+       else if (list_length(coordlist) == 0 &&
+                        exec_type == EXEC_ON_AVAILABLE_COORDS)
+       {
+               coordlist = GetAvailableCoordNodes();
+               co_conn_count = list_length(coordlist);
+       }
        else
        {
                if (exec_type == EXEC_ON_COORDS)
index 21c7e3fe1d6f58e836b099f6f18349bc8257269d..94fc8ee9356bcba19b1f08681fc59b18faaf76a2 100644 (file)
@@ -176,6 +176,7 @@ extern ExecNodes *GetRelationNodesByQuals(Oid reloid,
 extern bool IsTypeHashDistributable(Oid col_type);
 extern List *GetAllDataNodes(void);
 extern List *GetAllCoordNodes(void);
+extern List *GetAvailableCoordNodes(void);
 extern int GetAnyDataNode(Bitmapset *nodes);
 extern void RelationBuildLocator(Relation rel);
 extern void FreeRelationLocInfo(RelationLocInfo *relationLocInfo);
index d4223d2ab6425639c9d4129c943ba47240084389..af4569b21ae2122bd00c64abf92221b015b6f0c7 100644 (file)
@@ -58,6 +58,7 @@ typedef enum
        EXEC_ON_CURRENT,
        EXEC_ON_DATANODES,
        EXEC_ON_COORDS,
+       EXEC_ON_AVAILABLE_COORDS,
        EXEC_ON_ALL_NODES,
        EXEC_ON_NONE
 } RemoteQueryExecType;