Skip to content

Commit

Permalink
test: No divide by zero for row estimation of empty index (#1986)
Browse files Browse the repository at this point in the history
  • Loading branch information
joshua-spacetime authored Nov 14, 2024
1 parent 33c4aab commit 6dcb525
Showing 1 changed file with 14 additions and 0 deletions.
14 changes: 14 additions & 0 deletions crates/core/src/estimation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,13 @@ mod tests {
.expect("failed to insert into table");
}

fn create_empty_table_r(db: &RelationalDB, indexed: bool) {
let indexes = &[(0.into(), "a")];
let indexes = if indexed { indexes } else { &[] as &[_] };
db.create_table_for_test("R", &["a", "b"].map(|n| (n, AlgebraicType::U64)), indexes)
.expect("Failed to create table");
}

/// Cardinality estimation for an index lookup depends only on
/// (1) the total number of rows,
/// (2) the number of distinct values.
Expand All @@ -137,6 +144,13 @@ mod tests {
assert_eq!(NUM_T_ROWS / NDV_T, num_rows_for(&db, "select * from T where a = 0"));
}

#[test]
fn cardinality_estimation_0_ndv() {
let db = in_mem_db();
create_empty_table_r(&db, true);
assert_eq!(0, num_rows_for(&db, "select * from R where a = 0"));
}

/// We estimate an index range to return all input rows.
#[test]
fn cardinality_estimation_index_range() {
Expand Down

2 comments on commit 6dcb525

@github-actions
Copy link

@github-actions github-actions bot commented on 6dcb525 Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Criterion benchmark results

Criterion benchmark report

YOU SHOULD PROBABLY IGNORE THESE RESULTS.

Criterion is a wall time based benchmarking system that is extremely noisy when run on CI. We collect these results for longitudinal analysis, but they are not reliable for comparing individual PRs.

Go look at the callgrind report instead.

empty

db on disk new latency old latency new throughput old throughput
sqlite 💿 410.5±1.90ns 414.9±1.39ns - -
sqlite 🧠 406.2±2.03ns 401.9±1.31ns - -
stdb_raw 💿 775.7±1.28ns 779.0±1.22ns - -
stdb_raw 🧠 773.4±0.94ns 776.1±1.65ns - -

insert_1

db on disk schema indices preload new latency old latency new throughput old throughput

insert_bulk

db on disk schema indices preload count new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str btree_each_column 2048 256 592.9±1.44µs 602.7±59.03µs 1686 tx/sec 1659 tx/sec
sqlite 💿 u32_u64_str unique_0 2048 256 151.7±0.49µs 149.4±0.29µs 6.4 Ktx/sec 6.5 Ktx/sec
sqlite 💿 u32_u64_u64 btree_each_column 2048 256 483.5±31.83µs 464.1±0.64µs 2.0 Ktx/sec 2.1 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 2048 256 139.6±0.40µs 137.5±0.43µs 7.0 Ktx/sec 7.1 Ktx/sec
sqlite 🧠 u32_u64_str btree_each_column 2048 256 454.6±0.87µs 447.4±1.44µs 2.1 Ktx/sec 2.2 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 2048 256 123.1±0.52µs 121.1±0.71µs 7.9 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 u32_u64_u64 btree_each_column 2048 256 369.4±0.99µs 365.1±1.71µs 2.6 Ktx/sec 2.7 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 2048 256 105.8±2.34µs 101.0±0.37µs 9.2 Ktx/sec 9.7 Ktx/sec
stdb_raw 💿 u32_u64_str btree_each_column 2048 256 604.9±23.97µs 410.2±64.92µs 1653 tx/sec 2.4 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 2048 256 487.1±14.89µs 489.9±11.24µs 2.0 Ktx/sec 2041 tx/sec
stdb_raw 💿 u32_u64_u64 btree_each_column 2048 256 336.2±6.31µs 393.5±7.49µs 2.9 Ktx/sec 2.5 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 2048 256 353.7±8.68µs 347.9±21.57µs 2.8 Ktx/sec 2.8 Ktx/sec
stdb_raw 🧠 u32_u64_str btree_each_column 2048 256 310.0±0.46µs 316.0±0.23µs 3.2 Ktx/sec 3.1 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 2048 256 241.0±0.19µs 244.2±0.27µs 4.1 Ktx/sec 4.0 Ktx/sec
stdb_raw 🧠 u32_u64_u64 btree_each_column 2048 256 247.7±0.09µs 252.0±0.10µs 3.9 Ktx/sec 3.9 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 2048 256 220.9±0.37µs 226.0±0.31µs 4.4 Ktx/sec 4.3 Ktx/sec

iterate

db on disk schema indices new latency old latency new throughput old throughput
sqlite 💿 u32_u64_str unique_0 22.5±0.19µs 23.0±0.17µs 43.4 Ktx/sec 42.5 Ktx/sec
sqlite 💿 u32_u64_u64 unique_0 21.4±0.10µs 21.7±0.16µs 45.7 Ktx/sec 45.0 Ktx/sec
sqlite 🧠 u32_u64_str unique_0 19.7±0.10µs 20.3±0.18µs 49.5 Ktx/sec 48.1 Ktx/sec
sqlite 🧠 u32_u64_u64 unique_0 18.8±0.09µs 19.3±0.09µs 51.9 Ktx/sec 50.7 Ktx/sec
stdb_raw 💿 u32_u64_str unique_0 4.0±0.00µs 4.9±0.00µs 246.7 Ktx/sec 199.6 Ktx/sec
stdb_raw 💿 u32_u64_u64 unique_0 3.9±0.00µs 4.8±0.00µs 252.9 Ktx/sec 204.1 Ktx/sec
stdb_raw 🧠 u32_u64_str unique_0 4.0±0.01µs 4.9±0.00µs 247.0 Ktx/sec 200.4 Ktx/sec
stdb_raw 🧠 u32_u64_u64 unique_0 3.9±0.00µs 4.8±0.00µs 253.1 Ktx/sec 204.3 Ktx/sec

find_unique

db on disk key type preload new latency old latency new throughput old throughput

filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string index 2048 256 70.8±0.20µs 70.7±0.17µs 13.8 Ktx/sec 13.8 Ktx/sec
sqlite 💿 u64 index 2048 256 67.4±0.16µs 66.9±0.11µs 14.5 Ktx/sec 14.6 Ktx/sec
sqlite 🧠 string index 2048 256 66.7±0.10µs 67.2±0.14µs 14.6 Ktx/sec 14.5 Ktx/sec
sqlite 🧠 u64 index 2048 256 60.9±0.07µs 61.2±0.18µs 16.0 Ktx/sec 16.0 Ktx/sec
stdb_raw 💿 string index 2048 256 5.1±0.01µs 4.9±0.01µs 192.9 Ktx/sec 197.7 Ktx/sec
stdb_raw 💿 u64 index 2048 256 4.9±0.00µs 4.9±0.01µs 198.8 Ktx/sec 201.0 Ktx/sec
stdb_raw 🧠 string index 2048 256 5.1±0.00µs 4.9±0.01µs 192.9 Ktx/sec 197.4 Ktx/sec
stdb_raw 🧠 u64 index 2048 256 4.9±0.00µs 4.9±0.00µs 198.8 Ktx/sec 201.2 Ktx/sec

serialize

schema format count new latency old latency new throughput old throughput
u32_u64_str bflatn_to_bsatn_fast_path 100 3.6±0.00µs 3.6±0.01µs 26.7 Mtx/sec 26.7 Mtx/sec
u32_u64_str bflatn_to_bsatn_slow_path 100 2.9±0.01µs 2.9±0.01µs 32.4 Mtx/sec 32.4 Mtx/sec
u32_u64_str bsatn 100 15.3±0.01ns 15.9±0.01ns 6.1 Gtx/sec 5.9 Gtx/sec
u32_u64_str bsatn 100 2.2±0.00µs 2.2±0.00µs 44.2 Mtx/sec 44.3 Mtx/sec
u32_u64_str json 100 5.5±0.02µs 5.3±0.02µs 17.5 Mtx/sec 18.1 Mtx/sec
u32_u64_str json 100 8.7±0.04µs 8.8±0.05µs 10.9 Mtx/sec 10.8 Mtx/sec
u32_u64_str product_value 100 1019.0±0.75ns 1017.1±0.56ns 93.6 Mtx/sec 93.8 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_fast_path 100 1011.4±74.52ns 983.0±0.74ns 94.3 Mtx/sec 97.0 Mtx/sec
u32_u64_u64 bflatn_to_bsatn_slow_path 100 2.4±0.01µs 2.4±0.00µs 39.1 Mtx/sec 39.1 Mtx/sec
u32_u64_u64 bsatn 100 1535.5±2.47ns 1523.3±3.82ns 62.1 Mtx/sec 62.6 Mtx/sec
u32_u64_u64 bsatn 100 6.8±0.01ns 15.1±0.33ns 13.7 Gtx/sec 6.2 Gtx/sec
u32_u64_u64 json 100 3.7±0.00µs 3.8±0.01µs 26.0 Mtx/sec 25.4 Mtx/sec
u32_u64_u64 json 100 5.9±0.35µs 5.6±0.07µs 16.0 Mtx/sec 16.9 Mtx/sec
u32_u64_u64 product_value 100 1014.5±0.82ns 1014.6±0.62ns 94.0 Mtx/sec 94.0 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_fast_path 100 743.9±2.22ns 749.6±1.15ns 128.2 Mtx/sec 127.2 Mtx/sec
u64_u64_u32 bflatn_to_bsatn_slow_path 100 2.4±0.00µs 2.4±0.00µs 39.1 Mtx/sec 39.1 Mtx/sec
u64_u64_u32 bsatn 100 1545.0±1.26ns 1536.8±66.79ns 61.7 Mtx/sec 62.1 Mtx/sec
u64_u64_u32 bsatn 100 644.3±1.99ns 645.1±2.37ns 148.0 Mtx/sec 147.8 Mtx/sec
u64_u64_u32 json 100 4.0±0.01µs 3.7±0.01µs 23.6 Mtx/sec 25.9 Mtx/sec
u64_u64_u32 json 100 6.1±0.17µs 6.0±0.13µs 15.7 Mtx/sec 16.0 Mtx/sec
u64_u64_u32 product_value 100 1014.0±0.54ns 1014.2±0.47ns 94.1 Mtx/sec 94.0 Mtx/sec

stdb_module_large_arguments

arg size new latency old latency new throughput old throughput
64KiB 104.9±9.63µs 102.1±8.33µs - -

stdb_module_print_bulk

line count new latency old latency new throughput old throughput
1 52.0±5.86µs 54.0±5.85µs - -
100 604.1±4.21µs 597.0±7.96µs - -
1000 3.5±0.03ms 3.6±0.57ms - -

remaining

name new latency old latency new throughput old throughput
special/db_game/circles/load=10 38.8±6.19ms 42.1±7.76ms - -
special/db_game/circles/load=100 45.3±6.01ms 35.5±0.94ms - -
special/db_game/ia_loop/load=500 147.7±1.04ms 147.4±1.38ms - -
special/db_game/ia_loop/load=5000 5.3±0.03s 5.3±0.03s - -
sqlite/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 54.5±0.14µs 55.5±0.13µs 17.9 Ktx/sec 17.6 Ktx/sec
sqlite/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 47.2±0.06µs 49.7±0.03µs 20.7 Ktx/sec 19.7 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 38.4±0.12µs 40.7±0.26µs 25.4 Ktx/sec 24.0 Ktx/sec
sqlite/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 35.6±0.20µs 38.4±0.09µs 27.4 Ktx/sec 25.5 Ktx/sec
stdb_module/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 1256.1±8.05µs 1220.1±7.65µs 796 tx/sec 819 tx/sec
stdb_module/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 1006.3±3.13µs 1004.3±8.69µs 993 tx/sec 995 tx/sec
stdb_raw/💿/update_bulk/u32_u64_str/unique_0/load=2048/count=256 648.8±16.20µs 650.6±16.27µs 1541 tx/sec 1537 tx/sec
stdb_raw/💿/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 491.4±7.68µs 495.5±5.54µs 2035 tx/sec 2018 tx/sec
stdb_raw/🧠/update_bulk/u32_u64_str/unique_0/load=2048/count=256 378.1±0.87µs 377.8±0.45µs 2.6 Ktx/sec 2.6 Ktx/sec
stdb_raw/🧠/update_bulk/u32_u64_u64/unique_0/load=2048/count=256 342.2±0.62µs 341.6±0.16µs 2.9 Ktx/sec 2.9 Ktx/sec

@github-actions
Copy link

@github-actions github-actions bot commented on 6dcb525 Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Callgrind benchmark results

Callgrind Benchmark Report

These benchmarks were run using callgrind,
an instruction-level profiler. They allow comparisons between sqlite (sqlite), SpacetimeDB running through a module (stdb_module), and the underlying SpacetimeDB data storage engine (stdb_raw). Callgrind emulates a CPU to collect the below estimates.

Measurement changes larger than five percent are in bold.

In-memory benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 6397 6397 0.00% 6497 6497 0.00%
sqlite 5589 5589 0.00% 6007 6007 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 1 u64 76592 76592 0.00% 77064 77088 -0.03%
stdb_raw u32_u64_str no_index 64 128 2 string 118834 118834 0.00% 119656 119624 0.03%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25081 25083 -0.01% 25775 25693 0.32%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24049 24049 0.00% 24561 24529 0.13%
sqlite u32_u64_str no_index 64 128 2 string 144695 144695 0.00% 146231 146227 0.00%
sqlite u32_u64_str no_index 64 128 1 u64 124044 124089 -0.04% 125334 125383 -0.04%
sqlite u32_u64_str btree_each_column 64 128 1 u64 131361 131361 0.00% 132787 132787 0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 134494 134494 0.00% 136218 136210 0.01%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 872061 872911 -0.10% 920721 890811 3.36%
stdb_raw u32_u64_str btree_each_column 64 128 1019308 1023705 -0.43% 1079858 1053915 2.46%
sqlite u32_u64_str unique_0 64 128 398320 398320 0.00% 413936 413928 0.00%
sqlite u32_u64_str btree_each_column 64 128 983637 983637 0.00% 1020715 1020707 0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 153721 153721 0.00% 153849 153833 0.01%
stdb_raw u32_u64_str unique_0 64 16746 16746 0.00% 16842 16846 -0.02%
sqlite u32_u64_str unique_0 1024 1067255 1067255 0.00% 1070715 1070715 0.00%
sqlite u32_u64_str unique_0 64 76201 76201 0.00% 77255 77255 0.00%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47528 47528 0.00% 50214 50214 0.00%
64 bsatn 25509 25509 0.00% 27787 27787 0.00%
16 bsatn 8200 8200 0.00% 9594 9594 0.00%
16 json 12188 12188 0.00% 14126 14126 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 19983993 20413765 -2.11% 20438773 20922237 -2.31%
stdb_raw u32_u64_str unique_0 64 128 1277965 1278714 -0.06% 1343877 1313878 2.28%
sqlite u32_u64_str unique_0 1024 1024 1802182 1802182 0.00% 1811438 1811438 0.00%
sqlite u32_u64_str unique_0 64 128 128528 128528 0.00% 131340 131340 0.00%
On-disk benchmarks

callgrind: empty transaction

db total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw 6402 6402 0.00% 6498 6498 0.00%
sqlite 5621 5621 0.00% 6069 6069 0.00%

callgrind: filter

db schema indices count preload _column data_type total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str no_index 64 128 1 u64 76597 76597 0.00% 77049 77041 0.01%
stdb_raw u32_u64_str no_index 64 128 2 string 118860 119928 -0.89% 119646 120686 -0.86%
stdb_raw u32_u64_str btree_each_column 64 128 2 string 25086 25086 0.00% 25744 25704 0.16%
stdb_raw u32_u64_str btree_each_column 64 128 1 u64 24054 24054 0.00% 24506 24506 0.00%
sqlite u32_u64_str no_index 64 128 1 u64 125965 125965 0.00% 127555 127559 -0.00%
sqlite u32_u64_str no_index 64 128 2 string 146616 146616 0.00% 148404 148400 0.00%
sqlite u32_u64_str btree_each_column 64 128 2 string 136616 136616 0.00% 138654 138654 0.00%
sqlite u32_u64_str btree_each_column 64 128 1 u64 133457 133457 0.00% 135237 135237 0.00%

callgrind: insert bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 64 128 821628 821603 0.00% 869146 869161 -0.00%
stdb_raw u32_u64_str btree_each_column 64 128 969047 971929 -0.30% 1027657 1030629 -0.29%
sqlite u32_u64_str unique_0 64 128 415863 415857 0.00% 430645 430639 0.00%
sqlite u32_u64_str btree_each_column 64 128 1021898 1021898 0.00% 1058636 1058644 -0.00%

callgrind: iterate

db schema indices count total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 153726 153726 0.00% 153842 153822 0.01%
stdb_raw u32_u64_str unique_0 64 16751 16751 0.00% 16847 16887 -0.24%
sqlite u32_u64_str unique_0 1024 1070323 1070323 0.00% 1074165 1074165 0.00%
sqlite u32_u64_str unique_0 64 77973 77973 0.00% 79295 79295 0.00%

callgrind: serialize_product_value

count format total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
64 json 47528 47528 0.00% 50214 50214 0.00%
64 bsatn 25509 25509 0.00% 27787 27787 0.00%
16 bsatn 8200 8200 0.00% 9594 9594 0.00%
16 json 12188 12188 0.00% 14126 14126 0.00%

callgrind: update bulk

db schema indices count preload total reads + writes old total reads + writes Δrw estimated cycles old estimated cycles Δcycles
stdb_raw u32_u64_str unique_0 1024 1024 18903887 18904012 -0.00% 19440567 19440154 0.00%
stdb_raw u32_u64_str unique_0 64 128 1231460 1231776 -0.03% 1295388 1295984 -0.05%
sqlite u32_u64_str unique_0 1024 1024 1809743 1809743 0.00% 1818307 1818307 0.00%
sqlite u32_u64_str unique_0 64 128 132654 132654 0.00% 135574 135574 0.00%

Please sign in to comment.