@@ -1945,6 +1945,9 @@ TVector<NJson::TJsonValue> RemoveRedundantNodes(NJson::TJsonValue& plan, const T
1945
1945
}
1946
1946
}
1947
1947
1948
+ if (!planMap.contains (" Node Type" )) {
1949
+ return {};
1950
+ }
1948
1951
const auto typeName = planMap.at (" Node Type" ).GetStringSafe ();
1949
1952
if (redundantNodes.contains (typeName) || typeName.find (" Precompute" ) != TString::npos) {
1950
1953
return children;
@@ -1953,167 +1956,235 @@ TVector<NJson::TJsonValue> RemoveRedundantNodes(NJson::TJsonValue& plan, const T
1953
1956
return {plan};
1954
1957
}
1955
1958
1956
- NJson::TJsonValue ReconstructQueryPlanRec (const NJson::TJsonValue& plan,
1957
- int operatorIndex,
1958
- const THashMap<int , NJson::TJsonValue>& planIndex,
1959
- const THashMap<TString, NJson::TJsonValue>& precomputes,
1960
- int & nodeCounter) {
1961
-
1962
- int currentNodeId = nodeCounter++;
1963
-
1964
- NJson::TJsonValue result;
1965
- result[" PlanNodeId" ] = currentNodeId;
1966
-
1967
- if (plan.GetMapSafe ().contains (" PlanNodeType" )) {
1968
- result[" PlanNodeType" ] = plan.GetMapSafe ().at (" PlanNodeType" ).GetStringSafe ();
1969
- }
1959
+ struct TQueryPlanReconstructor {
1960
+ TQueryPlanReconstructor (
1961
+ const THashMap<int , NJson::TJsonValue>& planIndex,
1962
+ const THashMap<TString, NJson::TJsonValue>& precomputes
1963
+ )
1964
+ : PlanIndex(planIndex)
1965
+ , Precomputes(precomputes)
1966
+ , NodeIDCounter(0 )
1967
+ , Budget(10'000 )
1968
+ {}
1970
1969
1971
- if (plan.GetMapSafe ().contains (" Stats" ) && operatorIndex==0 ) {
1972
- result[" Stats" ] = plan.GetMapSafe ().at (" Stats" );
1973
- }
1970
+ NJson::TJsonValue Reconstruct (
1971
+ const NJson::TJsonValue& plan,
1972
+ int operatorIndex
1973
+ ) {
1974
+ int currentNodeId = NodeIDCounter++;
1974
1975
1975
- if (!plan. GetMapSafe (). contains ( " Operators " )) {
1976
- NJson::TJsonValue planInputs ;
1976
+ NJson::TJsonValue result;
1977
+ result[ " PlanNodeId " ] = currentNodeId ;
1977
1978
1978
- result[" Node Type" ] = plan.GetMapSafe ().at (" Node Type" ).GetStringSafe ();
1979
+ if (--Budget <= 0 ) {
1980
+ YQL_CLOG (DEBUG, ProviderKqp) << " Can't build the plan - recursion depth has been exceeded!" ;
1981
+ return result;
1982
+ }
1979
1983
1980
- if (plan.GetMapSafe ().contains (" CTE Name" )) {
1981
- auto precompute = plan.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
1982
- if (precomputes.contains (precompute)) {
1983
- planInputs.AppendValue (ReconstructQueryPlanRec (precomputes.at (precompute), 0 , planIndex, precomputes, nodeCounter));
1984
- }
1984
+ if (plan.GetMapSafe ().contains (" PlanNodeType" )) {
1985
+ result[" PlanNodeType" ] = plan.GetMapSafe ().at (" PlanNodeType" ).GetStringSafe ();
1985
1986
}
1986
1987
1987
- if (!plan.GetMapSafe ().contains (" Plans" )) {
1988
- result[" Plans" ] = planInputs;
1989
- return result;
1988
+ if (plan.GetMapSafe ().contains (" Stats" ) && operatorIndex==0 ) {
1989
+ result[" Stats" ] = plan.GetMapSafe ().at (" Stats" );
1990
1990
}
1991
1991
1992
- if (plan.GetMapSafe ().at (" Node Type" ).GetStringSafe () == " TableLookup" ) {
1992
+ if (plan.GetMapSafe ().at (" Node Type" ) == " TableLookupJoin" && plan.GetMapSafe ().contains (" Table" )) {
1993
+ result[" Node Type" ] = " LookupJoin" ;
1993
1994
NJson::TJsonValue newOps;
1994
1995
NJson::TJsonValue op;
1995
1996
1996
- op[" Name" ] = " TableLookup" ;
1997
- op[" Columns" ] = plan.GetMapSafe ().at (" Columns" );
1997
+ op[" Name" ] = " LookupJoin" ;
1998
1998
op[" LookupKeyColumns" ] = plan.GetMapSafe ().at (" LookupKeyColumns" );
1999
- op[" Table" ] = plan.GetMapSafe ().at (" Table" );
1999
+
2000
+ newOps.AppendValue (std::move (op));
2001
+ result[" Operators" ] = std::move (newOps);
2002
+
2003
+ NJson::TJsonValue newPlans;
2004
+
2005
+ NJson::TJsonValue lookupPlan;
2006
+ lookupPlan[" Node Type" ] = " TableLookup" ;
2007
+ lookupPlan[" PlanNodeType" ] = " TableLookup" ;
2008
+
2009
+ NJson::TJsonValue lookupOps;
2010
+ NJson::TJsonValue lookupOp;
2011
+
2012
+ lookupOp[" Name" ] = " TableLookup" ;
2013
+ lookupOp[" Columns" ] = plan.GetMapSafe ().at (" Columns" );
2014
+ lookupOp[" LookupKeyColumns" ] = plan.GetMapSafe ().at (" LookupKeyColumns" );
2015
+ lookupOp[" Table" ] = plan.GetMapSafe ().at (" Table" );
2000
2016
2001
2017
if (plan.GetMapSafe ().contains (" E-Cost" )) {
2002
- op [" E-Cost" ] = plan.GetMapSafe ().at (" E-Cost" );
2003
- }
2018
+ lookupOp [" E-Cost" ] = plan.GetMapSafe ().at (" E-Cost" );
2019
+ }
2004
2020
if (plan.GetMapSafe ().contains (" E-Rows" )) {
2005
- op [" E-Rows" ] = plan.GetMapSafe ().at (" E-Rows" );
2021
+ lookupOp [" E-Rows" ] = plan.GetMapSafe ().at (" E-Rows" );
2006
2022
}
2007
2023
if (plan.GetMapSafe ().contains (" E-Size" )) {
2008
- op [" E-Size" ] = plan.GetMapSafe ().at (" E-Size" );
2024
+ lookupOp [" E-Size" ] = plan.GetMapSafe ().at (" E-Size" );
2009
2025
}
2010
2026
2011
- newOps.AppendValue (op);
2027
+ lookupOps.AppendValue (std::move (lookupOp));
2028
+ lookupPlan[" Operators" ] = std::move (lookupOps);
2029
+
2030
+ newPlans.AppendValue (Reconstruct (plan.GetMapSafe ().at (" Plans" ).GetArraySafe ()[0 ], 0 ));
2031
+
2032
+ newPlans.AppendValue (std::move (lookupPlan));
2033
+
2034
+ result[" Plans" ] = std::move (newPlans);
2012
2035
2013
- result[" Operators" ] = newOps;
2014
2036
return result;
2015
2037
}
2016
2038
2017
- for (auto p : plan.GetMapSafe ().at (" Plans" ).GetArraySafe ()) {
2018
- if (!p.GetMapSafe ().contains (" Operators" ) && p.GetMapSafe ().contains (" CTE Name" )) {
2019
- auto precompute = p.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
2020
- if (precomputes.contains (precompute)) {
2021
- planInputs.AppendValue (ReconstructQueryPlanRec (precomputes.at (precompute), 0 , planIndex, precomputes, nodeCounter));
2039
+ if (!plan.GetMapSafe ().contains (" Operators" )) {
2040
+ NJson::TJsonValue planInputs;
2041
+
2042
+ result[" Node Type" ] = plan.GetMapSafe ().at (" Node Type" ).GetStringSafe ();
2043
+
2044
+ if (plan.GetMapSafe ().contains (" CTE Name" )) {
2045
+ auto precompute = plan.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
2046
+ if (Precomputes.contains (precompute)) {
2047
+ planInputs.AppendValue (Reconstruct (Precomputes.at (precompute), 0 ));
2022
2048
}
2023
- } else if (p.GetMapSafe ().at (" Node Type" ).GetStringSafe ().find (" Precompute" ) == TString::npos) {
2024
- planInputs.AppendValue (ReconstructQueryPlanRec (p, 0 , planIndex, precomputes, nodeCounter));
2025
2049
}
2026
- }
2027
- result[" Plans" ] = planInputs;
2028
- return result;
2029
- }
2030
2050
2031
- if (plan.GetMapSafe ().contains (" CTE Name" ) && plan.GetMapSafe ().at (" Node Type" ).GetStringSafe () == " ConstantExpr" ) {
2032
- auto precompute = plan.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
2033
- if (!precomputes.contains (precompute)) {
2034
- result[" Node Type" ] = plan.GetMapSafe ().at (" Node Type" );
2051
+ if (!plan.GetMapSafe ().contains (" Plans" )) {
2052
+ result[" Plans" ] = std::move (planInputs);
2053
+ return result;
2054
+ }
2055
+
2056
+ if (plan.GetMapSafe ().at (" Node Type" ).GetStringSafe () == " TableLookup" ) {
2057
+ NJson::TJsonValue newOps;
2058
+ NJson::TJsonValue op;
2059
+
2060
+ op[" Name" ] = " TableLookup" ;
2061
+ op[" Columns" ] = plan.GetMapSafe ().at (" Columns" );
2062
+ op[" LookupKeyColumns" ] = plan.GetMapSafe ().at (" LookupKeyColumns" );
2063
+ op[" Table" ] = plan.GetMapSafe ().at (" Table" );
2064
+
2065
+ if (plan.GetMapSafe ().contains (" E-Cost" )) {
2066
+ op[" E-Cost" ] = plan.GetMapSafe ().at (" E-Cost" );
2067
+ }
2068
+ if (plan.GetMapSafe ().contains (" E-Rows" )) {
2069
+ op[" E-Rows" ] = plan.GetMapSafe ().at (" E-Rows" );
2070
+ }
2071
+ if (plan.GetMapSafe ().contains (" E-Size" )) {
2072
+ op[" E-Size" ] = plan.GetMapSafe ().at (" E-Size" );
2073
+ }
2074
+
2075
+ newOps.AppendValue (std::move (op));
2076
+
2077
+ result[" Operators" ] = std::move (newOps);
2078
+ return result;
2079
+ }
2080
+
2081
+ for (auto p : plan.GetMapSafe ().at (" Plans" ).GetArraySafe ()) {
2082
+ if (!p.GetMapSafe ().contains (" Operators" ) && p.GetMapSafe ().contains (" CTE Name" )) {
2083
+ auto precompute = p.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
2084
+ if (Precomputes.contains (precompute)) {
2085
+ planInputs.AppendValue (Reconstruct (Precomputes.at (precompute), 0 ));
2086
+ }
2087
+ } else if (p.GetMapSafe ().at (" Node Type" ).GetStringSafe ().find (" Precompute" ) == TString::npos) {
2088
+ planInputs.AppendValue (Reconstruct (p, 0 ));
2089
+ }
2090
+ }
2091
+ result[" Plans" ] = planInputs;
2035
2092
return result;
2036
2093
}
2037
2094
2038
- return ReconstructQueryPlanRec (precomputes.at (precompute), 0 , planIndex, precomputes, nodeCounter);
2039
- }
2095
+ if (plan.GetMapSafe ().contains (" CTE Name" ) && plan.GetMapSafe ().at (" Node Type" ).GetStringSafe () == " ConstantExpr" ) {
2096
+ auto precompute = plan.GetMapSafe ().at (" CTE Name" ).GetStringSafe ();
2097
+ if (!Precomputes.contains (precompute)) {
2098
+ result[" Node Type" ] = plan.GetMapSafe ().at (" Node Type" );
2099
+ return result;
2100
+ }
2040
2101
2041
- auto ops = plan. GetMapSafe () .at (" Operators " ). GetArraySafe ( );
2042
- auto op = ops[operatorIndex];
2102
+ return Reconstruct (Precomputes .at (precompute), 0 );
2103
+ }
2043
2104
2044
- TVector<NJson::TJsonValue> planInputs;
2105
+ auto ops = plan.GetMapSafe ().at (" Operators" ).GetArraySafe ();
2106
+ auto op = ops[operatorIndex];
2045
2107
2046
- auto opName = op. GetMapSafe (). at ( " Name " ). GetStringSafe () ;
2108
+ TVector<NJson::TJsonValue> planInputs ;
2047
2109
2048
- THashSet<ui32> processedExternalOperators;
2049
- THashSet<ui32> processedInternalOperators;
2050
- for (auto opInput : op.GetMapSafe ().at (" Inputs" ).GetArraySafe ()) {
2110
+ auto opName = op.GetMapSafe ().at (" Name" ).GetStringSafe ();
2051
2111
2052
- if (opInput.GetMapSafe ().contains (" ExternalPlanNodeId" )) {
2053
- auto inputPlanKey = opInput.GetMapSafe ().at (" ExternalPlanNodeId" ).GetIntegerSafe ();
2112
+ THashSet<ui32> processedExternalOperators;
2113
+ THashSet<ui32> processedInternalOperators;
2114
+ for (auto opInput : op.GetMapSafe ().at (" Inputs" ).GetArraySafe ()) {
2054
2115
2055
- if (processedExternalOperators.contains (inputPlanKey)) {
2056
- continue ;
2057
- }
2058
- processedExternalOperators.insert (inputPlanKey);
2116
+ if (opInput.GetMapSafe ().contains (" ExternalPlanNodeId" )) {
2117
+ auto inputPlanKey = opInput.GetMapSafe ().at (" ExternalPlanNodeId" ).GetIntegerSafe ();
2059
2118
2060
- auto inputPlan = planIndex. at (inputPlanKey);
2061
- planInputs. push_back ( ReconstructQueryPlanRec (inputPlan, 0 , planIndex, precomputes, nodeCounter)) ;
2062
- } else if (opInput. GetMapSafe (). contains ( " InternalOperatorId " )) {
2063
- auto inputPlanId = opInput. GetMapSafe (). at ( " InternalOperatorId " ). GetIntegerSafe ( );
2119
+ if (processedExternalOperators. contains (inputPlanKey)) {
2120
+ continue ;
2121
+ }
2122
+ processedExternalOperators. insert (inputPlanKey );
2064
2123
2065
- if (processedInternalOperators. contains (inputPlanId)) {
2066
- continue ;
2067
- }
2068
- processedInternalOperators. insert (inputPlanId );
2124
+ auto inputPlan = PlanIndex. at (inputPlanKey);
2125
+ planInputs. push_back ( Reconstruct (inputPlan, 0 ) ) ;
2126
+ } else if (opInput. GetMapSafe (). contains ( " InternalOperatorId " )) {
2127
+ auto inputPlanId = opInput. GetMapSafe (). at ( " InternalOperatorId " ). GetIntegerSafe ( );
2069
2128
2070
- planInputs.push_back ( ReconstructQueryPlanRec (plan, inputPlanId, planIndex, precomputes, nodeCounter));
2129
+ if (processedInternalOperators.contains (inputPlanId)) {
2130
+ continue ;
2131
+ }
2132
+ processedInternalOperators.insert (inputPlanId);
2133
+
2134
+ planInputs.push_back ( Reconstruct (plan, inputPlanId) );
2135
+ }
2071
2136
}
2072
- }
2073
2137
2074
- if (op.GetMapSafe ().contains (" Inputs" )) {
2075
- op.GetMapSafe ().erase (" Inputs" );
2076
- }
2138
+ if (op.GetMapSafe ().contains (" Inputs" )) {
2139
+ op.GetMapSafe ().erase (" Inputs" );
2140
+ }
2077
2141
2078
- if (op.GetMapSafe ().contains (" Input" )
2079
- || op.GetMapSafe ().contains (" ToFlow" )
2080
- || op.GetMapSafe ().contains (" Member" )
2081
- || op.GetMapSafe ().contains (" AssumeSorted" )
2082
- || op.GetMapSafe ().contains (" Iterator" )) {
2142
+ if (op.GetMapSafe ().contains (" Input" )
2143
+ || op.GetMapSafe ().contains (" ToFlow" )
2144
+ || op.GetMapSafe ().contains (" Member" )
2145
+ || op.GetMapSafe ().contains (" AssumeSorted" )
2146
+ || op.GetMapSafe ().contains (" Iterator" )) {
2083
2147
2084
- TString maybePrecompute = " " ;
2085
- if (op.GetMapSafe ().contains (" Input" )) {
2086
- maybePrecompute = op.GetMapSafe ().at (" Input" ).GetStringSafe ();
2087
- } else if (op.GetMapSafe ().contains (" ToFlow" )) {
2088
- maybePrecompute = op.GetMapSafe ().at (" ToFlow" ).GetStringSafe ();
2089
- } else if (op.GetMapSafe ().contains (" Member" )) {
2090
- maybePrecompute = op.GetMapSafe ().at (" Member" ).GetStringSafe ();
2091
- } else if (op.GetMapSafe ().contains (" AssumeSorted" )) {
2092
- maybePrecompute = op.GetMapSafe ().at (" AssumeSorted" ).GetStringSafe ();
2093
- } else if (op.GetMapSafe ().contains (" Iterator" )) {
2094
- maybePrecompute = op.GetMapSafe ().at (" Iterator" ).GetStringSafe ();
2095
- }
2148
+ TString maybePrecompute = " " ;
2149
+ if (op.GetMapSafe ().contains (" Input" )) {
2150
+ maybePrecompute = op.GetMapSafe ().at (" Input" ).GetStringSafe ();
2151
+ } else if (op.GetMapSafe ().contains (" ToFlow" )) {
2152
+ maybePrecompute = op.GetMapSafe ().at (" ToFlow" ).GetStringSafe ();
2153
+ } else if (op.GetMapSafe ().contains (" Member" )) {
2154
+ maybePrecompute = op.GetMapSafe ().at (" Member" ).GetStringSafe ();
2155
+ } else if (op.GetMapSafe ().contains (" AssumeSorted" )) {
2156
+ maybePrecompute = op.GetMapSafe ().at (" AssumeSorted" ).GetStringSafe ();
2157
+ } else if (op.GetMapSafe ().contains (" Iterator" )) {
2158
+ maybePrecompute = op.GetMapSafe ().at (" Iterator" ).GetStringSafe ();
2159
+ }
2096
2160
2097
- if (precomputes.contains (maybePrecompute) && planInputs.empty ()) {
2098
- planInputs.push_back (ReconstructQueryPlanRec (precomputes.at (maybePrecompute), 0 , planIndex, precomputes, nodeCounter));
2161
+ if (Precomputes.contains (maybePrecompute) && planInputs.empty ()) {
2162
+ planInputs.push_back (Reconstruct (Precomputes.at (maybePrecompute), 0 ));
2163
+ }
2099
2164
}
2100
- }
2101
2165
2102
- result[" Node Type" ] = opName;
2103
- NJson::TJsonValue newOps;
2104
- newOps.AppendValue (op );
2105
- result[" Operators" ] = newOps;
2166
+ result[" Node Type" ] = std::move ( opName) ;
2167
+ NJson::TJsonValue newOps;
2168
+ newOps.AppendValue (std::move (op) );
2169
+ result[" Operators" ] = std::move ( newOps) ;
2106
2170
2107
- if (planInputs.size ()){
2108
- NJson::TJsonValue plans;
2109
- for ( auto i : planInputs) {
2110
- plans.AppendValue (i);
2171
+ if (!planInputs.empty ()){
2172
+ NJson::TJsonValue plans;
2173
+ for (auto && i : planInputs) {
2174
+ plans.AppendValue (std::move (i));
2175
+ }
2176
+ result[" Plans" ] = std::move (plans);
2111
2177
}
2112
- result[" Plans" ] = plans;
2178
+
2179
+ return result;
2113
2180
}
2114
2181
2115
- return result;
2116
- }
2182
+ private:
2183
+ const THashMap<int , NJson::TJsonValue>& PlanIndex;
2184
+ const THashMap<TString, NJson::TJsonValue>& Precomputes;
2185
+ ui32 NodeIDCounter;
2186
+ i32 Budget; // Prevent bugs with inf recursion
2187
+ };
2117
2188
2118
2189
double ComputeCpuTimes (NJson::TJsonValue& plan) {
2119
2190
double currCpuTime = 0 ;
@@ -2209,8 +2280,7 @@ NJson::TJsonValue SimplifyQueryPlan(NJson::TJsonValue& plan) {
2209
2280
2210
2281
BuildPlanIndex (plan, planIndex, precomputes);
2211
2282
2212
- int nodeCounter = 0 ;
2213
- plan = ReconstructQueryPlanRec (plan, 0 , planIndex, precomputes, nodeCounter);
2283
+ plan = TQueryPlanReconstructor (planIndex, precomputes).Reconstruct (plan, 0 );
2214
2284
2215
2285
RemoveRedundantNodes (plan, redundantNodes);
2216
2286
ComputeCpuTimes (plan);
0 commit comments