@@ -9,7 +9,7 @@ use crate::errors::{ErrorKind, ErrorLang, ErrorType, ErrorVm};
99use crate :: functions:: { FunDef , Param } ;
1010use crate :: operator:: { Op , OpCmp , OpLogic , OpQuery } ;
1111use crate :: types:: Ty ;
12- use spacetimedb_lib:: { Address , Identity } ;
12+ use spacetimedb_lib:: Identity ;
1313use spacetimedb_primitives:: * ;
1414use spacetimedb_sats:: algebraic_type:: AlgebraicType ;
1515use spacetimedb_sats:: algebraic_value:: AlgebraicValue ;
@@ -426,7 +426,7 @@ impl IndexJoin {
426426 // Reorder the index and probe sides of an index join.
427427 // This is necessary if the indexed table has been replaced by a delta table.
428428 // A delta table is a virtual table consisting of changes or updates to a physical table.
429- pub fn reorder ( self ) -> Self {
429+ pub fn reorder ( self , row_count : impl Fn ( TableId ) -> i64 ) -> Self {
430430 // The probe table must be a physical table.
431431 if matches ! ( self . probe_side. source, SourceExpr :: MemTable ( _) ) {
432432 return self ;
@@ -449,26 +449,25 @@ impl IndexJoin {
449449 {
450450 return self ;
451451 }
452- // Returns the `FieldName` for this `ColId`.
453- // Note there is an unwrap which the compiler will ensure is safe.
454- // The existence of `col` will already have been verified,
455- // during construction of the index join.
456- fn field ( table : & MemTable , col : & ColId ) -> FieldName {
457- table
458- . head ( )
459- . fields
460- . iter ( )
461- . find ( |Column { col_id, .. } | col_id == col)
462- . unwrap ( )
463- . field
464- . clone ( )
465- }
466452 // For the same reason the compiler also ensures this unwrap is safe.
467453 let probe_column = self . probe_side . source . head ( ) . column ( & self . probe_field ) . unwrap ( ) . col_id ;
468454 match self . index_side {
469- Table :: MemTable ( delta) => {
470- let index_field = field ( & delta, & self . index_col ) ;
471-
455+ // If the size of the indexed table is sufficiently large, do not reorder.
456+ Table :: DbTable ( DbTable { table_id, .. } ) if row_count ( table_id) > 1000 => self ,
457+ // If this is a delta table, we must reorder.
458+ // If this is a sufficiently small physical table, we should reorder.
459+ table => {
460+ // The compiler ensures the following unwrap is safe.
461+ // The existence of the index `ColId` as already been verified,
462+ // during construction of the index join.
463+ let index_field = table
464+ . head ( )
465+ . fields
466+ . iter ( )
467+ . find ( |col| col. col_id == self . index_col )
468+ . unwrap ( )
469+ . field
470+ . clone ( ) ;
472471 // Merge all selections from the original probe side into a single predicate.
473472 // This includes an index scan if present.
474473 let predicate = self . probe_side . query . into_iter ( ) . fold ( None , |acc, op| {
@@ -483,11 +482,11 @@ impl IndexJoin {
483482 // Push any selections on the index side to the probe side.
484483 let probe_side = if let Some ( predicate) = self . index_select {
485484 QueryExpr {
486- source : delta . into ( ) ,
485+ source : table . into ( ) ,
487486 query : vec ! [ predicate. into( ) ] ,
488487 }
489488 } else {
490- delta . into ( )
489+ table . into ( )
491490 } ;
492491 IndexJoin {
493492 // The new probe side consists of the updated rows.
@@ -506,7 +505,6 @@ impl IndexJoin {
506505 return_index_rows : !self . return_index_rows ,
507506 }
508507 }
509- Table :: DbTable ( _) => self ,
510508 }
511509 }
512510
@@ -624,9 +622,9 @@ pub enum CrudExpr {
624622}
625623
626624impl CrudExpr {
627- pub fn optimize ( self , db : Option < Address > ) -> Self {
625+ pub fn optimize ( self , row_count : & impl Fn ( TableId ) -> i64 ) -> Self {
628626 match self {
629- CrudExpr :: Query ( x) => CrudExpr :: Query ( x. optimize ( db ) ) ,
627+ CrudExpr :: Query ( x) => CrudExpr :: Query ( x. optimize ( row_count ) ) ,
630628 _ => self ,
631629 }
632630 }
@@ -1286,7 +1284,8 @@ impl QueryExpr {
12861284 //
12871285 // Ex. SELECT Left.* FROM Left JOIN Right ON Left.id = Right.id ...
12881286 // where `Left` has an index defined on `id`.
1289- fn try_index_join ( mut query : QueryExpr , _db : Option < Address > ) -> QueryExpr {
1287+ fn try_index_join ( self ) -> QueryExpr {
1288+ let mut query = self ;
12901289 // We expect 2 and only 2 operations - a join followed by a wildcard projection.
12911290 if query. query . len ( ) != 2 {
12921291 return query;
@@ -1391,7 +1390,7 @@ impl QueryExpr {
13911390 q
13921391 }
13931392
1394- pub fn optimize ( mut self , db : Option < Address > ) -> Self {
1393+ pub fn optimize ( mut self , row_count : & impl Fn ( TableId ) -> i64 ) -> Self {
13951394 let mut q = Self {
13961395 source : self . source . clone ( ) ,
13971396 query : Vec :: with_capacity ( self . query . len ( ) ) ,
@@ -1405,7 +1404,7 @@ impl QueryExpr {
14051404
14061405 if self . query . len ( ) == 1 && matches ! ( self . query[ 0 ] , Query :: IndexJoin ( _) ) {
14071406 if let Some ( Query :: IndexJoin ( join) ) = self . query . pop ( ) {
1408- q. query . push ( Query :: IndexJoin ( join. reorder ( ) ) ) ;
1407+ q. query . push ( Query :: IndexJoin ( join. reorder ( row_count ) ) ) ;
14091408 return q;
14101409 }
14111410 }
@@ -1415,11 +1414,18 @@ impl QueryExpr {
14151414 Query :: Select ( op) => {
14161415 q = Self :: optimize_select ( q, op, & tables) ;
14171416 }
1418- Query :: JoinInner ( join) => q = q. with_join_inner ( join. rhs . optimize ( db) , join. col_lhs , join. col_rhs ) ,
1417+ Query :: JoinInner ( join) => {
1418+ q = q. with_join_inner ( join. rhs . optimize ( row_count) , join. col_lhs , join. col_rhs )
1419+ }
14191420 _ => q. query . push ( query) ,
14201421 } ;
14211422 }
1422- Self :: try_index_join ( q, db)
1423+
1424+ let q = q. try_index_join ( ) ;
1425+ if q. query . len ( ) == 1 && matches ! ( q. query[ 0 ] , Query :: IndexJoin ( _) ) {
1426+ return q. optimize ( row_count) ;
1427+ }
1428+ q
14231429 }
14241430}
14251431
0 commit comments