Skip to content

Commit e3a4400

Browse files
committed
Merge 'Multi column indexes + index seek refactor' from Jussi Saurio
# Multi column indexes + index seek refactor ## PR reader guide I would say mostly you should just focus on the content of `optimizer.rs` and `plan.rs` because the rest is just small type changes, or in the case of `main_loop.rs`, a bunch of logic was just moved out of there and rewritten. ## New feature - multi column index seeks This PR adds support for utilizing multi-column indexes properly, i.e. using as many columns in the seek key as possible. Previously, we only used max one column per index. I've modified the existing compound index seek fuzz test to use this functionality. ## Refactoring of index seek related logic This PR moves a lot of index seek related logic out of `main_loop.rs` into `optimizer.rs` and `plan.rs` and introduces a bunch of helper structures to model finding and using an index to perform a seek + scan. ## Examples Here are some examples of multi-column seeks: ### Example table setup: ```sql sqlite> CREATE TABLE t(a,b,c,d,e); sqlite> CREATE INDEX abc ON t (a,b,c); -- create 10000 rows with random values between 0-9 for all columns sqlite >INSERT INTO t SELECT ABS(RANDOM() % 10),ABS(RANDOM() % 10),ABS(RANDOM() % 10),ABS(RANDOM() % 10),ABS(RANDOM() % 10) FROM generate_series(1,10000,1); ``` ### Example bytecode plans, results and timings vs main branch: ```sql limbo> EXPLAIN SELECT * FROM t WHERE a = 5 and b = 6 and c = 7; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 20 0 0 Start at 20 1 OpenReadAsync 0 2 0 0 table=t, root=2 2 OpenReadAwait 0 0 0 0 3 OpenReadAsync 1 3 0 0 table=abc, root=3 4 OpenReadAwait 0 0 0 0 5 Integer 5 6 0 0 r[6]=5 6 Integer 6 7 0 0 r[7]=6 7 Integer 7 8 0 0 r[8]=7 8 SeekGE 1 19 6 0 key=[6..8] 9 IdxGT 1 19 6 0 key=[6..8] 10 DeferredSeek 1 0 0 0 11 Column 0 0 1 0 r[1]=t.a 12 Column 0 1 2 0 r[2]=t.b 13 Column 0 2 3 0 r[3]=t.c 14 Column 0 3 4 0 r[4]=t.d 15 Column 0 4 5 0 r[5]=t.e 16 ResultRow 1 5 0 0 output=r[1..5] 17 NextAsync 1 0 0 0 18 NextAwait 1 9 0 0 19 Halt 0 0 0 0 20 Transaction 0 0 0 0 write=false 21 Goto 0 1 0 0 limbo> SELECT * FROM t WHERE a = 5 and b = 6 and c = 7; 5|6|7|9|9 5|6|7|4|7 5|6|7|3|2 5|6|7|3|7 5|6|7|5|2 5|6|7|5|3 5|6|7|9|7 runtime (debug build, this branch): total: 2 ms (this includes parsing/coloring of cli app) runtime (debud build, main branch): total: 67 ms (this includes parsing/coloring of cli app) ``` ```sql limbo> EXPLAIN SELECT * FROM t WHERE a = 5 and b = 6 and c < 7; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 21 0 0 Start at 21 1 OpenReadAsync 0 2 0 0 table=t, root=2 2 OpenReadAwait 0 0 0 0 3 OpenReadAsync 1 3 0 0 table=abc, root=3 4 OpenReadAwait 0 0 0 0 5 Integer 5 6 0 0 r[6]=5 6 Integer 6 7 0 0 r[7]=6 7 Null 0 8 0 0 r[8]=NULL 8 SeekGT 1 20 6 0 key=[6..8] 9 Integer 7 8 0 0 r[8]=7 10 IdxGE 1 20 6 0 key=[6..8] 11 DeferredSeek 1 0 0 0 12 Column 0 0 1 0 r[1]=t.a 13 Column 0 1 2 0 r[2]=t.b 14 Column 0 2 3 0 r[3]=t.c 15 Column 0 3 4 0 r[4]=t.d 16 Column 0 4 5 0 r[5]=t.e 17 ResultRow 1 5 0 0 output=r[1..5] 18 NextAsync 1 0 0 0 19 NextAwait 1 10 0 0 20 Halt 0 0 0 0 21 Transaction 0 0 0 0 write=false 22 Goto 0 1 0 0 limbo> SELECT * FROM t WHERE a = 5 and b = 6 and c < 7; 5|6|0|0|3 5|6|0|5|1 5|6|0|3|1 5|6|0|6|3 5|6|0|8|1 5|6|0|2|7 5|6|0|9|9 5|6|0|5|3 5|6|0|4|2 5|6|0|4|2 5|6|0|0|2 5|6|0|7|2 5|6|1|8|5 5|6|1|7|5 5|6|1|7|2 5|6|1|1|2 5|6|1|6|5 5|6|1|1|5 5|6|1|5|7 5|6|1|1|9 5|6|1|4|3 5|6|1|1|2 5|6|1|2|2 5|6|1|4|4 5|6|1|9|6 5|6|1|2|5 5|6|1|2|4 5|6|1|7|1 5|6|2|0|9 5|6|2|6|9 5|6|2|4|5 5|6|2|9|3 5|6|2|5|2 5|6|2|9|0 5|6|2|7|1 5|6|3|6|5 5|6|3|8|5 5|6|3|5|4 5|6|3|5|2 5|6|3|1|1 5|6|3|2|0 5|6|3|9|3 5|6|3|6|9 5|6|3|7|6 5|6|3|3|5 5|6|3|0|8 5|6|3|6|4 5|6|4|1|1 5|6|4|9|8 5|6|4|3|7 5|6|4|1|3 5|6|4|8|9 5|6|4|9|7 5|6|4|7|9 5|6|4|8|8 5|6|4|3|1 5|6|4|2|6 5|6|4|5|7 5|6|4|2|6 5|6|4|4|3 5|6|5|2|4 5|6|5|6|7 5|6|5|3|8 5|6|5|7|8 5|6|5|9|6 5|6|5|2|7 5|6|5|1|7 5|6|5|0|6 5|6|6|2|4 5|6|6|9|4 5|6|6|4|9 5|6|6|5|6 5|6|6|2|2 5|6|6|0|6 runtime (debug build, this branch): total: 9 ms (this includes parsing/coloring of cli app) runtime (debug build, main branch): total: 71 ms (this includes parsing/coloring of cli app) ``` ```sql limbo> EXPLAIN SELECT * FROM t WHERE a = 5 and b = 6 and c < 7 ORDER BY a desc, b desc, c desc; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 20 0 0 Start at 20 1 OpenReadAsync 0 2 0 0 table=t, root=2 2 OpenReadAwait 0 0 0 0 3 OpenReadAsync 1 3 0 0 table=abc, root=3 4 OpenReadAwait 0 0 0 0 5 Integer 5 6 0 0 r[6]=5 6 Integer 6 7 0 0 r[7]=6 7 Integer 7 8 0 0 r[8]=7 8 SeekLT 1 19 6 0 key=[6..8] 9 IdxLT 1 19 6 0 key=[6..7] 10 DeferredSeek 1 0 0 0 11 Column 0 0 1 0 r[1]=t.a 12 Column 0 1 2 0 r[2]=t.b 13 Column 0 2 3 0 r[3]=t.c 14 Column 0 3 4 0 r[4]=t.d 15 Column 0 4 5 0 r[5]=t.e 16 ResultRow 1 5 0 0 output=r[1..5] 17 PrevAsync 1 0 0 0 18 PrevAwait 1 0 0 0 19 Halt 0 0 0 0 20 Transaction 0 0 0 0 write=false 21 Goto 0 1 0 0 limbo> SELECT * FROM t WHERE a = 5 and b = 6 and c < 7 ORDER BY a desc, b desc, c desc; 5|6|6|0|6 5|6|6|2|2 5|6|6|5|6 5|6|6|4|9 5|6|6|9|4 5|6|6|2|4 5|6|5|0|6 5|6|5|1|7 5|6|5|2|7 5|6|5|9|6 5|6|5|7|8 5|6|5|3|8 5|6|5|6|7 5|6|5|2|4 5|6|4|4|3 5|6|4|2|6 5|6|4|5|7 5|6|4|2|6 5|6|4|3|1 5|6|4|8|8 5|6|4|7|9 5|6|4|9|7 5|6|4|8|9 5|6|4|1|3 5|6|4|3|7 5|6|4|9|8 5|6|4|1|1 5|6|3|6|4 5|6|3|0|8 5|6|3|3|5 5|6|3|7|6 5|6|3|6|9 5|6|3|9|3 5|6|3|2|0 5|6|3|1|1 5|6|3|5|2 5|6|3|5|4 5|6|3|8|5 5|6|3|6|5 5|6|2|7|1 5|6|2|9|0 5|6|2|5|2 5|6|2|9|3 5|6|2|4|5 5|6|2|6|9 5|6|2|0|9 5|6|1|7|1 5|6|1|2|4 5|6|1|2|5 5|6|1|9|6 5|6|1|4|4 5|6|1|2|2 5|6|1|1|2 5|6|1|4|3 5|6|1|1|9 5|6|1|5|7 5|6|1|1|5 5|6|1|6|5 5|6|1|1|2 5|6|1|7|2 5|6|1|7|5 5|6|1|8|5 5|6|0|7|2 5|6|0|0|2 5|6|0|4|2 5|6|0|4|2 5|6|0|5|3 5|6|0|9|9 5|6|0|2|7 5|6|0|8|1 5|6|0|6|3 5|6|0|3|1 5|6|0|5|1 5|6|0|0|3 runtime (debug build, this branch): total: 9 ms (this includes parsing/coloring of cli app) runtime (debug build, main branch): total: 71 ms (this includes parsing/coloring of cli app) ``` Closes #1288
2 parents 2752c77 + 4daad0a commit e3a4400

File tree

7 files changed

+1005
-539
lines changed

7 files changed

+1005
-539
lines changed

core/translate/emitter.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -397,10 +397,12 @@ fn emit_delete_insns(
397397
let cursor_id = match &table_reference.op {
398398
Operation::Scan { .. } => program.resolve_cursor_id(&table_reference.identifier),
399399
Operation::Search(search) => match search {
400-
Search::RowidEq { .. } | Search::RowidSearch { .. } => {
400+
Search::RowidEq { .. } | Search::Seek { index: None, .. } => {
401401
program.resolve_cursor_id(&table_reference.identifier)
402402
}
403-
Search::IndexSearch { index, .. } => program.resolve_cursor_id(&index.name),
403+
Search::Seek {
404+
index: Some(index), ..
405+
} => program.resolve_cursor_id(&index.name),
404406
},
405407
_ => return Ok(()),
406408
};
@@ -537,12 +539,14 @@ fn emit_update_insns(
537539
table_ref.virtual_table().is_some(),
538540
),
539541
Operation::Search(search) => match search {
540-
&Search::RowidEq { .. } | Search::RowidSearch { .. } => (
542+
&Search::RowidEq { .. } | Search::Seek { index: None, .. } => (
541543
program.resolve_cursor_id(&table_ref.identifier),
542544
None,
543545
false,
544546
),
545-
Search::IndexSearch { index, .. } => (
547+
Search::Seek {
548+
index: Some(index), ..
549+
} => (
546550
program.resolve_cursor_id(&table_ref.identifier),
547551
Some((index.clone(), program.resolve_cursor_id(&index.name))),
548552
false,

core/translate/main_loop.rs

Lines changed: 248 additions & 267 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)