Skip to content

Commit

Permalink
perf(461): Record metrics for rows [inserted|deleted] on commit (#462)
Browse files Browse the repository at this point in the history
Closes #456.
Closes #461.

Define an execution context for database operations.
Store the database id in RelationalDB.
Record metrics for rows [inserted|deleted] on commit.
  • Loading branch information
joshua-spacetime authored Oct 25, 2023
1 parent cb32c83 commit 23b2e6c
Show file tree
Hide file tree
Showing 14 changed files with 245 additions and 63 deletions.
24 changes: 14 additions & 10 deletions crates/bench/src/spacetime_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ use crate::{
schemas::{table_name, BenchTable, IndexStrategy},
ResultBench,
};
use spacetimedb::db::datastore::traits::{IndexDef, TableDef};
use spacetimedb::db::relational_db::{open_db, RelationalDB};
use spacetimedb::{
db::datastore::traits::{IndexDef, TableDef},
execution_context::ExecutionContext,
};
use spacetimedb_lib::sats::AlgebraicValue;
use spacetimedb_primitives::{ColId, TableId};
use std::hint::black_box;
Expand Down Expand Up @@ -38,7 +41,7 @@ impl BenchDatabase for SpacetimeRaw {

fn create_table<T: BenchTable>(&mut self, index_strategy: IndexStrategy) -> ResultBench<Self::TableId> {
let name = table_name::<T>(index_strategy);
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
let table_def = TableDef::from(T::product_type());
let table_id = self.db.create_table(tx, table_def)?;
self.db.rename_table(tx, table_id, &name)?;
Expand All @@ -63,30 +66,31 @@ impl BenchDatabase for SpacetimeRaw {
}

fn clear_table(&mut self, table_id: &Self::TableId) -> ResultBench<()> {
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
self.db.clear_table(tx, *table_id)?;
Ok(())
})
}

fn count_table(&mut self, table_id: &Self::TableId) -> ResultBench<u32> {
self.db
.with_auto_commit(|tx| Ok(self.db.iter(tx, *table_id)?.map(|_| 1u32).sum()))
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
Ok(self.db.iter(tx, *table_id)?.map(|_| 1u32).sum())
})
}

fn empty_transaction(&mut self) -> ResultBench<()> {
self.db.with_auto_commit(|_tx| Ok(()))
self.db.with_auto_commit(&ExecutionContext::default(), |_tx| Ok(()))
}

fn insert<T: BenchTable>(&mut self, table_id: &Self::TableId, row: T) -> ResultBench<()> {
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
self.db.insert(tx, *table_id, row.into_product_value())?;
Ok(())
})
}

fn insert_bulk<T: BenchTable>(&mut self, table_id: &Self::TableId, rows: Vec<T>) -> ResultBench<()> {
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
for row in rows {
self.db.insert(tx, *table_id, row.into_product_value())?;
}
Expand All @@ -95,7 +99,7 @@ impl BenchDatabase for SpacetimeRaw {
}

fn iterate(&mut self, table_id: &Self::TableId) -> ResultBench<()> {
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
for row in self.db.iter(tx, *table_id)? {
black_box(row);
}
Expand All @@ -110,7 +114,7 @@ impl BenchDatabase for SpacetimeRaw {
value: AlgebraicValue,
) -> ResultBench<()> {
let col: ColId = column_index.into();
self.db.with_auto_commit(|tx| {
self.db.with_auto_commit(&ExecutionContext::default(), |tx| {
for row in self.db.iter_by_col_eq(tx, *table_id, col, value)? {
black_box(row);
}
Expand Down
10 changes: 9 additions & 1 deletion crates/core/src/database_instance_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,15 @@ impl DatabaseInstanceContext {
address,
logger: Arc::new(Mutex::new(DatabaseLogger::open(log_path))),
relational_db: Arc::new(
RelationalDB::open(db_path, message_log, odb, address, config.fsync != FsyncPolicy::Never).unwrap(),
RelationalDB::open(
db_path,
message_log,
odb,
database_id,
address,
config.fsync != FsyncPolicy::Never,
)
.unwrap(),
),
publisher_address,
})
Expand Down
66 changes: 53 additions & 13 deletions crates/core/src/db/commit_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ use super::{
use crate::{
db::{
datastore::{locking_tx_datastore::RowId, traits::TxOp},
db_metrics::DB_METRICS,
messages::{
transaction::Transaction,
write::{Operation, Write},
},
},
error::DBError,
execution_context::ExecutionContext,
};

use anyhow::Context;
Expand Down Expand Up @@ -52,13 +54,18 @@ impl CommitLog {
///
/// Returns `Some(n_bytes_written)` if `commit_result` was persisted, `None` if it doesn't have bytes to write.
#[tracing::instrument(skip_all)]
pub fn append_tx<D>(&self, tx_data: &TxData, datastore: &D) -> Result<Option<usize>, DBError>
pub fn append_tx<D>(
&self,
ctx: &ExecutionContext,
tx_data: &TxData,
datastore: &D,
) -> Result<Option<usize>, DBError>
where
D: MutTxDatastore<RowId = RowId>,
{
if let Some(mlog) = &self.mlog {
let mut mlog = mlog.lock().unwrap();
self.generate_commit(tx_data, datastore)
self.generate_commit(ctx, tx_data, datastore)
.as_deref()
.map(|bytes| self.append_commit_bytes(&mut mlog, bytes))
.transpose()
Expand Down Expand Up @@ -88,7 +95,12 @@ impl CommitLog {
Ok(commit.len())
}

fn generate_commit<D: MutTxDatastore<RowId = RowId>>(&self, tx_data: &TxData, _datastore: &D) -> Option<Vec<u8>> {
fn generate_commit<D: MutTxDatastore<RowId = RowId>>(
&self,
ctx: &ExecutionContext,
tx_data: &TxData,
_datastore: &D,
) -> Option<Vec<u8>> {
// We are not creating a commit for empty transactions.
// The reason for this is that empty transactions get encoded as 0 bytes,
// so a commit containing an empty transaction contains no useful information.
Expand All @@ -97,18 +109,46 @@ impl CommitLog {
}

let mut unwritten_commit = self.unwritten_commit.lock().unwrap();
let writes = tx_data
.records
.iter()
.map(|record| Write {
operation: match record.op {
TxOp::Insert(_) => Operation::Insert,
TxOp::Delete => Operation::Delete,
},
set_id: record.table_id.0,
let mut writes = Vec::with_capacity(tx_data.records.len());

let rows_inserted = &DB_METRICS.rdb_num_rows_inserted;
let rows_deleted = &DB_METRICS.rdb_num_rows_deleted;

for record in &tx_data.records {
let table_id: u32 = record.table_id.into();

let operation = match record.op {
TxOp::Insert(_) => {
// Increment rows inserted metric
let metric = rows_inserted.with_label_values(
&ctx.txn_type(),
&ctx.database_id(),
&ctx.reducer_id().unwrap_or(0),
&table_id,
);
metric.inc();
Operation::Insert
}
TxOp::Delete => {
// Increment rows deleted metric
let metric = rows_deleted.with_label_values(
&ctx.txn_type(),
&ctx.database_id(),
&ctx.reducer_id().unwrap_or(0),
&table_id,
);
metric.inc();
Operation::Delete
}
};

writes.push(Write {
operation,
set_id: table_id,
data_key: record.key,
})
.collect();
}

let transaction = Transaction { writes };
unwritten_commit.transactions.push(Arc::new(transaction));

Expand Down
14 changes: 12 additions & 2 deletions crates/core/src/db/db_metrics/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::util::typed_prometheus::metrics_group;
use crate::{execution_context::TransactionType, util::typed_prometheus::metrics_group};
use once_cell::sync::Lazy;
use prometheus::{Histogram, HistogramVec};
use prometheus::{Histogram, HistogramVec, IntCounterVec};

metrics_group!(
#[non_exhaustive]
Expand Down Expand Up @@ -49,6 +49,16 @@ metrics_group!(
#[help = "The time spent deleting values in a set from a table"]
#[labels(table_id: u32)]
pub rdb_delete_by_rel_time: HistogramVec,

#[name = spacetime_num_rows_inserted]
#[help = "The number of rows inserted into a table"]
#[labels(txn_type: TransactionType, database_id: u64, reducer_id: u64, table_id: u32)]
pub rdb_num_rows_inserted: IntCounterVec,

#[name = spacetime_num_rows_deleted]
#[help = "The number of rows deleted from a table"]
#[labels(txn_type: TransactionType, database_id: u64, reducer_id: u64, table_id: u32)]
pub rdb_num_rows_deleted: IntCounterVec,
}
);

Expand Down
38 changes: 24 additions & 14 deletions crates/core/src/db/relational_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::db::messages::commit::Commit;
use crate::db::ostorage::hashmap_object_db::HashMapObjectDB;
use crate::db::ostorage::ObjectDB;
use crate::error::{DBError, DatabaseError, IndexError, TableError};
use crate::execution_context::ExecutionContext;
use crate::hash::Hash;
use fs2::FileExt;
use nonempty::NonEmpty;
Expand Down Expand Up @@ -44,6 +45,7 @@ pub struct RelationalDB {
pub(crate) inner: Locking,
commit_log: CommitLog,
_lock: Arc<File>,
id: u64,
}

impl DataRow for RelationalDB {
Expand All @@ -66,6 +68,7 @@ impl RelationalDB {
root: impl AsRef<Path>,
message_log: Option<Arc<Mutex<MessageLog>>>,
odb: Arc<Mutex<Box<dyn ObjectDB + Send>>>,
id: u64,
address: Address,
fsync: bool,
) -> Result<Self, DBError> {
Expand Down Expand Up @@ -159,12 +162,18 @@ impl RelationalDB {
inner: datastore,
commit_log,
_lock: Arc::new(lock),
id,
};

log::trace!("[{}] DATABASE: OPENED", address);
Ok(db)
}

/// Returns the id for this database
pub fn id(&self) -> u64 {
self.id
}

/// Obtain a read-only view of this database's [`CommitLog`].
pub fn commit_log(&self) -> CommitLogView {
CommitLogView::from(&self.commit_log)
Expand Down Expand Up @@ -259,10 +268,10 @@ impl RelationalDB {
}

#[tracing::instrument(skip_all)]
pub fn commit_tx(&self, tx: MutTxId) -> Result<Option<(TxData, Option<usize>)>, DBError> {
pub fn commit_tx(&self, ctx: &ExecutionContext, tx: MutTxId) -> Result<Option<(TxData, Option<usize>)>, DBError> {
log::trace!("COMMIT TX");
if let Some(tx_data) = self.inner.commit_mut_tx(tx)? {
let bytes_written = self.commit_log.append_tx(&tx_data, &self.inner)?;
let bytes_written = self.commit_log.append_tx(ctx, &tx_data, &self.inner)?;
return Ok(Some((tx_data, bytes_written)));
}
Ok(None)
Expand Down Expand Up @@ -296,14 +305,14 @@ impl RelationalDB {
/// Ok(())
/// })?;
/// ```
pub fn with_auto_commit<F, A, E>(&self, f: F) -> Result<A, E>
pub fn with_auto_commit<F, A, E>(&self, ctx: &ExecutionContext, f: F) -> Result<A, E>
where
F: FnOnce(&mut MutTxId) -> Result<A, E>,
E: From<DBError>,
{
let mut tx = self.begin_tx();
let res = f(&mut tx);
self.finish_tx(tx, res)
self.finish_tx(ctx, tx, res)
}

/// Run a fallible function in a transaction, rolling it back if the
Expand Down Expand Up @@ -343,14 +352,14 @@ impl RelationalDB {

/// Perform the transactional logic for the `tx` according to the `res`
#[tracing::instrument(skip_all)]
pub fn finish_tx<A, E>(&self, tx: MutTxId, res: Result<A, E>) -> Result<A, E>
pub fn finish_tx<A, E>(&self, ctx: &ExecutionContext, tx: MutTxId, res: Result<A, E>) -> Result<A, E>
where
E: From<DBError>,
{
if res.is_err() {
self.rollback_tx(tx);
} else {
match self.commit_tx(tx).map_err(E::from)? {
match self.commit_tx(ctx, tx).map_err(E::from)? {
Some(_) => (),
None => panic!("TODO: retry?"),
}
Expand Down Expand Up @@ -613,7 +622,7 @@ pub fn open_db(path: impl AsRef<Path>, in_memory: bool, fsync: bool) -> Result<R
Some(Arc::new(Mutex::new(MessageLog::open(path.join("mlog"))?)))
};
let odb = Arc::new(Mutex::new(make_default_ostorage(in_memory, path.join("odb"))?));
let stdb = RelationalDB::open(path, mlog, odb, Address::zero(), fsync)?;
let stdb = RelationalDB::open(path, mlog, odb, 0, Address::zero(), fsync)?;

Ok(stdb)
}
Expand Down Expand Up @@ -658,6 +667,7 @@ mod tests {
use crate::db::datastore::traits::TableDef;
use crate::db::message_log::MessageLog;
use crate::db::relational_db::{open_db, ST_TABLES_ID};
use crate::execution_context::ExecutionContext;

use super::RelationalDB;
use crate::db::relational_db::make_default_ostorage;
Expand Down Expand Up @@ -704,7 +714,7 @@ mod tests {
let mut schema = TableDef::from(ProductType::from([("my_col", AlgebraicType::I32)]));
schema.table_name = "MyTable".to_string();
stdb.create_table(&mut tx, schema)?;
stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;

Ok(())
}
Expand All @@ -719,7 +729,7 @@ mod tests {
schema.table_name = "MyTable".to_string();
stdb.create_table(&mut tx, schema)?;

stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;

let mlog = Some(Arc::new(Mutex::new(MessageLog::open(tmp_dir.path().join("mlog"))?)));
let in_memory = false;
Expand All @@ -728,7 +738,7 @@ mod tests {
tmp_dir.path().join("odb"),
)?));

match RelationalDB::open(tmp_dir.path(), mlog, odb, Address::zero(), true) {
match RelationalDB::open(tmp_dir.path(), mlog, odb, 0, Address::zero(), true) {
Ok(_) => {
panic!("Allowed to open database twice")
}
Expand Down Expand Up @@ -821,7 +831,7 @@ mod tests {
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(-1)])?;
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(0)])?;
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(1)])?;
stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;

let tx = stdb.begin_tx();
let mut rows = stdb
Expand Down Expand Up @@ -871,7 +881,7 @@ mod tests {
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(-1)])?;
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(0)])?;
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(1)])?;
stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;

let tx = stdb.begin_tx();
let mut rows = stdb
Expand Down Expand Up @@ -910,7 +920,7 @@ mod tests {
let mut schema = TableDef::from(ProductType::from([("my_col", AlgebraicType::I32)]));
schema.table_name = "MyTable".to_string();
let table_id = stdb.create_table(&mut tx, schema)?;
stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;

let mut tx = stdb.begin_tx();
stdb.insert(&mut tx, table_id, product![AlgebraicValue::I32(-1)])?;
Expand Down Expand Up @@ -1031,7 +1041,7 @@ mod tests {

assert_eq!(rows, vec![1]);

stdb.commit_tx(tx)?;
stdb.commit_tx(&ExecutionContext::default(), tx)?;
drop(stdb);

dbg!("reopen...");
Expand Down
Loading

1 comment on commit 23b2e6c

@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 💿 451.0±3.28ns 435.1±2.41ns - -
sqlite 🧠 446.2±1.48ns 428.2±1.34ns - -
stdb_module 💿 16.1±0.47µs 16.3±0.54µs - -
stdb_module 🧠 16.3±0.56µs 16.6±0.39µs - -
stdb_raw 💿 195.4±1.59ns 192.3±0.43ns - -
stdb_raw 🧠 192.7±0.54ns 189.1±0.28ns - -

Single-row insertions

db on disk schema index type load new latency old latency new throughput old throughput
sqlite 💿 location multi_index 0 14.7±0.08µs 14.5±0.04µs 66.5 Ktx/sec 67.5 Ktx/sec
sqlite 💿 location multi_index 1000 15.9±0.35µs 15.6±0.10µs 61.4 Ktx/sec 62.6 Ktx/sec
sqlite 💿 location non_unique 0 7.2±0.03µs 7.1±0.06µs 135.8 Ktx/sec 137.5 Ktx/sec
sqlite 💿 location non_unique 1000 7.1±0.04µs 7.0±0.03µs 137.6 Ktx/sec 139.2 Ktx/sec
sqlite 💿 location unique 0 7.1±0.03µs 7.1±0.03µs 136.8 Ktx/sec 137.7 Ktx/sec
sqlite 💿 location unique 1000 7.2±0.07µs 7.0±0.03µs 136.1 Ktx/sec 139.6 Ktx/sec
sqlite 💿 person multi_index 0 14.2±0.06µs 14.2±0.06µs 68.6 Ktx/sec 68.7 Ktx/sec
sqlite 💿 person multi_index 1000 16.4±0.15µs 16.0±0.15µs 59.7 Ktx/sec 60.9 Ktx/sec
sqlite 💿 person non_unique 0 7.3±0.45µs 7.3±0.58µs 133.1 Ktx/sec 134.6 Ktx/sec
sqlite 💿 person non_unique 1000 7.3±0.04µs 7.2±0.03µs 133.5 Ktx/sec 136.5 Ktx/sec
sqlite 💿 person unique 0 7.3±0.03µs 7.2±0.45µs 134.2 Ktx/sec 135.0 Ktx/sec
sqlite 💿 person unique 1000 7.4±0.06µs 7.2±0.06µs 132.5 Ktx/sec 136.0 Ktx/sec
sqlite 🧠 location multi_index 0 4.0±0.02µs 4.0±0.02µs 242.6 Ktx/sec 242.7 Ktx/sec
sqlite 🧠 location multi_index 1000 5.1±0.05µs 5.2±0.02µs 190.8 Ktx/sec 187.2 Ktx/sec
sqlite 🧠 location non_unique 0 1879.9±5.15ns 1865.6±6.62ns 519.5 Ktx/sec 523.5 Ktx/sec
sqlite 🧠 location non_unique 1000 1939.9±18.56ns 1911.5±16.17ns 503.4 Ktx/sec 510.9 Ktx/sec
sqlite 🧠 location unique 0 1852.6±7.44ns 1852.8±5.06ns 527.1 Ktx/sec 527.1 Ktx/sec
sqlite 🧠 location unique 1000 1990.9±10.72ns 1959.5±12.18ns 490.5 Ktx/sec 498.4 Ktx/sec
sqlite 🧠 person multi_index 0 3.7±0.01µs 3.7±0.01µs 265.1 Ktx/sec 263.9 Ktx/sec
sqlite 🧠 person multi_index 1000 5.4±0.04µs 5.4±0.03µs 181.8 Ktx/sec 180.3 Ktx/sec
sqlite 🧠 person non_unique 0 1940.8±8.10ns 1954.4±6.90ns 503.2 Ktx/sec 499.7 Ktx/sec
sqlite 🧠 person non_unique 1000 2.0±0.01µs 2.0±0.02µs 480.0 Ktx/sec 481.8 Ktx/sec
sqlite 🧠 person unique 0 1937.5±4.68ns 1923.1±20.79ns 504.0 Ktx/sec 507.8 Ktx/sec
sqlite 🧠 person unique 1000 2.1±0.01µs 2.0±0.01µs 470.7 Ktx/sec 479.4 Ktx/sec
stdb_module 💿 location multi_index 0 41.0±5.48µs 46.0±3.57µs 23.8 Ktx/sec 21.2 Ktx/sec
stdb_module 💿 location multi_index 1000 135.1±29.25µs 136.7±2.63µs 7.2 Ktx/sec 7.1 Ktx/sec
stdb_module 💿 location non_unique 0 35.2±3.55µs 35.8±3.56µs 27.8 Ktx/sec 27.3 Ktx/sec
stdb_module 💿 location non_unique 1000 271.8±13.62µs 107.4±24.98µs 3.6 Ktx/sec 9.1 Ktx/sec
stdb_module 💿 location unique 0 43.3±5.38µs 43.4±4.34µs 22.6 Ktx/sec 22.5 Ktx/sec
stdb_module 💿 location unique 1000 248.8±3.21µs 219.0±51.18µs 3.9 Ktx/sec 4.5 Ktx/sec
stdb_module 💿 person multi_index 0 52.3±6.55µs 50.8±4.40µs 18.7 Ktx/sec 19.2 Ktx/sec
stdb_module 💿 person multi_index 1000 186.7±28.30µs 194.3±22.11µs 5.2 Ktx/sec 5.0 Ktx/sec
stdb_module 💿 person non_unique 0 39.4±4.32µs 39.8±4.64µs 24.8 Ktx/sec 24.5 Ktx/sec
stdb_module 💿 person non_unique 1000 168.4±26.53µs 181.5±23.61µs 5.8 Ktx/sec 5.4 Ktx/sec
stdb_module 💿 person unique 0 48.5±3.84µs 46.5±6.95µs 20.1 Ktx/sec 21.0 Ktx/sec
stdb_module 💿 person unique 1000 163.3±10.67µs 88.9±51.19µs 6.0 Ktx/sec 11.0 Ktx/sec
stdb_module 🧠 location multi_index 0 30.8±3.19µs 30.6±2.24µs 31.8 Ktx/sec 31.9 Ktx/sec
stdb_module 🧠 location multi_index 1000 112.7±17.92µs 154.5±29.67µs 8.7 Ktx/sec 6.3 Ktx/sec
stdb_module 🧠 location non_unique 0 26.5±2.27µs 25.5±1.62µs 36.9 Ktx/sec 38.3 Ktx/sec
stdb_module 🧠 location non_unique 1000 152.1±21.56µs 127.9±6.48µs 6.4 Ktx/sec 7.6 Ktx/sec
stdb_module 🧠 location unique 0 28.7±2.21µs 28.6±2.17µs 34.0 Ktx/sec 34.1 Ktx/sec
stdb_module 🧠 location unique 1000 135.8±11.61µs 127.5±10.62µs 7.2 Ktx/sec 7.7 Ktx/sec
stdb_module 🧠 person multi_index 0 38.7±4.02µs 36.6±2.94µs 25.2 Ktx/sec 26.7 Ktx/sec
stdb_module 🧠 person multi_index 1000 110.6±9.14µs 275.4±7.46µs 8.8 Ktx/sec 3.5 Ktx/sec
stdb_module 🧠 person non_unique 0 28.3±2.20µs 27.5±2.20µs 34.5 Ktx/sec 35.5 Ktx/sec
stdb_module 🧠 person non_unique 1000 167.1±9.48µs 284.7±19.71µs 5.8 Ktx/sec 3.4 Ktx/sec
stdb_module 🧠 person unique 0 34.4±3.30µs 30.5±2.87µs 28.4 Ktx/sec 32.0 Ktx/sec
stdb_module 🧠 person unique 1000 236.8±16.54µs 251.8±6.99µs 4.1 Ktx/sec 3.9 Ktx/sec
stdb_raw 💿 location multi_index 0 6.4±0.02µs 6.3±0.02µs 151.7 Ktx/sec 155.4 Ktx/sec
stdb_raw 💿 location multi_index 1000 9.1±0.17µs 35.7±268.82µs 107.8 Ktx/sec 27.4 Ktx/sec
stdb_raw 💿 location non_unique 0 4.1±0.01µs 4.0±0.05µs 235.9 Ktx/sec 246.7 Ktx/sec
stdb_raw 💿 location non_unique 1000 5.4±0.16µs 16.5±112.12µs 180.5 Ktx/sec 59.3 Ktx/sec
stdb_raw 💿 location unique 0 5.5±0.05µs 5.3±0.02µs 179.0 Ktx/sec 184.2 Ktx/sec
stdb_raw 💿 location unique 1000 7.7±0.15µs 25.3±177.54µs 126.8 Ktx/sec 38.6 Ktx/sec
stdb_raw 💿 person multi_index 0 10.2±0.33µs 10.0±0.12µs 96.0 Ktx/sec 97.7 Ktx/sec
stdb_raw 💿 person multi_index 1000 48.5±352.29µs 54.2±411.62µs 20.1 Ktx/sec 18.0 Ktx/sec
stdb_raw 💿 person non_unique 0 4.7±0.02µs 4.5±0.01µs 209.0 Ktx/sec 217.3 Ktx/sec
stdb_raw 💿 person non_unique 1000 6.3±0.08µs 6.2±0.07µs 156.2 Ktx/sec 157.1 Ktx/sec
stdb_raw 💿 person unique 0 7.0±0.24µs 6.8±0.01µs 139.3 Ktx/sec 142.8 Ktx/sec
stdb_raw 💿 person unique 1000 9.6±0.15µs 9.5±0.11µs 102.0 Ktx/sec 103.0 Ktx/sec
stdb_raw 🧠 location multi_index 0 3.7±0.01µs 3.6±0.01µs 267.2 Ktx/sec 268.4 Ktx/sec
stdb_raw 🧠 location multi_index 1000 5.1±0.04µs 5.1±0.03µs 190.9 Ktx/sec 191.4 Ktx/sec
stdb_raw 🧠 location non_unique 0 1381.6±3.75ns 1399.8±5.61ns 706.8 Ktx/sec 697.6 Ktx/sec
stdb_raw 🧠 location non_unique 1000 1826.4±13.94ns 1928.9±24.57ns 534.7 Ktx/sec 506.3 Ktx/sec
stdb_raw 🧠 location unique 0 2.6±0.00µs 2.6±0.01µs 369.1 Ktx/sec 370.6 Ktx/sec
stdb_raw 🧠 location unique 1000 3.8±0.02µs 3.9±0.02µs 259.0 Ktx/sec 250.3 Ktx/sec
stdb_raw 🧠 person multi_index 0 7.3±0.08µs 7.3±0.01µs 134.0 Ktx/sec 134.6 Ktx/sec
stdb_raw 🧠 person multi_index 1000 9.3±0.07µs 9.3±0.11µs 105.5 Ktx/sec 105.0 Ktx/sec
stdb_raw 🧠 person non_unique 0 1937.4±18.58ns 1964.0±6.80ns 504.1 Ktx/sec 497.2 Ktx/sec
stdb_raw 🧠 person non_unique 1000 2.6±0.04µs 2.6±0.02µs 380.7 Ktx/sec 372.6 Ktx/sec
stdb_raw 🧠 person unique 0 4.2±0.01µs 4.2±0.01µs 230.1 Ktx/sec 232.3 Ktx/sec
stdb_raw 🧠 person unique 1000 5.5±0.05µs 5.6±0.05µs 176.3 Ktx/sec 174.0 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 129.5±0.33µs 132.3±3.47µs 7.5 Ktx/sec 7.4 Ktx/sec
sqlite 💿 location multi_index 1000 100 201.7±1.33µs 203.5±1.54µs 4.8 Ktx/sec 4.8 Ktx/sec
sqlite 💿 location non_unique 0 100 49.6±1.14µs 51.5±1.27µs 19.7 Ktx/sec 19.0 Ktx/sec
sqlite 💿 location non_unique 1000 100 53.1±0.34µs 54.2±0.63µs 18.4 Ktx/sec 18.0 Ktx/sec
sqlite 💿 location unique 0 100 51.7±0.99µs 52.0±0.98µs 18.9 Ktx/sec 18.8 Ktx/sec
sqlite 💿 location unique 1000 100 56.7±0.48µs 57.3±0.55µs 17.2 Ktx/sec 17.0 Ktx/sec
sqlite 💿 person multi_index 0 100 117.5±0.37µs 117.7±3.50µs 8.3 Ktx/sec 8.3 Ktx/sec
sqlite 💿 person multi_index 1000 100 236.0±2.95µs 237.4±25.71µs 4.1 Ktx/sec 4.1 Ktx/sec
sqlite 💿 person non_unique 0 100 49.1±1.13µs 49.0±1.36µs 19.9 Ktx/sec 19.9 Ktx/sec
sqlite 💿 person non_unique 1000 100 59.9±0.37µs 59.4±0.25µs 16.3 Ktx/sec 16.4 Ktx/sec
sqlite 💿 person unique 0 100 50.6±0.94µs 49.8±1.03µs 19.3 Ktx/sec 19.6 Ktx/sec
sqlite 💿 person unique 1000 100 55.1±0.34µs 55.6±0.39µs 17.7 Ktx/sec 17.6 Ktx/sec
sqlite 🧠 location multi_index 0 100 117.5±0.21µs 119.3±1.24µs 8.3 Ktx/sec 8.2 Ktx/sec
sqlite 🧠 location multi_index 1000 100 168.3±0.27µs 170.1±0.56µs 5.8 Ktx/sec 5.7 Ktx/sec
sqlite 🧠 location non_unique 0 100 42.8±0.29µs 43.4±0.51µs 22.8 Ktx/sec 22.5 Ktx/sec
sqlite 🧠 location non_unique 1000 100 43.9±0.38µs 45.6±0.54µs 22.3 Ktx/sec 21.4 Ktx/sec
sqlite 🧠 location unique 0 100 43.5±0.46µs 45.4±0.62µs 22.5 Ktx/sec 21.5 Ktx/sec
sqlite 🧠 location unique 1000 100 48.4±0.42µs 49.3±0.32µs 20.2 Ktx/sec 19.8 Ktx/sec
sqlite 🧠 person multi_index 0 100 105.1±0.56µs 105.2±0.34µs 9.3 Ktx/sec 9.3 Ktx/sec
sqlite 🧠 person multi_index 1000 100 187.0±0.40µs 187.9±0.37µs 5.2 Ktx/sec 5.2 Ktx/sec
sqlite 🧠 person non_unique 0 100 41.2±0.60µs 42.3±0.45µs 23.7 Ktx/sec 23.1 Ktx/sec
sqlite 🧠 person non_unique 1000 100 44.8±0.52µs 45.5±0.34µs 21.8 Ktx/sec 21.4 Ktx/sec
sqlite 🧠 person unique 0 100 42.8±0.33µs 43.8±0.52µs 22.8 Ktx/sec 22.3 Ktx/sec
sqlite 🧠 person unique 1000 100 46.8±0.48µs 48.3±0.31µs 20.8 Ktx/sec 20.2 Ktx/sec
stdb_module 💿 location multi_index 0 100 733.9±156.07µs 670.6±108.60µs 1362 tx/sec 1491 tx/sec
stdb_module 💿 location multi_index 1000 100 1226.6±11.65µs 755.5±122.29µs 815 tx/sec 1323 tx/sec
stdb_module 💿 location non_unique 0 100 376.2±1.22µs 484.7±70.35µs 2.6 Ktx/sec 2.0 Ktx/sec
stdb_module 💿 location non_unique 1000 100 749.1±34.29µs 392.0±1.87µs 1334 tx/sec 2.5 Ktx/sec
stdb_module 💿 location unique 0 100 653.8±50.17µs 440.3±28.71µs 1529 tx/sec 2.2 Ktx/sec
stdb_module 💿 location unique 1000 100 805.6±123.92µs 501.5±17.03µs 1241 tx/sec 1993 tx/sec
stdb_module 💿 person multi_index 0 100 1052.6±63.26µs 1097.0±454.45µs 950 tx/sec 911 tx/sec
stdb_module 💿 person multi_index 1000 100 1127.9±76.29µs 1252.7±13.49µs 886 tx/sec 798 tx/sec
stdb_module 💿 person non_unique 0 100 539.7±100.58µs 579.1±71.23µs 1852 tx/sec 1726 tx/sec
stdb_module 💿 person non_unique 1000 100 820.7±175.34µs 715.7±4.78µs 1218 tx/sec 1397 tx/sec
stdb_module 💿 person unique 0 100 698.7±44.02µs 660.4±43.81µs 1431 tx/sec 1514 tx/sec
stdb_module 💿 person unique 1000 100 720.0±51.12µs 675.6±45.50µs 1388 tx/sec 1480 tx/sec
stdb_module 🧠 location multi_index 0 100 711.7±18.42µs 679.2±65.66µs 1405 tx/sec 1472 tx/sec
stdb_module 🧠 location multi_index 1000 100 776.2±61.59µs 747.6±72.29µs 1288 tx/sec 1337 tx/sec
stdb_module 🧠 location non_unique 0 100 334.8±15.25µs 280.3±2.39µs 2.9 Ktx/sec 3.5 Ktx/sec
stdb_module 🧠 location non_unique 1000 100 379.0±2.32µs 318.9±0.87µs 2.6 Ktx/sec 3.1 Ktx/sec
stdb_module 🧠 location unique 0 100 502.4±75.95µs 344.3±43.54µs 1990 tx/sec 2.8 Ktx/sec
stdb_module 🧠 location unique 1000 100 617.9±48.04µs 555.9±13.16µs 1618 tx/sec 1798 tx/sec
stdb_module 🧠 person multi_index 0 100 777.3±4.56µs 928.9±7.17µs 1286 tx/sec 1076 tx/sec
stdb_module 🧠 person multi_index 1000 100 972.6±130.42µs 1070.5±4.70µs 1028 tx/sec 934 tx/sec
stdb_module 🧠 person non_unique 0 100 444.8±56.25µs 434.2±17.90µs 2.2 Ktx/sec 2.2 Ktx/sec
stdb_module 🧠 person non_unique 1000 100 472.9±102.66µs 537.7±1.49µs 2.1 Ktx/sec 1859 tx/sec
stdb_module 🧠 person unique 0 100 596.1±4.37µs 607.7±12.66µs 1677 tx/sec 1645 tx/sec
stdb_module 🧠 person unique 1000 100 798.3±6.59µs 784.4±5.60µs 1252 tx/sec 1274 tx/sec
stdb_raw 💿 location multi_index 0 100 379.2±0.62µs 364.8±0.42µs 2.6 Ktx/sec 2.7 Ktx/sec
stdb_raw 💿 location multi_index 1000 100 428.1±232.18µs 399.7±81.00µs 2.3 Ktx/sec 2.4 Ktx/sec
stdb_raw 💿 location non_unique 0 100 156.9±0.22µs 143.5±0.65µs 6.2 Ktx/sec 6.8 Ktx/sec
stdb_raw 💿 location non_unique 1000 100 169.4±106.23µs 148.7±33.00µs 5.8 Ktx/sec 6.6 Ktx/sec
stdb_raw 💿 location unique 0 100 284.3±2.89µs 267.3±4.87µs 3.4 Ktx/sec 3.7 Ktx/sec
stdb_raw 💿 location unique 1000 100 302.8±1.12µs 286.5±1.24µs 3.2 Ktx/sec 3.4 Ktx/sec
stdb_raw 💿 person multi_index 0 100 702.4±0.84µs 690.7±1.58µs 1423 tx/sec 1447 tx/sec
stdb_raw 💿 person multi_index 1000 100 760.1±271.37µs 721.4±2.57µs 1315 tx/sec 1386 tx/sec
stdb_raw 💿 person non_unique 0 100 213.9±0.30µs 200.6±0.44µs 4.6 Ktx/sec 4.9 Ktx/sec
stdb_raw 💿 person non_unique 1000 100 216.9±0.41µs 216.8±138.44µs 4.5 Ktx/sec 4.5 Ktx/sec
stdb_raw 💿 person unique 0 100 426.3±0.37µs 414.9±23.23µs 2.3 Ktx/sec 2.4 Ktx/sec
stdb_raw 💿 person unique 1000 100 445.4±1.51µs 451.8±206.61µs 2.2 Ktx/sec 2.2 Ktx/sec
stdb_raw 🧠 location multi_index 0 100 301.5±0.95µs 300.6±0.75µs 3.2 Ktx/sec 3.2 Ktx/sec
stdb_raw 🧠 location multi_index 1000 100 325.9±0.65µs 325.7±0.67µs 3.0 Ktx/sec 3.0 Ktx/sec
stdb_raw 🧠 location non_unique 0 100 76.2±0.09µs 77.1±0.12µs 12.8 Ktx/sec 12.7 Ktx/sec
stdb_raw 🧠 location non_unique 1000 100 77.2±0.16µs 78.1±0.14µs 12.7 Ktx/sec 12.5 Ktx/sec
stdb_raw 🧠 location unique 0 100 201.4±0.33µs 199.2±0.28µs 4.8 Ktx/sec 4.9 Ktx/sec
stdb_raw 🧠 location unique 1000 100 220.1±0.35µs 219.0±0.59µs 4.4 Ktx/sec 4.5 Ktx/sec
stdb_raw 🧠 person multi_index 0 100 618.6±1.08µs 619.6±1.40µs 1616 tx/sec 1613 tx/sec
stdb_raw 🧠 person multi_index 1000 100 647.5±0.67µs 650.0±1.26µs 1544 tx/sec 1538 tx/sec
stdb_raw 🧠 person non_unique 0 100 128.2±0.29µs 128.8±0.18µs 7.6 Ktx/sec 7.6 Ktx/sec
stdb_raw 🧠 person non_unique 1000 100 130.4±0.21µs 131.0±0.49µs 7.5 Ktx/sec 7.5 Ktx/sec
stdb_raw 🧠 person unique 0 100 339.6±0.49µs 339.5±0.36µs 2.9 Ktx/sec 2.9 Ktx/sec
stdb_raw 🧠 person unique 1000 100 357.1±0.52µs 359.1±0.84µs 2.7 Ktx/sec 2.7 Ktx/sec

Full table iterate

db on disk schema index type new latency old latency new throughput old throughput
sqlite 💿 location unique 8.9±0.05µs 8.9±0.09µs 109.3 Ktx/sec 109.8 Ktx/sec
sqlite 💿 person unique 9.6±0.12µs 9.2±0.13µs 101.9 Ktx/sec 106.6 Ktx/sec
sqlite 🧠 location unique 7.7±0.07µs 7.7±0.07µs 126.7 Ktx/sec 127.6 Ktx/sec
sqlite 🧠 person unique 8.1±0.12µs 8.0±0.10µs 120.8 Ktx/sec 121.3 Ktx/sec
stdb_module 💿 location unique 49.8±2.95µs 50.4±6.18µs 19.6 Ktx/sec 19.4 Ktx/sec
stdb_module 💿 person unique 62.5±6.54µs 64.3±8.98µs 15.6 Ktx/sec 15.2 Ktx/sec
stdb_module 🧠 location unique 46.6±4.60µs 50.4±6.41µs 20.9 Ktx/sec 19.4 Ktx/sec
stdb_module 🧠 person unique 63.4±7.10µs 61.8±9.32µs 15.4 Ktx/sec 15.8 Ktx/sec
stdb_raw 💿 location unique 8.1±0.03µs 8.2±0.02µs 120.4 Ktx/sec 118.9 Ktx/sec
stdb_raw 💿 person unique 8.1±0.06µs 8.2±0.03µs 120.1 Ktx/sec 118.8 Ktx/sec
stdb_raw 🧠 location unique 8.1±0.03µs 8.2±0.04µs 120.3 Ktx/sec 118.8 Ktx/sec
stdb_raw 🧠 person unique 8.1±0.03µs 8.2±0.03µs 120.5 Ktx/sec 118.8 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 409.9 Ktx/sec 414.2 Ktx/sec
sqlite 🧠 u32 1000 1134.7±2.84ns 1174.4±5.30ns 860.6 Ktx/sec 831.5 Ktx/sec
stdb_module 💿 u32 1000 19.9±1.16µs 20.6±1.50µs 49.0 Ktx/sec 47.3 Ktx/sec
stdb_module 🧠 u32 1000 20.1±1.31µs 19.5±1.14µs 48.6 Ktx/sec 50.1 Ktx/sec
stdb_raw 💿 u32 1000 888.2±2.73ns 882.0±8.03ns 1099.5 Ktx/sec 1107.2 Ktx/sec
stdb_raw 🧠 u32 1000 884.6±2.34ns 873.4±3.74ns 1103.9 Ktx/sec 1118.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.03µs 169.3 Ktx/sec 171.0 Ktx/sec
sqlite 💿 string non_indexed 1000 10 49.8±0.38µs 52.5±0.96µs 19.6 Ktx/sec 18.6 Ktx/sec
sqlite 💿 u64 indexed 1000 10 5.6±0.02µs 5.5±0.02µs 175.7 Ktx/sec 177.9 Ktx/sec
sqlite 💿 u64 non_indexed 1000 10 32.7±0.10µs 33.0±0.06µs 29.8 Ktx/sec 29.6 Ktx/sec
sqlite 🧠 string indexed 1000 10 4.3±0.01µs 4.3±0.02µs 229.7 Ktx/sec 227.9 Ktx/sec
sqlite 🧠 string non_indexed 1000 10 48.4±0.49µs 51.7±0.73µs 20.2 Ktx/sec 18.9 Ktx/sec
sqlite 🧠 u64 indexed 1000 10 4.1±0.01µs 4.1±0.02µs 239.5 Ktx/sec 240.9 Ktx/sec
sqlite 🧠 u64 non_indexed 1000 10 31.4±0.05µs 31.7±0.05µs 31.1 Ktx/sec 30.8 Ktx/sec
stdb_module 💿 string indexed 1000 10 31.2±2.29µs 29.0±3.72µs 31.3 Ktx/sec 33.7 Ktx/sec
stdb_module 💿 string non_indexed 1000 10 171.1±1.36µs 169.7±2.26µs 5.7 Ktx/sec 5.8 Ktx/sec
stdb_module 💿 u64 indexed 1000 10 25.0±2.34µs 24.1±1.54µs 39.1 Ktx/sec 40.6 Ktx/sec
stdb_module 💿 u64 non_indexed 1000 10 139.5±4.52µs 135.0±1.69µs 7.0 Ktx/sec 7.2 Ktx/sec
stdb_module 🧠 string indexed 1000 10 29.2±2.21µs 29.7±2.36µs 33.5 Ktx/sec 32.9 Ktx/sec
stdb_module 🧠 string non_indexed 1000 10 166.8±4.54µs 169.9±3.08µs 5.9 Ktx/sec 5.7 Ktx/sec
stdb_module 🧠 u64 indexed 1000 10 24.7±2.34µs 23.8±1.70µs 39.5 Ktx/sec 41.0 Ktx/sec
stdb_module 🧠 u64 non_indexed 1000 10 143.9±19.10µs 145.0±22.94µs 6.8 Ktx/sec 6.7 Ktx/sec
stdb_raw 💿 string indexed 1000 10 3.3±0.01µs 3.4±0.01µs 291.8 Ktx/sec 289.1 Ktx/sec
stdb_raw 💿 string non_indexed 1000 10 134.4±1.75µs 140.2±0.25µs 7.3 Ktx/sec 7.0 Ktx/sec
stdb_raw 💿 u64 indexed 1000 10 3.2±0.01µs 3.3±0.02µs 303.1 Ktx/sec 297.5 Ktx/sec
stdb_raw 💿 u64 non_indexed 1000 10 113.3±0.22µs 116.6±2.15µs 8.6 Ktx/sec 8.4 Ktx/sec
stdb_raw 🧠 string indexed 1000 10 3.3±0.01µs 3.4±0.01µs 292.1 Ktx/sec 290.3 Ktx/sec
stdb_raw 🧠 string non_indexed 1000 10 125.5±0.32µs 139.4±0.39µs 7.8 Ktx/sec 7.0 Ktx/sec
stdb_raw 🧠 u64 indexed 1000 10 3.2±0.01µs 3.3±0.02µs 303.2 Ktx/sec 297.1 Ktx/sec
stdb_raw 🧠 u64 non_indexed 1000 10 110.5±1.69µs 114.0±0.27µs 8.8 Ktx/sec 8.6 Ktx/sec

Serialize

schema format count new latency old latency new throughput old throughput
location bsatn 100 1939.7±54.20ns 1670.3±36.72ns 49.2 Mtx/sec 57.1 Mtx/sec
location json 100 3.5±0.07µs 3.4±0.03µs 27.0 Mtx/sec 28.4 Mtx/sec
location product_value 100 846.7±0.75ns 1121.1±0.57ns 112.6 Mtx/sec 85.1 Mtx/sec
person bsatn 100 2.7±0.02µs 3.0±0.01µs 35.9 Mtx/sec 31.5 Mtx/sec
person json 100 5.0±0.03µs 5.3±0.03µs 19.1 Mtx/sec 18.1 Mtx/sec
person product_value 100 1114.8±1.22ns 1116.8±0.52ns 85.5 Mtx/sec 85.4 Mtx/sec

Module: invoke with large arguments

arg size new latency old latency new throughput old throughput
64KiB 76.0±8.12µs 71.3±5.44µs - -

Module: print bulk

line count new latency old latency new throughput old throughput
1 20.8±1.55µs 20.6±1.14µs - -
100 200.0±11.05µs 198.9±1.03µs - -
1000 1788.2±9.20µs 1916.7±65.14µs - -

Remaining benchmarks

name new latency old latency new throughput old throughput

Please sign in to comment.