mirror of
https://github.com/aljazceru/turso.git
synced 2025-12-25 12:04:21 +01:00
Closes #747 - Creates an automatic ephemeral (in-memory) index on the right-side table of a join if otherwise a nested table scan would be selected. - This behavior is not hardcoded; instead this PR introduces a (quite dumb) cost estimator that naturally deincentivizes building ephemeral indexes where they don't make sense (e.g. the outermost table). I will probably build this estimator to be smarter in the future when working on join reordering optimizations ### Example bytecode plans and runtimes (note that this is debug mode) Example query with no persistent indexes to choose from. Without ephemeral index it's a nested scan: ```sql limbo> explain select * from t1 natural join t2; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 13 0 0 Start at 13 1 OpenRead 0 2 0 0 table=t1, root=2 2 OpenRead 1 3 0 0 table=t2, root=3 3 Rewind 0 12 0 0 Rewind t1 4 Rewind 1 11 0 0 Rewind t2 5 Column 0 0 2 0 r[2]=t1.a 6 Column 1 0 3 0 r[3]=t2.a 7 Ne 2 3 10 0 if r[2]!=r[3] goto 10 8 Column 0 0 1 0 r[1]=t1.a 9 ResultRow 1 1 0 0 output=r[1] 10 Next 1 5 0 0 11 Next 0 4 0 0 12 Halt 0 0 0 0 13 Transaction 0 0 0 0 write=false 14 Goto 0 1 0 0 limbo> .timer on limbo> select * from t1 natural join t2; ┌───┐ │ a │ ├───┤ └───┘ Command stats: ---------------------------- total: 953 ms (this includes parsing/coloring of cli app) ``` Same query with autoindexing enabled: ```sql limbo> explain select * from t1 natural join t2; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 22 0 0 Start at 22 1 OpenRead 0 2 0 0 table=t1, root=2 2 OpenRead 1 3 0 0 table=t2, root=3 3 Rewind 0 21 0 0 Rewind t1 4 Once 12 0 0 0 goto 12 # execute block 5-11 only once, on subsequent iters jump straight to 12 5 OpenAutoindex 3 0 0 0 cursor=3 6 Rewind 1 12 0 0 Rewind t2 # open source table for ephemeral index 7 Column 1 0 2 0 r[2]=t2.a 8 RowId 1 3 0 0 r[3]=t2.rowid 9 MakeRecord 2 2 4 0 r[4]=mkrec(r[2..3]) 10 IdxInsert 3 4 2 0 key=r[4] # insert stuff to ephemeral index 11 Next 1 7 0 0 12 Column 0 0 5 0 r[5]=t1.a 13 IsNull 5 20 0 0 if (r[5]==NULL) goto 20 14 SeekGE 3 20 5 0 key=[5..5] # perform seek on ephemeral index 15 IdxGT 3 20 5 0 key=[5..5] 16 DeferredSeek 3 1 0 0 17 Column 0 0 1 0 r[1]=t1.a 18 ResultRow 1 1 0 0 output=r[1] 19 Next 2 15 0 0 20 Next 0 4 0 0 21 Halt 0 0 0 0 22 Transaction 0 0 0 0 write=false 23 Goto 0 1 0 0 limbo> .timer on limbo> select * from t1 natural join t2; ┌───┐ │ a │ ├───┤ └───┘ Command stats: ---------------------------- total: 220 ms (this includes parsing/coloring of cli app) ``` Closes #1356