Skip to content

Commit

Permalink
[wip] Multi-tiered index structure
Browse files Browse the repository at this point in the history
  • Loading branch information
RReverser committed Oct 18, 2023
1 parent 18bab3d commit d428821
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 81 deletions.
131 changes: 68 additions & 63 deletions crates/core/src/db/datastore/locking_tx_datastore/btree_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use crate::{
error::DBError,
};
use nonempty::NonEmpty;
use spacetimedb_lib::{data_key::ToDataKey, DataKey};
use spacetimedb_lib::data_key::ToDataKey;
use spacetimedb_sats::{AlgebraicValue, ProductValue};
use std::{
collections::{btree_set, BTreeSet},
ops::{Bound, RangeBounds},
collections::{btree_map, BTreeMap},
ops::RangeBounds,
};

/// ## Index Key Composition
Expand All @@ -31,57 +31,44 @@ use std::{
/// [AlgebraicValue::I32(0)] = Row(ProductValue(...))
/// [AlgebraicValue::Product(AlgebraicValue::I32(0), AlgebraicValue::I32(1))] = Row(ProductValue(...))
/// ```
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
struct IndexKey {
value: AlgebraicValue,
row_id: RowId,
}
impl IndexKey {
#[tracing::instrument(skip_all)]
pub(crate) fn from_row(value: &AlgebraicValue, row_id: DataKey) -> Self {
Self {
value: value.clone(),
row_id: RowId(row_id),
}
}
enum Rows {
Unique(BTreeMap<AlgebraicValue, RowId>),
NonUnique(BTreeMap<AlgebraicValue, indexmap::IndexSet<RowId>>),
}

pub struct BTreeIndexIter<'a> {
iter: btree_set::Iter<'a, IndexKey>,
}
pub struct ValueIter<I>(I);

impl Iterator for BTreeIndexIter<'_> {
type Item = RowId;
impl<'a, K: 'a, V: 'a, I> Iterator for ValueIter<I>
where
I: Iterator<Item = (&'a K, &'a V)>,
{
type Item = &'a V;

#[tracing::instrument(skip_all)]
fn next(&mut self) -> Option<Self::Item> {
self.iter.next().map(|key| key.row_id)
self.0.next().map(|(_, v)| v)
}
}

/// An iterator for the rows that match a value [AlgebraicValue] on the
/// [BTreeIndex]
pub struct BTreeIndexRangeIter<'a> {
range_iter: btree_set::Range<'a, IndexKey>,
}

impl Iterator for BTreeIndexRangeIter<'_> {
type Item = RowId;

#[tracing::instrument(skip_all)]
fn next(&mut self) -> Option<Self::Item> {
self.range_iter.next().map(|key| key.row_id)
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}

pub type BTreeIndexRangeIter<'a> = std::iter::Copied<
itertools::Either<
ValueIter<btree_map::Range<'a, AlgebraicValue, RowId>>,
std::iter::Flatten<ValueIter<btree_map::Range<'a, AlgebraicValue, indexmap::IndexSet<RowId>>>>,
>,
>;

pub(crate) struct BTreeIndex {
pub(crate) index_id: IndexId,
pub(crate) table_id: u32,
pub(crate) cols: NonEmpty<u32>,
pub(crate) name: String,
pub(crate) is_unique: bool,
idx: BTreeSet<IndexKey>,
// todo: remove is_unique in favour of this
idx: Rows,
}

impl BTreeIndex {
Expand All @@ -92,7 +79,10 @@ impl BTreeIndex {
cols,
name,
is_unique,
idx: BTreeSet::new(),
idx: match is_unique {
true => Rows::Unique(Default::default()),
false => Rows::NonUnique(Default::default()),
},
}
}

Expand All @@ -104,32 +94,51 @@ impl BTreeIndex {
#[tracing::instrument(skip_all)]
pub(crate) fn insert(&mut self, row: &ProductValue) -> Result<(), DBError> {
let col_value = self.get_fields(row)?;
let key = IndexKey::from_row(&col_value, row.to_data_key());
self.idx.insert(key);
let row_id = RowId(row.to_data_key());
match &mut self.idx {
Rows::Unique(rows) => {
if rows.insert(col_value, row_id).is_some() {
tracing::error!("unique constraint violation that should have been checked by now");
}
}
Rows::NonUnique(rows) => {
rows.entry(col_value).or_default().insert(row_id);
}
}
Ok(())
}

#[tracing::instrument(skip_all)]
pub(crate) fn delete(&mut self, col_value: &AlgebraicValue, row_id: &RowId) {
let key = IndexKey::from_row(col_value, row_id.0);
self.idx.remove(&key);
match &mut self.idx {
Rows::Unique(rows) => {
rows.remove(col_value);
}
Rows::NonUnique(rows) => {
if let Some(rows) = rows.get_mut(col_value) {
rows.remove(row_id);
}
}
}
}

#[tracing::instrument(skip_all)]
pub(crate) fn violates_unique_constraint(&self, row: &ProductValue) -> bool {
if self.is_unique {
let col_value = self.get_fields(row).unwrap();
return self.contains_any(&col_value);
pub(crate) fn get_row_that_violates_unique_constraint<'a>(&'a self, row: &AlgebraicValue) -> Option<&'a RowId> {
match &self.idx {
Rows::Unique(rows) => rows.get(row),
Rows::NonUnique(_) => None,
}
false
}

#[tracing::instrument(skip_all)]
pub(crate) fn get_rows_that_violate_unique_constraint<'a>(
&'a self,
row: &'a AlgebraicValue,
) -> Option<BTreeIndexRangeIter<'a>> {
self.is_unique.then(|| self.seek(row))
pub(crate) fn violates_unique_constraint(&self, row: &ProductValue) -> bool {
match &self.idx {
Rows::Unique(rows) => {
let col_value = self.get_fields(row).unwrap();
rows.contains_key(&col_value)
}
Rows::NonUnique(_) => false,
}
}

/// Returns `true` if the [BTreeIndex] contains a value for the specified `value`.
Expand All @@ -140,24 +149,20 @@ impl BTreeIndex {

/// Returns an iterator over the `RowId`s in the [BTreeIndex]
#[tracing::instrument(skip_all)]
pub(crate) fn scan(&self) -> BTreeIndexIter<'_> {
BTreeIndexIter { iter: self.idx.iter() }
pub(crate) fn scan(&self) -> BTreeIndexRangeIter<'_> {
self.seek(&(..))
}

/// Returns an iterator over the [BTreeIndex] that yields all the `RowId`s
/// that fall within the specified `range`.
#[tracing::instrument(skip_all)]
pub(crate) fn seek<'a>(&'a self, range: &impl RangeBounds<AlgebraicValue>) -> BTreeIndexRangeIter<'a> {
let map = |bound, datakey| match bound {
Bound::Included(x) => Bound::Included(IndexKey::from_row(x, datakey)),
Bound::Excluded(x) => Bound::Excluded(IndexKey::from_row(x, datakey)),
Bound::Unbounded => Bound::Unbounded,
};
let start = map(range.start_bound(), DataKey::min_datakey());
let end = map(range.end_bound(), DataKey::max_datakey());
BTreeIndexRangeIter {
range_iter: self.idx.range((start, end)),
let range = (range.start_bound(), range.end_bound());
match &self.idx {
Rows::Unique(rows) => itertools::Either::Left(ValueIter(rows.range(range))),
Rows::NonUnique(rows) => itertools::Either::Right(ValueIter(rows.range(range)).flatten()),
}
.copied()
}

/// Construct the [BTreeIndex] from the rows.
Expand Down
34 changes: 16 additions & 18 deletions crates/core/src/db/datastore/locking_tx_datastore/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1281,26 +1281,11 @@ impl Inner {
if let Some(table) = self.committed_state.tables.get_mut(&table_id) {
for index in table.indexes.values() {
let value = index.get_fields(&row)?;
let Some(violators) = index.get_rows_that_violate_unique_constraint(&value) else {
let Some(row_id) = index.get_row_that_violates_unique_constraint(&value) else {
continue;
};
for row_id in violators {
if let Some(delete_table) = self.tx_state.as_ref().unwrap().delete_tables.get(&table_id) {
if !delete_table.contains(&row_id) {
let value = row.project_not_empty(&index.cols)?;
return Err(IndexError::UniqueConstraintViolation {
constraint_name: index.name.clone(),
table_name: table.schema.table_name.clone(),
col_names: index
.cols
.iter()
.map(|&x| insert_table.schema.columns[x as usize].col_name.clone())
.collect(),
value,
}
.into());
}
} else {
if let Some(delete_table) = self.tx_state.as_ref().unwrap().delete_tables.get(&table_id) {
if !delete_table.contains(row_id) {
let value = row.project_not_empty(&index.cols)?;
return Err(IndexError::UniqueConstraintViolation {
constraint_name: index.name.clone(),
Expand All @@ -1314,6 +1299,19 @@ impl Inner {
}
.into());
}
} else {
let value = row.project_not_empty(&index.cols)?;
return Err(IndexError::UniqueConstraintViolation {
constraint_name: index.name.clone(),
table_name: table.schema.table_name.clone(),
col_names: index
.cols
.iter()
.map(|&x| insert_table.schema.columns[x as usize].col_name.clone())
.collect(),
value,
}
.into());
}
}
}
Expand Down

1 comment on commit d428821

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark results

Benchmark Report

Legend:

  • load: number of rows pre-loaded into the database
  • count: number of rows touched by the transaction
  • index types:
    • unique: a single index on the id column
    • non_unique: no indexes
    • multi_index: non-unique index on every column
  • schemas:
    • person(id: u32, name: String, age: u64)
    • location(id: u32, x: u64, y: u64)

All throughputs are single-threaded.

Empty transaction

db on disk new latency old latency new throughput old throughput
sqlite 💿 444.7±2.19ns 458.1±8.77ns - -
sqlite 🧠 435.7±3.30ns 457.5±6.57ns - -
stdb_module 💿 15.6±0.41µs 15.6±0.36µs - -
stdb_module 🧠 15.9±0.45µs 15.9±0.44µs - -
stdb_raw 💿 99.1±0.69ns 103.7±0.12ns - -
stdb_raw 🧠 99.4±0.74ns 103.4±0.13ns - -

Single-row insertions

db on disk schema index type load new latency old latency new throughput old throughput
sqlite 💿 location multi_index 0 14.8±0.72µs 14.6±0.07µs 66.0 Ktx/sec 66.7 Ktx/sec
sqlite 💿 location multi_index 1000 16.0±0.12µs 16.0±0.13µs 61.2 Ktx/sec 60.9 Ktx/sec
sqlite 💿 location non_unique 0 7.3±0.39µs 7.4±0.04µs 133.5 Ktx/sec 132.8 Ktx/sec
sqlite 💿 location non_unique 1000 7.2±0.07µs 7.2±0.04µs 135.4 Ktx/sec 135.9 Ktx/sec
sqlite 💿 location unique 0 7.3±0.33µs 7.4±0.33µs 133.9 Ktx/sec 131.5 Ktx/sec
sqlite 💿 location unique 1000 7.3±0.05µs 7.2±0.04µs 134.3 Ktx/sec 135.8 Ktx/sec
sqlite 💿 person multi_index 0 14.4±0.03µs 14.7±0.71µs 67.9 Ktx/sec 66.5 Ktx/sec
sqlite 💿 person multi_index 1000 16.3±0.11µs 16.2±0.13µs 59.9 Ktx/sec 60.3 Ktx/sec
sqlite 💿 person non_unique 0 7.4±0.54µs 7.5±0.35µs 131.3 Ktx/sec 130.5 Ktx/sec
sqlite 💿 person non_unique 1000 7.4±0.04µs 7.4±0.04µs 132.3 Ktx/sec 132.2 Ktx/sec
sqlite 💿 person unique 0 7.4±0.50µs 7.4±0.33µs 132.6 Ktx/sec 131.6 Ktx/sec
sqlite 💿 person unique 1000 7.4±0.09µs 7.4±0.05µs 131.3 Ktx/sec 132.1 Ktx/sec
sqlite 🧠 location multi_index 0 4.1±0.01µs 4.0±0.01µs 240.7 Ktx/sec 241.3 Ktx/sec
sqlite 🧠 location multi_index 1000 5.3±0.03µs 5.2±0.03µs 183.1 Ktx/sec 186.5 Ktx/sec
sqlite 🧠 location non_unique 0 1873.1±5.24ns 1888.8±7.69ns 521.4 Ktx/sec 517.0 Ktx/sec
sqlite 🧠 location non_unique 1000 1928.6±7.46ns 1910.4±9.81ns 506.4 Ktx/sec 511.2 Ktx/sec
sqlite 🧠 location unique 0 1849.4±10.15ns 1880.8±5.27ns 528.0 Ktx/sec 519.2 Ktx/sec
sqlite 🧠 location unique 1000 1981.2±14.02ns 1951.8±7.85ns 492.9 Ktx/sec 500.3 Ktx/sec
sqlite 🧠 person multi_index 0 3.9±0.02µs 4.0±0.01µs 248.9 Ktx/sec 243.3 Ktx/sec
sqlite 🧠 person multi_index 1000 5.8±0.05µs 5.7±0.03µs 167.7 Ktx/sec 171.4 Ktx/sec
sqlite 🧠 person non_unique 0 1944.6±4.93ns 1970.5±6.36ns 502.2 Ktx/sec 495.6 Ktx/sec
sqlite 🧠 person non_unique 1000 2.1±0.01µs 2.1±0.01µs 468.7 Ktx/sec 465.7 Ktx/sec
sqlite 🧠 person unique 0 1959.9±10.13ns 1951.3±5.15ns 498.3 Ktx/sec 500.5 Ktx/sec
sqlite 🧠 person unique 1000 2.1±0.03µs 2.1±0.01µs 458.0 Ktx/sec 456.1 Ktx/sec
stdb_module 💿 location multi_index 0 42.6±4.91µs 35.1±4.62µs 22.9 Ktx/sec 27.9 Ktx/sec
stdb_module 💿 location multi_index 1000 511.9±19.17µs 136.0±55.50µs 1953 tx/sec 7.2 Ktx/sec
stdb_module 💿 location non_unique 0 34.8±2.87µs 35.0±3.03µs 28.1 Ktx/sec 27.9 Ktx/sec
stdb_module 💿 location non_unique 1000 370.3±39.86µs 230.7±3.00µs 2.6 Ktx/sec 4.2 Ktx/sec
stdb_module 💿 location unique 0 37.2±4.56µs 40.4±4.30µs 26.2 Ktx/sec 24.2 Ktx/sec
stdb_module 💿 location unique 1000 229.4±103.11µs 383.8±8.09µs 4.3 Ktx/sec 2.5 Ktx/sec
stdb_module 💿 person multi_index 0 51.1±5.71µs 52.7±6.65µs 19.1 Ktx/sec 18.5 Ktx/sec
stdb_module 💿 person multi_index 1000 304.0±64.74µs 471.2±109.22µs 3.2 Ktx/sec 2.1 Ktx/sec
stdb_module 💿 person non_unique 0 35.7±5.21µs 35.8±3.54µs 27.4 Ktx/sec 27.3 Ktx/sec
stdb_module 💿 person non_unique 1000 258.5±32.14µs 259.0±113.00µs 3.8 Ktx/sec 3.8 Ktx/sec
stdb_module 💿 person unique 0 42.8±5.70µs 44.0±4.17µs 22.8 Ktx/sec 22.2 Ktx/sec
stdb_module 💿 person unique 1000 166.6±88.44µs 435.2±8.06µs 5.9 Ktx/sec 2.2 Ktx/sec
stdb_module 🧠 location multi_index 0 31.6±3.09µs 30.1±2.64µs 30.9 Ktx/sec 32.4 Ktx/sec
stdb_module 🧠 location multi_index 1000 367.4±96.17µs 217.6±15.56µs 2.7 Ktx/sec 4.5 Ktx/sec
stdb_module 🧠 location non_unique 0 26.2±1.62µs 26.0±1.45µs 37.3 Ktx/sec 37.6 Ktx/sec
stdb_module 🧠 location non_unique 1000 224.6±46.60µs 230.1±18.37µs 4.3 Ktx/sec 4.2 Ktx/sec
stdb_module 🧠 location unique 0 27.7±2.59µs 28.9±1.86µs 35.2 Ktx/sec 33.8 Ktx/sec
stdb_module 🧠 location unique 1000 250.1±91.08µs 304.6±20.93µs 3.9 Ktx/sec 3.2 Ktx/sec
stdb_module 🧠 person multi_index 0 40.9±4.29µs 38.1±3.17µs 23.9 Ktx/sec 25.6 Ktx/sec
stdb_module 🧠 person multi_index 1000 394.6±19.67µs 210.5±49.11µs 2.5 Ktx/sec 4.6 Ktx/sec
stdb_module 🧠 person non_unique 0 27.6±2.41µs 28.4±2.90µs 35.3 Ktx/sec 34.4 Ktx/sec
stdb_module 🧠 person non_unique 1000 185.9±62.27µs 247.1±21.15µs 5.3 Ktx/sec 4.0 Ktx/sec
stdb_module 🧠 person unique 0 31.5±2.40µs 34.7±3.07µs 31.0 Ktx/sec 28.2 Ktx/sec
stdb_module 🧠 person unique 1000 247.2±8.52µs 385.1±14.01µs 3.9 Ktx/sec 2.5 Ktx/sec
stdb_raw 💿 location multi_index 0 6.0±0.01µs 5.3±0.01µs 163.6 Ktx/sec 184.3 Ktx/sec
stdb_raw 💿 location multi_index 1000 62.8±183.65µs 33.8±0.51µs 15.6 Ktx/sec 28.9 Ktx/sec
stdb_raw 💿 location non_unique 0 3.5±0.01µs 3.5±0.01µs 279.0 Ktx/sec 277.3 Ktx/sec
stdb_raw 💿 location non_unique 1000 42.3±105.55µs 29.7±79.92µs 23.1 Ktx/sec 32.8 Ktx/sec
stdb_raw 💿 location unique 0 4.2±0.10µs 4.3±0.01µs 233.0 Ktx/sec 224.8 Ktx/sec
stdb_raw 💿 location unique 1000 46.2±111.87µs 39.9±127.80µs 21.1 Ktx/sec 24.5 Ktx/sec
stdb_raw 💿 person multi_index 0 9.7±0.02µs 9.0±0.01µs 100.4 Ktx/sec 108.7 Ktx/sec
stdb_raw 💿 person multi_index 1000 38.9±0.47µs 59.6±350.92µs 25.1 Ktx/sec 16.4 Ktx/sec
stdb_raw 💿 person non_unique 0 4.1±0.01µs 4.1±0.04µs 239.8 Ktx/sec 236.1 Ktx/sec
stdb_raw 💿 person non_unique 1000 28.8±150.35µs 14.2±0.13µs 33.9 Ktx/sec 68.8 Ktx/sec
stdb_raw 💿 person unique 0 5.8±0.02µs 5.9±0.01µs 167.8 Ktx/sec 165.5 Ktx/sec
stdb_raw 💿 person unique 1000 38.1±167.05µs 21.7±0.35µs 25.6 Ktx/sec 45.1 Ktx/sec
stdb_raw 🧠 location multi_index 0 4.6±0.05µs 4.1±0.01µs 213.5 Ktx/sec 237.6 Ktx/sec
stdb_raw 🧠 location multi_index 1000 40.4±0.18µs 29.4±0.79µs 24.2 Ktx/sec 33.2 Ktx/sec
stdb_raw 🧠 location non_unique 0 2.2±0.02µs 2.2±0.01µs 439.0 Ktx/sec 441.5 Ktx/sec
stdb_raw 🧠 location non_unique 1000 27.9±0.10µs 19.4±0.08µs 35.0 Ktx/sec 50.4 Ktx/sec
stdb_raw 🧠 location unique 0 2.9±0.01µs 3.0±0.01µs 342.0 Ktx/sec 322.7 Ktx/sec
stdb_raw 🧠 location unique 1000 30.2±0.10µs 24.5±0.12µs 32.4 Ktx/sec 39.9 Ktx/sec
stdb_raw 🧠 person multi_index 0 8.2±0.01µs 7.6±0.01µs 118.8 Ktx/sec 128.6 Ktx/sec
stdb_raw 🧠 person multi_index 1000 34.0±0.31µs 21.5±1.16µs 28.7 Ktx/sec 45.4 Ktx/sec
stdb_raw 🧠 person non_unique 0 2.8±0.05µs 2.8±0.01µs 345.8 Ktx/sec 345.8 Ktx/sec
stdb_raw 🧠 person non_unique 1000 12.8±0.19µs 12.8±0.17µs 76.6 Ktx/sec 76.2 Ktx/sec
stdb_raw 🧠 person unique 0 4.5±0.01µs 4.7±0.01µs 216.8 Ktx/sec 209.3 Ktx/sec
stdb_raw 🧠 person unique 1000 17.2±0.45µs 17.0±0.57µs 56.8 Ktx/sec 57.5 Ktx/sec

Multi-row insertions

db on disk schema index type load count new latency old latency new throughput old throughput
sqlite 💿 location multi_index 0 100 130.7±4.50µs 132.9±2.68µs 7.5 Ktx/sec 7.3 Ktx/sec
sqlite 💿 location multi_index 1000 100 200.8±1.26µs 205.2±3.24µs 4.9 Ktx/sec 4.8 Ktx/sec
sqlite 💿 location non_unique 0 100 49.5±1.52µs 50.2±3.32µs 19.7 Ktx/sec 19.4 Ktx/sec
sqlite 💿 location non_unique 1000 100 51.6±0.28µs 52.0±0.25µs 18.9 Ktx/sec 18.8 Ktx/sec
sqlite 💿 location unique 0 100 51.3±1.53µs 50.7±2.72µs 19.0 Ktx/sec 19.2 Ktx/sec
sqlite 💿 location unique 1000 100 55.7±0.28µs 55.6±0.31µs 17.5 Ktx/sec 17.6 Ktx/sec
sqlite 💿 person multi_index 0 100 120.8±6.68µs 121.1±5.76µs 8.1 Ktx/sec 8.1 Ktx/sec
sqlite 💿 person multi_index 1000 100 236.3±1.95µs 231.9±0.35µs 4.1 Ktx/sec 4.2 Ktx/sec
sqlite 💿 person non_unique 0 100 49.9±1.54µs 50.6±1.16µs 19.6 Ktx/sec 19.3 Ktx/sec
sqlite 💿 person non_unique 1000 100 60.1±0.37µs 62.0±10.46µs 16.2 Ktx/sec 15.7 Ktx/sec
sqlite 💿 person unique 0 100 52.2±1.99µs 50.7±0.33µs 18.7 Ktx/sec 19.3 Ktx/sec
sqlite 💿 person unique 1000 100 57.4±0.44µs 56.3±0.56µs 17.0 Ktx/sec 17.3 Ktx/sec
sqlite 🧠 location multi_index 0 100 118.1±0.40µs 120.3±0.27µs 8.3 Ktx/sec 8.1 Ktx/sec
sqlite 🧠 location multi_index 1000 100 169.4±0.24µs 169.8±0.42µs 5.8 Ktx/sec 5.8 Ktx/sec
sqlite 🧠 location non_unique 0 100 43.5±0.34µs 43.2±0.46µs 22.4 Ktx/sec 22.6 Ktx/sec
sqlite 🧠 location non_unique 1000 100 44.0±0.24µs 43.4±0.26µs 22.2 Ktx/sec 22.5 Ktx/sec
sqlite 🧠 location unique 0 100 44.9±0.46µs 44.3±0.49µs 21.8 Ktx/sec 22.0 Ktx/sec
sqlite 🧠 location unique 1000 100 48.1±0.25µs 47.0±0.26µs 20.3 Ktx/sec 20.8 Ktx/sec
sqlite 🧠 person multi_index 0 100 107.4±0.24µs 109.7±0.47µs 9.1 Ktx/sec 8.9 Ktx/sec
sqlite 🧠 person multi_index 1000 100 191.1±0.50µs 190.9±0.29µs 5.1 Ktx/sec 5.1 Ktx/sec
sqlite 🧠 person non_unique 0 100 43.6±0.29µs 44.1±0.31µs 22.4 Ktx/sec 22.2 Ktx/sec
sqlite 🧠 person non_unique 1000 100 48.3±0.24µs 48.1±0.30µs 20.2 Ktx/sec 20.3 Ktx/sec
sqlite 🧠 person unique 0 100 46.2±0.38µs 44.8±0.31µs 21.1 Ktx/sec 21.8 Ktx/sec
sqlite 🧠 person unique 1000 100 49.5±0.28µs 48.4±0.30µs 19.7 Ktx/sec 20.2 Ktx/sec
stdb_module 💿 location multi_index 0 100 727.2±139.05µs 802.0±33.36µs 1375 tx/sec 1246 tx/sec
stdb_module 💿 location multi_index 1000 100 1037.8±94.64µs 1066.7±8.03µs 963 tx/sec 937 tx/sec
stdb_module 💿 location non_unique 0 100 531.2±7.86µs 426.9±93.74µs 1882 tx/sec 2.3 Ktx/sec
stdb_module 💿 location non_unique 1000 100 815.6±306.01µs 762.7±66.37µs 1226 tx/sec 1311 tx/sec
stdb_module 💿 location unique 0 100 646.2±3.50µs 678.6±8.02µs 1547 tx/sec 1473 tx/sec
stdb_module 💿 location unique 1000 100 1056.1±47.01µs 917.8±93.75µs 946 tx/sec 1089 tx/sec
stdb_module 💿 person multi_index 0 100 1116.7±187.65µs 1520.0±19.35µs 895 tx/sec 657 tx/sec
stdb_module 💿 person multi_index 1000 100 1472.8±236.34µs 1493.1±75.06µs 678 tx/sec 669 tx/sec
stdb_module 💿 person non_unique 0 100 636.1±24.25µs 636.6±28.35µs 1572 tx/sec 1570 tx/sec
stdb_module 💿 person non_unique 1000 100 917.7±38.03µs 850.9±23.67µs 1089 tx/sec 1175 tx/sec
stdb_module 💿 person unique 0 100 867.3±42.32µs 939.8±26.00µs 1152 tx/sec 1064 tx/sec
stdb_module 💿 person unique 1000 100 1021.7±108.73µs 1398.5±87.23µs 978 tx/sec 715 tx/sec
stdb_module 🧠 location multi_index 0 100 833.5±8.53µs 718.2±4.41µs 1199 tx/sec 1392 tx/sec
stdb_module 🧠 location multi_index 1000 100 1276.1±12.32µs 921.4±5.43µs 783 tx/sec 1085 tx/sec
stdb_module 🧠 location non_unique 0 100 439.0±5.87µs 420.1±2.15µs 2.2 Ktx/sec 2.3 Ktx/sec
stdb_module 🧠 location non_unique 1000 100 709.1±2.72µs 635.7±19.99µs 1410 tx/sec 1573 tx/sec
stdb_module 🧠 location unique 0 100 554.4±17.84µs 558.2±1.47µs 1803 tx/sec 1791 tx/sec
stdb_module 🧠 location unique 1000 100 924.9±23.17µs 742.0±19.45µs 1081 tx/sec 1347 tx/sec
stdb_module 🧠 person multi_index 0 100 1079.2±247.65µs 826.2±5.98µs 926 tx/sec 1210 tx/sec
stdb_module 🧠 person multi_index 1000 100 1287.6±263.43µs 1141.4±151.91µs 776 tx/sec 876 tx/sec
stdb_module 🧠 person non_unique 0 100 590.5±6.99µs 420.1±98.20µs 1693 tx/sec 2.3 Ktx/sec
stdb_module 🧠 person non_unique 1000 100 873.2±21.71µs 790.0±12.72µs 1145 tx/sec 1265 tx/sec
stdb_module 🧠 person unique 0 100 842.7±12.07µs 845.3±74.40µs 1186 tx/sec 1183 tx/sec
stdb_module 🧠 person unique 1000 100 1144.2±13.48µs 1152.4±14.87µs 874 tx/sec 867 tx/sec
stdb_raw 💿 location multi_index 0 100 381.7±2.97µs 304.8±0.38µs 2.6 Ktx/sec 3.2 Ktx/sec
stdb_raw 💿 location multi_index 1000 100 429.1±1.40µs 366.9±82.40µs 2.3 Ktx/sec 2.7 Ktx/sec
stdb_raw 💿 location non_unique 0 100 142.1±4.19µs 136.9±0.17µs 6.9 Ktx/sec 7.1 Ktx/sec
stdb_raw 💿 location non_unique 1000 100 185.0±92.56µs 171.2±110.79µs 5.3 Ktx/sec 5.7 Ktx/sec
stdb_raw 💿 location unique 0 100 206.8±1.27µs 214.4±0.33µs 4.7 Ktx/sec 4.6 Ktx/sec
stdb_raw 💿 location unique 1000 100 260.6±1.15µs 267.2±58.35µs 3.7 Ktx/sec 3.7 Ktx/sec
stdb_raw 💿 person multi_index 0 100 716.7±1.23µs 645.3±0.37µs 1395 tx/sec 1549 tx/sec
stdb_raw 💿 person multi_index 1000 100 787.9±406.56µs 698.6±2.60µs 1269 tx/sec 1431 tx/sec
stdb_raw 💿 person non_unique 0 100 198.4±9.15µs 195.0±0.24µs 4.9 Ktx/sec 5.0 Ktx/sec
stdb_raw 💿 person non_unique 1000 100 226.6±0.64µs 233.8±161.81µs 4.3 Ktx/sec 4.2 Ktx/sec
stdb_raw 💿 person unique 0 100 348.1±0.36µs 360.0±1.82µs 2.8 Ktx/sec 2.7 Ktx/sec
stdb_raw 💿 person unique 1000 100 395.4±1.09µs 426.5±258.75µs 2.5 Ktx/sec 2.3 Ktx/sec
stdb_raw 🧠 location multi_index 0 100 375.5±0.54µs 306.8±0.55µs 2.6 Ktx/sec 3.2 Ktx/sec
stdb_raw 🧠 location multi_index 1000 100 419.5±0.74µs 357.0±0.67µs 2.3 Ktx/sec 2.7 Ktx/sec
stdb_raw 🧠 location non_unique 0 100 138.5±0.18µs 135.4±0.10µs 7.0 Ktx/sec 7.2 Ktx/sec
stdb_raw 🧠 location non_unique 1000 100 167.4±0.24µs 156.8±0.46µs 5.8 Ktx/sec 6.2 Ktx/sec
stdb_raw 🧠 location unique 0 100 203.2±2.07µs 210.1±0.20µs 4.8 Ktx/sec 4.6 Ktx/sec
stdb_raw 🧠 location unique 1000 100 255.4±0.81µs 258.7±0.88µs 3.8 Ktx/sec 3.8 Ktx/sec
stdb_raw 🧠 person multi_index 0 100 707.3±0.56µs 643.1±0.58µs 1413 tx/sec 1554 tx/sec
stdb_raw 🧠 person multi_index 1000 100 736.7±1.56µs 685.6±2.01µs 1357 tx/sec 1458 tx/sec
stdb_raw 🧠 person non_unique 0 100 192.3±0.32µs 191.1±0.22µs 5.1 Ktx/sec 5.1 Ktx/sec
stdb_raw 🧠 person non_unique 1000 100 221.4±0.93µs 213.9±0.71µs 4.4 Ktx/sec 4.6 Ktx/sec
stdb_raw 🧠 person unique 0 100 339.5±0.39µs 355.9±0.28µs 2.9 Ktx/sec 2.7 Ktx/sec
stdb_raw 🧠 person unique 1000 100 392.1±0.73µs 397.9±2.29µs 2.5 Ktx/sec 2.5 Ktx/sec

Full table iterate

db on disk schema index type new latency old latency new throughput old throughput
sqlite 💿 location unique 9.0±0.20µs 9.0±0.12µs 108.0 Ktx/sec 108.6 Ktx/sec
sqlite 💿 person unique 9.5±0.16µs 9.3±0.10µs 102.3 Ktx/sec 105.5 Ktx/sec
sqlite 🧠 location unique 7.7±0.14µs 7.7±0.14µs 126.3 Ktx/sec 126.9 Ktx/sec
sqlite 🧠 person unique 8.4±0.14µs 8.2±0.12µs 115.7 Ktx/sec 119.7 Ktx/sec
stdb_module 💿 location unique 41.6±4.17µs 44.9±4.67µs 23.5 Ktx/sec 21.7 Ktx/sec
stdb_module 💿 person unique 60.9±5.06µs 55.0±10.15µs 16.0 Ktx/sec 17.8 Ktx/sec
stdb_module 🧠 location unique 41.2±2.88µs 46.0±3.32µs 23.7 Ktx/sec 21.2 Ktx/sec
stdb_module 🧠 person unique 59.9±7.33µs 60.1±7.36µs 16.3 Ktx/sec 16.3 Ktx/sec
stdb_raw 💿 location unique 10.7±0.01µs 10.5±0.09µs 90.9 Ktx/sec 93.2 Ktx/sec
stdb_raw 💿 person unique 12.2±0.02µs 12.2±0.01µs 79.9 Ktx/sec 80.3 Ktx/sec
stdb_raw 🧠 location unique 10.8±0.09µs 10.4±0.05µs 90.7 Ktx/sec 93.5 Ktx/sec
stdb_raw 🧠 person unique 12.5±0.01µs 12.2±0.02µs 78.2 Ktx/sec 80.3 Ktx/sec

Find unique key

db on disk key type load new latency old latency new throughput old throughput
sqlite 💿 u32 1000 2.4±0.01µs 2.4±0.01µs 402.6 Ktx/sec 405.5 Ktx/sec
sqlite 🧠 u32 1000 1165.3±6.15ns 1176.1±9.94ns 838.0 Ktx/sec 830.4 Ktx/sec
stdb_module 💿 u32 1000 18.3±0.89µs 18.8±1.42µs 53.4 Ktx/sec 52.0 Ktx/sec
stdb_module 🧠 u32 1000 18.3±0.94µs 18.5±1.10µs 53.3 Ktx/sec 52.9 Ktx/sec
stdb_raw 💿 u32 1000 478.0±0.61ns 491.2±1.21ns 2043.1 Ktx/sec 1988.1 Ktx/sec
stdb_raw 🧠 u32 1000 477.7±0.86ns 485.1±1.01ns 2044.5 Ktx/sec 2013.1 Ktx/sec

Filter

db on disk key type index strategy load count new latency old latency new throughput old throughput
sqlite 💿 string indexed 1000 10 5.8±0.02µs 5.7±0.02µs 169.0 Ktx/sec 172.1 Ktx/sec
sqlite 💿 string non_indexed 1000 10 48.9±0.39µs 49.9±0.61µs 20.0 Ktx/sec 19.6 Ktx/sec
sqlite 💿 u64 indexed 1000 10 5.5±0.02µs 5.5±0.01µs 176.5 Ktx/sec 178.3 Ktx/sec
sqlite 💿 u64 non_indexed 1000 10 33.1±0.11µs 34.1±0.09µs 29.5 Ktx/sec 28.6 Ktx/sec
sqlite 🧠 string indexed 1000 10 4.3±0.04µs 4.2±0.01µs 225.4 Ktx/sec 231.4 Ktx/sec
sqlite 🧠 string non_indexed 1000 10 47.3±0.40µs 48.3±0.42µs 20.6 Ktx/sec 20.2 Ktx/sec
sqlite 🧠 u64 indexed 1000 10 4.1±0.02µs 4.1±0.02µs 237.9 Ktx/sec 240.9 Ktx/sec
sqlite 🧠 u64 non_indexed 1000 10 31.8±0.10µs 31.8±0.09µs 30.7 Ktx/sec 30.7 Ktx/sec
stdb_module 💿 string indexed 1000 10 24.8±2.47µs 26.4±2.70µs 39.4 Ktx/sec 37.0 Ktx/sec
stdb_module 💿 string non_indexed 1000 10 195.5±2.12µs 190.1±2.91µs 5.0 Ktx/sec 5.1 Ktx/sec
stdb_module 💿 u64 indexed 1000 10 22.4±1.72µs 21.1±0.98µs 43.7 Ktx/sec 46.2 Ktx/sec
stdb_module 💿 u64 non_indexed 1000 10 145.7±3.81µs 165.6±6.51µs 6.7 Ktx/sec 5.9 Ktx/sec
stdb_module 🧠 string indexed 1000 10 23.6±2.15µs 25.9±2.46µs 41.4 Ktx/sec 37.8 Ktx/sec
stdb_module 🧠 string non_indexed 1000 10 190.7±0.87µs 187.4±4.32µs 5.1 Ktx/sec 5.2 Ktx/sec
stdb_module 🧠 u64 indexed 1000 10 21.0±1.06µs 21.1±1.04µs 46.4 Ktx/sec 46.2 Ktx/sec
stdb_module 🧠 u64 non_indexed 1000 10 144.6±1.18µs 158.1±4.72µs 6.8 Ktx/sec 6.2 Ktx/sec
stdb_raw 💿 string indexed 1000 10 2.2±0.00µs 2.6±0.00µs 435.4 Ktx/sec 371.5 Ktx/sec
stdb_raw 💿 string non_indexed 1000 10 161.6±0.50µs 173.2±0.73µs 6.0 Ktx/sec 5.6 Ktx/sec
stdb_raw 💿 u64 indexed 1000 10 2.2±0.01µs 2.2±0.01µs 441.7 Ktx/sec 439.0 Ktx/sec
stdb_raw 💿 u64 non_indexed 1000 10 113.6±0.32µs 135.7±1.88µs 8.6 Ktx/sec 7.2 Ktx/sec
stdb_raw 🧠 string indexed 1000 10 2.3±0.00µs 2.6±0.00µs 433.9 Ktx/sec 372.0 Ktx/sec
stdb_raw 🧠 string non_indexed 1000 10 162.7±0.29µs 172.8±0.56µs 6.0 Ktx/sec 5.7 Ktx/sec
stdb_raw 🧠 u64 indexed 1000 10 2.3±0.02µs 2.2±0.00µs 433.9 Ktx/sec 437.9 Ktx/sec
stdb_raw 🧠 u64 non_indexed 1000 10 113.9±0.19µs 135.0±0.35µs 8.6 Ktx/sec 7.2 Ktx/sec

Serialize

schema format count new latency old latency new throughput old throughput
location bsatn 100 1891.6±30.55ns 1659.9±116.77ns 50.4 Mtx/sec 57.5 Mtx/sec
location json 100 3.2±0.07µs 3.2±0.09µs 29.6 Mtx/sec 29.5 Mtx/sec
location product_value 100 2.4±0.02µs 2.5±0.01µs 39.6 Mtx/sec 38.4 Mtx/sec
person bsatn 100 2.6±0.02µs 2.4±0.01µs 36.5 Mtx/sec 38.9 Mtx/sec
person json 100 4.9±0.04µs 4.9±0.04µs 19.5 Mtx/sec 19.4 Mtx/sec
person product_value 100 1611.8±4.75ns 1615.2±6.59ns 59.2 Mtx/sec 59.0 Mtx/sec

Module: invoke with large arguments

arg size new latency old latency new throughput old throughput
64KiB 79.1±4.35µs 92.2±9.90µs - -

Module: print bulk

line count new latency old latency new throughput old throughput
1 20.2±0.83µs 20.7±1.30µs - -
100 201.6±0.78µs 200.8±1.68µs - -
1000 1924.8±72.54µs 1815.2±7.83µs - -

Remaining benchmarks

name new latency old latency new throughput old throughput

Please sign in to comment.