12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
+ use std:: collections:: BTreeSet ;
15
16
use std:: collections:: HashSet ;
16
17
use std:: sync:: Arc ;
17
18
@@ -21,16 +22,22 @@ use databend_common_expression::DataField;
21
22
use databend_common_expression:: DataSchemaRef ;
22
23
use databend_common_expression:: DataSchemaRefExt ;
23
24
use databend_common_expression:: RemoteExpr ;
25
+ use databend_common_expression:: Scalar ;
24
26
use databend_common_functions:: BUILTIN_FUNCTIONS ;
25
27
26
28
use crate :: executor:: explain:: PlanStatsInfo ;
27
29
use crate :: executor:: physical_plan:: PhysicalPlan ;
28
30
use crate :: executor:: physical_plan_builder:: PhysicalPlanBuilder ;
31
+ use crate :: optimizer:: ir:: Matcher ;
29
32
use crate :: optimizer:: ir:: SExpr ;
33
+ use crate :: plans:: Filter ;
30
34
use crate :: plans:: FunctionCall ;
31
35
use crate :: plans:: ProjectSet ;
36
+ use crate :: plans:: RelOp ;
32
37
use crate :: plans:: RelOperator ;
33
38
use crate :: plans:: ScalarExpr ;
39
+ use crate :: plans:: ScalarItem ;
40
+ use crate :: plans:: Visitor ;
34
41
use crate :: ColumnSet ;
35
42
use crate :: IndexType ;
36
43
use crate :: TypeCheck ;
@@ -99,11 +106,7 @@ impl PhysicalPlanBuilder {
99
106
self . build ( s_expr. child ( 0 ) ?, required) . await
100
107
} else {
101
108
let child = s_expr. child ( 0 ) ?;
102
- let input = if let RelOperator :: ProjectSet ( project_set) = child. plan ( ) {
103
- let new_project_set =
104
- self . prune_flatten_columns ( eval_scalar, project_set, & required) ;
105
- let mut new_child = child. clone ( ) ;
106
- new_child. plan = Arc :: new ( new_project_set. into ( ) ) ;
109
+ let input = if let Some ( new_child) = self . try_eliminate_flatten_columns ( & used, child) ? {
107
110
self . build ( & new_child, required) . await ?
108
111
} else {
109
112
self . build ( child, required) . await ?
@@ -171,45 +174,136 @@ impl PhysicalPlanBuilder {
171
174
} ) )
172
175
}
173
176
177
+ fn try_eliminate_flatten_columns (
178
+ & mut self ,
179
+ scalar_items : & Vec < ScalarItem > ,
180
+ s_expr : & SExpr ,
181
+ ) -> Result < Option < SExpr > > {
182
+ // (1) ProjectSet
183
+ // \
184
+ // *
185
+ //
186
+ // (2) Filter
187
+ // \
188
+ // ProjectSet
189
+ // \
190
+ // *
191
+ let matchers = vec ! [
192
+ Matcher :: MatchOp {
193
+ op_type: RelOp :: ProjectSet ,
194
+ children: vec![ Matcher :: Leaf ] ,
195
+ } ,
196
+ Matcher :: MatchOp {
197
+ op_type: RelOp :: Filter ,
198
+ children: vec![ Matcher :: MatchOp {
199
+ op_type: RelOp :: ProjectSet ,
200
+ children: vec![ Matcher :: Leaf ] ,
201
+ } ] ,
202
+ } ,
203
+ ] ;
204
+
205
+ let mut matched = false ;
206
+ for matcher in matchers {
207
+ if matcher. matches ( s_expr) {
208
+ matched = true ;
209
+ break ;
210
+ }
211
+ }
212
+ if !matched {
213
+ return Ok ( None ) ;
214
+ }
215
+
216
+ if let RelOperator :: Filter ( filter) = s_expr. plan ( ) {
217
+ let child = s_expr. child ( 0 ) ?;
218
+ let project_set: ProjectSet = child. plan ( ) . clone ( ) . try_into ( ) ?;
219
+ let Some ( new_project_set) =
220
+ self . eliminate_flatten_columns ( scalar_items, Some ( filter) , & project_set)
221
+ else {
222
+ return Ok ( None ) ;
223
+ } ;
224
+ let mut new_child = child. clone ( ) ;
225
+ new_child. plan = Arc :: new ( new_project_set. into ( ) ) ;
226
+ let new_filter =
227
+ SExpr :: create_unary ( Arc :: new ( s_expr. plan ( ) . clone ( ) ) , Arc :: new ( new_child) ) ;
228
+ Ok ( Some ( new_filter) )
229
+ } else {
230
+ let project_set: ProjectSet = s_expr. plan ( ) . clone ( ) . try_into ( ) ?;
231
+ let Some ( new_project_set) =
232
+ self . eliminate_flatten_columns ( scalar_items, None , & project_set)
233
+ else {
234
+ return Ok ( None ) ;
235
+ } ;
236
+ let mut new_expr = s_expr. clone ( ) ;
237
+ new_expr. plan = Arc :: new ( new_project_set. into ( ) ) ;
238
+ Ok ( Some ( new_expr) )
239
+ }
240
+ }
241
+
174
242
// The flatten function returns a tuple, which contains 6 columns.
175
- // Only keep columns required by parent plan, other columns can be pruned
243
+ // Only keep columns required by parent plan, other columns can be eliminated
176
244
// to reduce the memory usage.
177
- fn prune_flatten_columns (
245
+ fn eliminate_flatten_columns (
178
246
& mut self ,
179
- eval_scalar : & crate :: plans:: EvalScalar ,
247
+ scalar_items : & Vec < ScalarItem > ,
248
+ filter : Option < & Filter > ,
180
249
project_set : & ProjectSet ,
181
- required : & ColumnSet ,
182
- ) -> ProjectSet {
250
+ ) -> Option < ProjectSet > {
251
+ let mut has_flatten = false ;
183
252
let mut project_set = project_set. clone ( ) ;
184
253
for srf_item in & mut project_set. srfs {
185
254
if let ScalarExpr :: FunctionCall ( srf_func) = & srf_item. scalar {
186
255
if srf_func. func_name == "flatten" {
187
- // Store the columns required by the parent plan in params.
188
- let mut params = Vec :: new ( ) ;
189
- for item in & eval_scalar. items {
190
- if !required. contains ( & item. index ) {
191
- continue ;
192
- }
193
- if let ScalarExpr :: FunctionCall ( func) = & item. scalar {
194
- if func. func_name == "get" && !func. arguments . is_empty ( ) {
195
- if let ScalarExpr :: BoundColumnRef ( column_ref) = & func. arguments [ 0 ] {
196
- if column_ref. column . index == srf_item. index {
197
- params. push ( func. params [ 0 ] . clone ( ) ) ;
198
- }
199
- }
200
- }
256
+ has_flatten = true ;
257
+ let mut visitor = FlattenColumnsVisitor {
258
+ params : BTreeSet :: new ( ) ,
259
+ column_index : srf_item. index ,
260
+ } ;
261
+ // Collect columns required by the parent plan in params.
262
+ for item in scalar_items {
263
+ visitor. visit ( & item. scalar ) . unwrap ( ) ;
264
+ }
265
+ if let Some ( filter) = filter {
266
+ for pred in & filter. predicates {
267
+ visitor. visit ( pred) . unwrap ( ) ;
201
268
}
202
269
}
203
270
204
271
srf_item. scalar = ScalarExpr :: FunctionCall ( FunctionCall {
205
272
span : srf_func. span ,
206
273
func_name : srf_func. func_name . clone ( ) ,
207
- params,
274
+ params : visitor . params . into_iter ( ) . collect :: < Vec < _ > > ( ) ,
208
275
arguments : srf_func. arguments . clone ( ) ,
209
276
} ) ;
210
277
}
211
278
}
212
279
}
213
- project_set
280
+ if has_flatten {
281
+ Some ( project_set)
282
+ } else {
283
+ None
284
+ }
285
+ }
286
+ }
287
+
288
+ struct FlattenColumnsVisitor {
289
+ params : BTreeSet < Scalar > ,
290
+ column_index : IndexType ,
291
+ }
292
+
293
+ impl < ' a > Visitor < ' a > for FlattenColumnsVisitor {
294
+ // Collect the params in get function which is used to extract the inner column of flatten function.
295
+ fn visit_function_call ( & mut self , func : & ' a FunctionCall ) -> Result < ( ) > {
296
+ if func. func_name == "get" && !func. arguments . is_empty ( ) {
297
+ if let ScalarExpr :: BoundColumnRef ( column_ref) = & func. arguments [ 0 ] {
298
+ if column_ref. column . index == self . column_index {
299
+ self . params . insert ( func. params [ 0 ] . clone ( ) ) ;
300
+ return Ok ( ( ) ) ;
301
+ }
302
+ }
303
+ }
304
+ for expr in & func. arguments {
305
+ self . visit ( expr) ?;
306
+ }
307
+ Ok ( ( ) )
214
308
}
215
309
}
0 commit comments