@@ -311,277 +311,3 @@ impl Operator for UnionAll {
311311 Ok ( children_required)
312312 }
313313}
314-
315- #[ cfg( test) ]
316- mod tests {
317- use std:: collections:: HashMap ;
318-
319- use databend_common_expression:: stat_distribution:: NdvEstimate ;
320- use databend_common_expression:: stat_distribution:: StatCount ;
321- use databend_common_expression:: types:: ArgType ;
322- use databend_common_expression:: types:: DataType ;
323- use databend_common_expression:: types:: Int32Type ;
324- use databend_common_expression:: types:: Int64Type ;
325- use databend_common_statistics:: Datum ;
326- use databend_common_statistics:: HistogramBuilder ;
327-
328- use super :: * ;
329- use crate :: ColumnBindingBuilder ;
330- use crate :: Visibility ;
331- use crate :: plans:: BoundColumnRef ;
332- use crate :: plans:: CastExpr ;
333- use crate :: plans:: Join ;
334- use crate :: plans:: JoinEquiCondition ;
335- use crate :: plans:: JoinType ;
336-
337- fn stat_info ( cardinality : u64 , column : Option < ( Symbol , ColumnStat ) > ) -> Arc < StatInfo > {
338- Arc :: new ( StatInfo {
339- cardinality : cardinality as f64 ,
340- statistics : Statistics {
341- precise_cardinality : Some ( cardinality) ,
342- column_stats : column. into_iter ( ) . collect :: < HashMap < _ , _ > > ( ) ,
343- top_n : Default :: default ( ) ,
344- count_min_sketch : Default :: default ( ) ,
345- } ,
346- } )
347- }
348-
349- fn column_stat ( min : i64 , max : i64 , ndv : f64 , null_count : u64 ) -> ColumnStat {
350- ColumnStat {
351- min : Datum :: Int ( min) ,
352- max : Datum :: Int ( max) ,
353- ndv : NdvEstimate :: exact ( ndv) ,
354- null_count : StatCount :: exact ( null_count) ,
355- histogram : None ,
356- }
357- }
358-
359- fn typed_column ( index : Symbol , data_type : DataType ) -> ScalarExpr {
360- ScalarExpr :: BoundColumnRef ( BoundColumnRef {
361- span : None ,
362- column : ColumnBindingBuilder :: new (
363- format ! ( "c{}" , index. as_usize( ) ) ,
364- index,
365- Box :: new ( data_type) ,
366- Visibility :: Visible ,
367- )
368- . build ( ) ,
369- } )
370- }
371-
372- #[ test]
373- fn test_union_stats_merge_and_remap_output_column ( ) -> Result < ( ) > {
374- let left = Symbol :: new ( 1 ) ;
375- let right = Symbol :: new ( 2 ) ;
376- let output = Symbol :: new ( 10 ) ;
377- let union = UnionAll {
378- left_outputs : vec ! [ ( left, None ) ] ,
379- right_outputs : vec ! [ ( right, None ) ] ,
380- cte_scan_names : vec ! [ ] ,
381- logical_recursive_cte_id : None ,
382- output_indexes : vec ! [ output] ,
383- } ;
384- let stats = union. derive_union_stats (
385- stat_info ( 10 , Some ( ( left, column_stat ( 1 , 3 , 3.0 , 1 ) ) ) ) ,
386- stat_info ( 20 , Some ( ( right, column_stat ( 4 , 8 , 5.0 , 2 ) ) ) ) ,
387- ) ?;
388-
389- assert_eq ! ( stats. cardinality, 30.0 ) ;
390- assert_eq ! ( stats. statistics. precise_cardinality, Some ( 30 ) ) ;
391- assert ! ( !stats. statistics. column_stats. contains_key( & left) ) ;
392- assert ! ( !stats. statistics. column_stats. contains_key( & right) ) ;
393- let output_stat = & stats. statistics . column_stats [ & output] ;
394- assert_eq ! ( output_stat, & ColumnStat {
395- min: Datum :: Int ( 1 ) ,
396- max: Datum :: Int ( 8 ) ,
397- ndv: NdvEstimate :: new( 5.0 , 8.0 ) ,
398- null_count: StatCount :: exact( 3 ) ,
399- histogram: None ,
400- } ) ;
401- Ok ( ( ) )
402- }
403-
404- #[ test]
405- fn test_union_stats_apply_lossless_coercion_cast ( ) -> Result < ( ) > {
406- let left = Symbol :: new ( 1 ) ;
407- let right = Symbol :: new ( 2 ) ;
408- let output = Symbol :: new ( 10 ) ;
409- let union = UnionAll {
410- left_outputs : vec ! [ (
411- left,
412- Some ( ScalarExpr :: CastExpr ( CastExpr {
413- span: None ,
414- is_try: false ,
415- argument: Box :: new( typed_column( left, Int32Type :: data_type( ) . wrap_nullable( ) ) ) ,
416- target_type: Box :: new( Int64Type :: data_type( ) . wrap_nullable( ) ) ,
417- } ) ) ,
418- ) ] ,
419- right_outputs : vec ! [ ( right, None ) ] ,
420- cte_scan_names : vec ! [ ] ,
421- logical_recursive_cte_id : None ,
422- output_indexes : vec ! [ output] ,
423- } ;
424-
425- let stats = union. derive_union_stats (
426- stat_info ( 10 , Some ( ( left, column_stat ( 1 , 3 , 3.0 , 1 ) ) ) ) ,
427- stat_info ( 20 , Some ( ( right, column_stat ( 4 , 8 , 5.0 , 2 ) ) ) ) ,
428- ) ?;
429-
430- let output_stat = & stats. statistics . column_stats [ & output] ;
431- assert_eq ! ( output_stat, & ColumnStat {
432- min: Datum :: Int ( 1 ) ,
433- max: Datum :: Int ( 8 ) ,
434- ndv: NdvEstimate :: new( 5.0 , 8.0 ) ,
435- null_count: StatCount :: exact( 3 ) ,
436- histogram: None ,
437- } ) ;
438- Ok ( ( ) )
439- }
440-
441- #[ test]
442- fn test_union_stats_do_not_keep_partial_stats_from_nonempty_branch ( ) -> Result < ( ) > {
443- let left = Symbol :: new ( 1 ) ;
444- let right = Symbol :: new ( 2 ) ;
445- let output = Symbol :: new ( 10 ) ;
446- let union = UnionAll {
447- left_outputs : vec ! [ ( left, None ) ] ,
448- right_outputs : vec ! [ ( right, None ) ] ,
449- cte_scan_names : vec ! [ ] ,
450- logical_recursive_cte_id : None ,
451- output_indexes : vec ! [ output] ,
452- } ;
453-
454- let stats = union. derive_union_stats (
455- stat_info ( 10 , Some ( ( left, column_stat ( 1 , 3 , 3.0 , 0 ) ) ) ) ,
456- stat_info ( 20 , None ) ,
457- ) ?;
458- assert ! ( !stats. statistics. column_stats. contains_key( & output) ) ;
459-
460- let stats = union. derive_union_stats (
461- stat_info ( 10 , Some ( ( left, column_stat ( 1 , 3 , 3.0 , 0 ) ) ) ) ,
462- stat_info ( 0 , None ) ,
463- ) ?;
464- assert_eq ! (
465- stats. statistics. column_stats[ & output] . ndv,
466- NdvEstimate :: exact( 3.0 )
467- ) ;
468- Ok ( ( ) )
469- }
470-
471- #[ test]
472- fn test_union_ndv_fallback_preserves_known_side ( ) -> Result < ( ) > {
473- let left = Symbol :: new ( 1 ) ;
474- let right = Symbol :: new ( 2 ) ;
475- let output = Symbol :: new ( 10 ) ;
476- let mut left_stat = column_stat ( 1 , 3 , 3.0 , 0 ) ;
477- left_stat. ndv = NdvEstimate :: upper_bound ( 3.0 ) ;
478-
479- let union = UnionAll {
480- left_outputs : vec ! [ ( left, None ) ] ,
481- right_outputs : vec ! [ ( right, None ) ] ,
482- cte_scan_names : vec ! [ ] ,
483- logical_recursive_cte_id : None ,
484- output_indexes : vec ! [ output] ,
485- } ;
486- let stats = union. derive_union_stats (
487- stat_info ( 10 , Some ( ( left, left_stat) ) ) ,
488- stat_info ( 20 , Some ( ( right, column_stat ( 2 , 8 , 5.0 , 0 ) ) ) ) ,
489- ) ?;
490-
491- assert_eq ! (
492- stats. statistics. column_stats[ & output] . ndv,
493- NdvEstimate :: new( 5.0 , 8.0 )
494- ) ;
495- Ok ( ( ) )
496- }
497-
498- #[ test]
499- fn test_union_output_stats_are_consumed_by_join_estimation ( ) -> Result < ( ) > {
500- let left = Symbol :: new ( 1 ) ;
501- let right = Symbol :: new ( 2 ) ;
502- let output = Symbol :: new ( 10 ) ;
503- let join_key = Symbol :: new ( 20 ) ;
504- let union = UnionAll {
505- left_outputs : vec ! [ ( left, None ) ] ,
506- right_outputs : vec ! [ ( right, None ) ] ,
507- cte_scan_names : vec ! [ ] ,
508- logical_recursive_cte_id : None ,
509- output_indexes : vec ! [ output] ,
510- } ;
511- let union_stats = union. derive_union_stats (
512- stat_info ( 10 , Some ( ( left, column_stat ( 1 , 3 , 3.0 , 0 ) ) ) ) ,
513- stat_info ( 20 , Some ( ( right, column_stat ( 2 , 8 , 5.0 , 0 ) ) ) ) ,
514- ) ?;
515- assert_eq ! (
516- union_stats. statistics. column_stats[ & output] . ndv,
517- NdvEstimate :: new( 5.0 , 8.0 )
518- ) ;
519- let join = Join {
520- equi_conditions : vec ! [ JoinEquiCondition :: new(
521- typed_column( output, Int64Type :: data_type( ) ) ,
522- typed_column( join_key, Int64Type :: data_type( ) ) ,
523- false ,
524- ) ] ,
525- join_type : JoinType :: Inner ,
526- ..Default :: default ( )
527- } ;
528-
529- let stats = join. derive_join_stats (
530- union_stats,
531- stat_info ( 100 , Some ( ( join_key, column_stat ( 1 , 10 , 10.0 , 0 ) ) ) ) ,
532- ) ?;
533-
534- // 30 * 100 / max(union estimated NDV 5, right NDV 10), rather than 30 * 100.
535- assert_eq ! ( stats. cardinality, 300.0 ) ;
536- Ok ( ( ) )
537- }
538-
539- #[ test]
540- fn test_union_ndv_uses_histogram_intersection ( ) -> Result < ( ) > {
541- let left = Symbol :: new ( 1 ) ;
542- let right = Symbol :: new ( 2 ) ;
543- let output = Symbol :: new ( 10 ) ;
544- let mut left_histogram =
545- HistogramBuilder :: from_ndv ( 10 , 100 , Some ( ( Datum :: Int ( 0 ) , Datum :: Int ( 9 ) ) ) , 2 )
546- . expect ( "left histogram should be valid" ) ;
547- let mut right_histogram =
548- HistogramBuilder :: from_ndv ( 10 , 100 , Some ( ( Datum :: Int ( 5 ) , Datum :: Int ( 14 ) ) ) , 2 )
549- . expect ( "right histogram should be valid" ) ;
550- left_histogram. scale_counts ( 0.25 ) ;
551- right_histogram. scale_counts ( 0.5 ) ;
552- let left_ndv = left_histogram. ndv ( ) ;
553- let right_ndv = right_histogram. ndv ( ) ;
554- let intersection_ndv = left_histogram
555- . estimate_join_numeric_compatible ( & right_histogram) ?
556- . expect ( "integer histograms should be compatible" )
557- . ndv
558- . expected
559- . expect ( "histogram intersection should have an expected NDV" ) ;
560- let mut left_stat = column_stat ( 0 , 9 , 10.0 , 0 ) ;
561- left_stat. ndv = left_ndv;
562- left_stat. histogram = Some ( left_histogram) ;
563- let mut right_stat = column_stat ( 5 , 14 , 10.0 , 0 ) ;
564- right_stat. ndv = right_ndv;
565- right_stat. histogram = Some ( right_histogram) ;
566-
567- let union = UnionAll {
568- left_outputs : vec ! [ ( left, None ) ] ,
569- right_outputs : vec ! [ ( right, None ) ] ,
570- cte_scan_names : vec ! [ ] ,
571- logical_recursive_cte_id : None ,
572- output_indexes : vec ! [ output] ,
573- } ;
574- let stats = union. derive_union_stats (
575- stat_info ( 25 , Some ( ( left, left_stat) ) ) ,
576- stat_info ( 50 , Some ( ( right, right_stat) ) ) ,
577- ) ?;
578-
579- let expected = stats. statistics . column_stats [ & output] . ndv . expected . unwrap ( ) ;
580- let expected_from_intersection =
581- left_ndv. expected . unwrap ( ) + right_ndv. expected . unwrap ( ) - intersection_ndv;
582- assert ! ( ( expected - expected_from_intersection) . abs( ) < 1e-9 ) ;
583- assert ! ( expected > left_ndv. expected. unwrap( ) . max( right_ndv. expected. unwrap( ) ) ) ;
584- assert ! ( expected < left_ndv. expected. unwrap( ) + right_ndv. expected. unwrap( ) ) ;
585- Ok ( ( ) )
586- }
587- }
0 commit comments