ic-rusqlite Users-Orders Benchmark

This project benchmarks ic-rusqlite dependency on a benchmark canister, the original benchmark project can be found here in the benchmarks repository.

Prerequisites

It is assumed that you have rust, dfx.

You will also need the Wasm-oriented clang installation.

Install wasi2ic and canbench:

  cargo install wasi2ic
  cargo install canbench

Deployment and testing

To run benchmarks, launch the canbench command.

Pragma settings

This shows the current benchmark results for database performance based on a database file that writes directly to a stable memory (minimized chunked storage overheads).

Following pragma settings:

PragmaValueDescription
journalPERSISTpersist journal file (is faster than deleting the file every time). Setting it to OFF works faster, but disallows atomic COMMIT/ROLLBACK
synchronousNORMALa readonable value for data safety and performance
page_size4096a reasonable default value
locking_modeEXCLUSIVEexclusive mode is faster because we avoid locking and unlocking the database for each query
temp_storeMEMORYcauses to keep the temporary data in memory, at the moment this is necessary to avoid sqlite cash during complex queries
cache_size1000000gives a significant performance boost at the expence of the canister memory used. (It tries to keep the whole database in memory, thus reducing read operation request count)

Database structure

CREATE TABLE users (
  user_id INTEGER PRIMARY KEY AUTOINCREMENT,
  username TEXT NOT NULL,
  email TEXT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE orders (
  order_id INTEGER PRIMARY KEY AUTOINCREMENT,
  user_id INTEGER NOT NULL,
  amount REAL NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  FOREIGN KEY (user_id) REFERENCES users(user_id)
);

Benchmark results

TestCycles cost
Create 100 000 users (cached INSERT query with parameters executed 100000 times).1.94 B
Create 1M orders (each refers to one of the users, no extra indexes present)20.05 B
Create indexes, when there are 1M orders in the table: CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);CREATE INDEX IF NOT EXISTS idx_orders_user_id ON orders(user_id);6.27 B
Make a joint selection (100K users, 1M orders): SELECT u.user_id, u.username, o.order_id, o.amount FROM users u JOIN orders o ON u.user_id = o.user_id WHERE u.user_id < 1000 ORDER BY o.created_at DESC;202.28 M
Select using LIKE on an indexed field: SELECT * FROM users WHERE email LIKE 'user%'781.46 M
Create 100 extra orders after there were already 1M orders and field indexes created.9.03 M
Remove 1000 orders (we remove all orders from the first 100 users): DELETE FROM orders WHERE user_id <= 10023.14 M
Create 1M orders after indices were created29.88 B
Delete 100000 orders with transaction rollback: BEGIN TRANSACTION; DELETE FROM orders WHERE order_id > 900000; ROLLBACK1.53 B