@@ -634,6 +634,308 @@ fn criterion_benchmark(c: &mut Criterion) {
634634 c. bench_function ( "with_param_values_many_columns" , |b| {
635635 benchmark_with_param_values_many_columns ( & ctx, & rt, b) ;
636636 } ) ;
637+
638+ // ==========================================================================
639+ // Optimizer-focused benchmarks
640+ // These benchmarks are designed to stress the logical optimizer with
641+ // varying plan sizes, expression counts, and node type distributions.
642+ // ==========================================================================
643+
644+ // --- Deep join trees (many plan nodes, few expressions) ---
645+ // Tests optimizer traversal cost as plan node count grows.
646+ // Each join adds ~3 nodes (Join, TableScan, CrossJoin/Filter).
647+
648+ // Register additional tables for join benchmarks
649+ for i in 3 ..=16 {
650+ ctx. register_table (
651+ & format ! ( "j{i}" ) ,
652+ create_table_provider ( "x" , 10 ) ,
653+ )
654+ . unwrap ( ) ;
655+ }
656+
657+ c. bench_function ( "logical_join_chain_4" , |b| {
658+ b. iter ( || {
659+ logical_plan (
660+ & ctx,
661+ & rt,
662+ "SELECT j3.x0 FROM j3 \
663+ JOIN j4 ON j3.x0 = j4.x0 \
664+ JOIN j5 ON j4.x0 = j5.x0 \
665+ JOIN j6 ON j5.x0 = j6.x0",
666+ )
667+ } )
668+ } ) ;
669+
670+ c. bench_function ( "logical_join_chain_8" , |b| {
671+ b. iter ( || {
672+ logical_plan (
673+ & ctx,
674+ & rt,
675+ "SELECT j3.x0 FROM j3 \
676+ JOIN j4 ON j3.x0 = j4.x0 \
677+ JOIN j5 ON j4.x0 = j5.x0 \
678+ JOIN j6 ON j5.x0 = j6.x0 \
679+ JOIN j7 ON j6.x0 = j7.x0 \
680+ JOIN j8 ON j7.x0 = j8.x0 \
681+ JOIN j9 ON j8.x0 = j9.x0 \
682+ JOIN j10 ON j9.x0 = j10.x0",
683+ )
684+ } )
685+ } ) ;
686+
687+ c. bench_function ( "logical_join_chain_16" , |b| {
688+ b. iter ( || {
689+ logical_plan (
690+ & ctx,
691+ & rt,
692+ "SELECT j3.x0 FROM j3 \
693+ JOIN j4 ON j3.x0 = j4.x0 \
694+ JOIN j5 ON j4.x0 = j5.x0 \
695+ JOIN j6 ON j5.x0 = j6.x0 \
696+ JOIN j7 ON j6.x0 = j7.x0 \
697+ JOIN j8 ON j7.x0 = j8.x0 \
698+ JOIN j9 ON j8.x0 = j9.x0 \
699+ JOIN j10 ON j9.x0 = j10.x0 \
700+ JOIN j11 ON j10.x0 = j11.x0 \
701+ JOIN j12 ON j11.x0 = j12.x0 \
702+ JOIN j13 ON j12.x0 = j13.x0 \
703+ JOIN j14 ON j13.x0 = j14.x0 \
704+ JOIN j15 ON j14.x0 = j15.x0 \
705+ JOIN j16 ON j15.x0 = j16.x0 \
706+ JOIN j3 AS j3b ON j16.x0 = j3b.x0 \
707+ JOIN j4 AS j4b ON j3b.x0 = j4b.x0",
708+ )
709+ } )
710+ } ) ;
711+
712+ // --- Wide expressions (few plan nodes, many expressions) ---
713+ // Tests expression processing overhead in optimizer rules like
714+ // SimplifyExpressions, CommonSubexprEliminate, OptimizeProjections.
715+
716+ // Many WHERE clauses (filter expressions)
717+ {
718+ let predicates: Vec < String > = ( 0 ..50 )
719+ . map ( |i| format ! ( "a{i} > 0" ) )
720+ . collect ( ) ;
721+ let query = format ! (
722+ "SELECT a0 FROM t1 WHERE {}" ,
723+ predicates. join( " AND " )
724+ ) ;
725+ c. bench_function ( "logical_wide_filter_50_predicates" , |b| {
726+ b. iter ( || logical_plan ( & ctx, & rt, & query) )
727+ } ) ;
728+ }
729+
730+ {
731+ let predicates: Vec < String > = ( 0 ..200 )
732+ . map ( |i| format ! ( "a{i} > 0" ) )
733+ . collect ( ) ;
734+ let query = format ! (
735+ "SELECT a0 FROM t1 WHERE {}" ,
736+ predicates. join( " AND " )
737+ ) ;
738+ c. bench_function ( "logical_wide_filter_200_predicates" , |b| {
739+ b. iter ( || logical_plan ( & ctx, & rt, & query) )
740+ } ) ;
741+ }
742+
743+ // Many aggregate expressions
744+ {
745+ let aggs: Vec < String > = ( 0 ..50 )
746+ . map ( |i| format ! ( "SUM(a{i}), AVG(a{i})" ) )
747+ . collect ( ) ;
748+ let query = format ! ( "SELECT {} FROM t1" , aggs. join( ", " ) ) ;
749+ c. bench_function ( "logical_wide_aggregate_100_exprs" , |b| {
750+ b. iter ( || logical_plan ( & ctx, & rt, & query) )
751+ } ) ;
752+ }
753+
754+ // Many CASE WHEN expressions (complex expressions)
755+ {
756+ let cases: Vec < String > = ( 0 ..50 )
757+ . map ( |i| {
758+ format ! (
759+ "CASE WHEN a{i} > 0 THEN a{i} * 2 ELSE a{i} + 1 END AS r{i}"
760+ )
761+ } )
762+ . collect ( ) ;
763+ let query = format ! ( "SELECT {} FROM t1" , cases. join( ", " ) ) ;
764+ c. bench_function ( "logical_wide_case_50_exprs" , |b| {
765+ b. iter ( || logical_plan ( & ctx, & rt, & query) )
766+ } ) ;
767+ }
768+
769+ // --- Mixed: deep plan + wide expressions ---
770+ // This is the worst case for optimizer: many nodes AND many expressions.
771+
772+ c. bench_function ( "logical_join_4_with_agg_and_filter" , |b| {
773+ b. iter ( || {
774+ logical_plan (
775+ & ctx,
776+ & rt,
777+ "SELECT j3.x0, SUM(j4.x1), AVG(j5.x2), COUNT(j6.x3), \
778+ MIN(j3.x4), MAX(j4.x5) \
779+ FROM j3 \
780+ JOIN j4 ON j3.x0 = j4.x0 \
781+ JOIN j5 ON j4.x0 = j5.x0 \
782+ JOIN j6 ON j5.x0 = j6.x0 \
783+ WHERE j3.x1 > 0 AND j4.x2 < 100 AND j5.x3 != j6.x4 \
784+ GROUP BY j3.x0 \
785+ HAVING SUM(j4.x1) > 10 \
786+ ORDER BY j3.x0",
787+ )
788+ } )
789+ } ) ;
790+
791+ c. bench_function ( "logical_join_8_with_agg_sort_limit" , |b| {
792+ b. iter ( || {
793+ logical_plan (
794+ & ctx,
795+ & rt,
796+ "SELECT j3.x0, j4.x1, j5.x2, \
797+ SUM(j6.x3), AVG(j7.x4), COUNT(j8.x5), \
798+ MIN(j9.x6), MAX(j10.x7) \
799+ FROM j3 \
800+ JOIN j4 ON j3.x0 = j4.x0 \
801+ JOIN j5 ON j4.x0 = j5.x0 \
802+ JOIN j6 ON j5.x0 = j6.x0 \
803+ JOIN j7 ON j6.x0 = j7.x0 \
804+ JOIN j8 ON j7.x0 = j8.x0 \
805+ JOIN j9 ON j8.x0 = j9.x0 \
806+ JOIN j10 ON j9.x0 = j10.x0 \
807+ WHERE j3.x1 > 0 AND j5.x2 < 100 \
808+ GROUP BY j3.x0, j4.x1, j5.x2 \
809+ ORDER BY j3.x0 DESC \
810+ LIMIT 100",
811+ )
812+ } )
813+ } ) ;
814+
815+ // --- Subqueries (trigger decorrelation rules) ---
816+ // Tests rules like DecorrelatePredicateSubquery, ScalarSubqueryToJoin.
817+
818+ c. bench_function ( "logical_correlated_subquery_exists" , |b| {
819+ b. iter ( || {
820+ logical_plan (
821+ & ctx,
822+ & rt,
823+ "SELECT a0, a1 FROM t1 \
824+ WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b0 = t1.a0)",
825+ )
826+ } )
827+ } ) ;
828+
829+ c. bench_function ( "logical_correlated_subquery_in" , |b| {
830+ b. iter ( || {
831+ logical_plan (
832+ & ctx,
833+ & rt,
834+ "SELECT a0, a1 FROM t1 \
835+ WHERE a0 IN (SELECT b0 FROM t2 WHERE t2.b1 = t1.a1)",
836+ )
837+ } )
838+ } ) ;
839+
840+ c. bench_function ( "logical_scalar_subquery" , |b| {
841+ b. iter ( || {
842+ logical_plan (
843+ & ctx,
844+ & rt,
845+ "SELECT a0, (SELECT MAX(b1) FROM t2 WHERE t2.b0 = t1.a0) AS max_b \
846+ FROM t1",
847+ )
848+ } )
849+ } ) ;
850+
851+ c. bench_function ( "logical_multiple_subqueries" , |b| {
852+ b. iter ( || {
853+ logical_plan (
854+ & ctx,
855+ & rt,
856+ "SELECT a0, a1 FROM t1 \
857+ WHERE a0 IN (SELECT b0 FROM t2 WHERE b1 > 0) \
858+ AND EXISTS (SELECT 1 FROM t2 WHERE t2.b0 = t1.a0 AND t2.b1 < 100) \
859+ AND a1 > (SELECT AVG(b1) FROM t2)",
860+ )
861+ } )
862+ } ) ;
863+
864+ // --- UNION queries (test OptimizeUnions, PropagateEmptyRelation) ---
865+
866+ c. bench_function ( "logical_union_4_branches" , |b| {
867+ b. iter ( || {
868+ logical_plan (
869+ & ctx,
870+ & rt,
871+ "SELECT a0, a1 FROM t1 WHERE a0 > 0 \
872+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 10 \
873+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 20 \
874+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 30",
875+ )
876+ } )
877+ } ) ;
878+
879+ c. bench_function ( "logical_union_8_branches" , |b| {
880+ b. iter ( || {
881+ logical_plan (
882+ & ctx,
883+ & rt,
884+ "SELECT a0, a1 FROM t1 WHERE a0 > 0 \
885+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 10 \
886+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 20 \
887+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 30 \
888+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 40 \
889+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 50 \
890+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 60 \
891+ UNION ALL SELECT a0, a1 FROM t1 WHERE a0 > 70",
892+ )
893+ } )
894+ } ) ;
895+
896+ // --- DISTINCT (test ReplaceDistinctWithAggregate) ---
897+
898+ c. bench_function ( "logical_distinct_many_columns" , |b| {
899+ let cols: Vec < String > = ( 0 ..50 ) . map ( |i| format ! ( "a{i}" ) ) . collect ( ) ;
900+ let query = format ! ( "SELECT DISTINCT {} FROM t1" , cols. join( ", " ) ) ;
901+ b. iter ( || logical_plan ( & ctx, & rt, & query) )
902+ } ) ;
903+
904+ // --- Nested views / CTEs (deeper plan trees) ---
905+
906+ c. bench_function ( "logical_nested_cte_4_levels" , |b| {
907+ b. iter ( || {
908+ logical_plan (
909+ & ctx,
910+ & rt,
911+ "WITH \
912+ cte1 AS (SELECT a0, a1, a2 FROM t1 WHERE a0 > 0), \
913+ cte2 AS (SELECT a0, a1 FROM cte1 WHERE a1 > 0), \
914+ cte3 AS (SELECT a0 FROM cte2 WHERE a0 < 100), \
915+ cte4 AS (SELECT a0, COUNT(*) AS cnt FROM cte3 GROUP BY a0) \
916+ SELECT * FROM cte4 ORDER BY a0 LIMIT 10",
917+ )
918+ } )
919+ } ) ;
920+
921+ // --- TPC-H logical plans (uncommented from existing code) ---
922+ // These test real-world query patterns with moderate plan complexity.
923+
924+ c. bench_function ( "logical_plan_tpch_all" , |b| {
925+ b. iter ( || {
926+ for sql in & all_tpch_sql_queries {
927+ logical_plan ( & tpch_ctx, & rt, sql)
928+ }
929+ } )
930+ } ) ;
931+
932+ c. bench_function ( "logical_plan_tpcds_all" , |b| {
933+ b. iter ( || {
934+ for sql in & all_tpcds_sql_queries {
935+ logical_plan ( & tpcds_ctx, & rt, sql)
936+ }
937+ } )
938+ } ) ;
637939}
638940
639941criterion_group ! ( benches, criterion_benchmark) ;
0 commit comments