diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..71510b8 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,7 @@ +# Use the system `git` CLI for fetching git dependencies. Required because +# the cipherstash-client / stack-profile git deps in Cargo.toml point at +# the private cipherstash-suite repo, and cargo's built-in libgit2 SSH +# transport can't pick up the user's SSH agent / config the same way the +# CLI does. Removing this needs the deps to move back to crates.io. +[net] +git-fetch-with-cli = true diff --git a/Cargo.lock b/Cargo.lock index bf5d43e..13c6791 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -619,9 +619,8 @@ dependencies = [ [[package]] name = "cipherstash-client" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3d67cc26d8422509d2c20644576124e7344a4bf14ded06c7affa8dc18aabca" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "aes-gcm-siv", "anyhow", @@ -648,7 +647,6 @@ dependencies = [ "miette", "opaque-debug", "open 3.2.0", - "orderable-bytes", "ore-rs 0.8.3", "percent-encoding", "rand 0.8.6", @@ -676,7 +674,6 @@ dependencies = [ "url", "uuid", "vitaminc", - "vitaminc-protected", "winnow 0.6.26", "zeroize", "zerokms-protocol", @@ -684,21 +681,18 @@ dependencies = [ [[package]] name = "cipherstash-config" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "283fa04db19f9bf2cb2f09e8c1505a15560310bc50fdc066734072c616aa8ca9" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "bitflags 2.11.1", "serde", - "serde_json", "thiserror 1.0.69", ] [[package]] name = "cipherstash-core" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5bb7181053c3fc35569e0800fa7510c85ee2bffee21abbd2a7aeb498f5f0972" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "hmac", "lazy_static", @@ -732,16 +726,12 @@ dependencies = [ [[package]] name = "cllw-ore" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d007a5be83ae12adbd17543f9631d64090d761c029d2f8f7eb8f8ddb2a87caf" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "blake3", - "chrono", "hex", - "orderable-bytes", "postgres-types", - "rust_decimal", "subtle", "thiserror 1.0.69", "unicode-normalization", @@ -1038,9 +1028,8 @@ dependencies = [ [[package]] name = "cts-common" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b26644e630f2e690194c6b61f5b613b768061750f2060cf4db73ddb8058d284" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "arrayvec", "base32", @@ -1052,9 +1041,7 @@ dependencies = [ "nom", "regex", "serde", - "serde_json", "thiserror 1.0.69", - "tracing", "url", "utoipa", "uuid", @@ -1121,6 +1108,7 @@ dependencies = [ "sqlx", "stack-profile", "tokio", + "tracing-subscriber", ] [[package]] @@ -2733,10 +2721,6 @@ name = "orderable-bytes" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adba0469737879cabc3bdcaa6a7beb4ff7f5bb4aa5d624816c8bb9d425a7d5df" -dependencies = [ - "chrono", - "rust_decimal", -] [[package]] name = "ore-rs" @@ -2766,14 +2750,12 @@ dependencies = [ "aes", "block-modes 0.9.1", "byteorder", - "chrono", "hex", "lazy_static", "num", "orderable-bytes", "rand 0.8.6", "rand_chacha 0.3.1", - "rust_decimal", "subtle-ng", "thiserror 1.0.69", "zeroize", @@ -3038,7 +3020,6 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.114", ] [[package]] @@ -3277,9 +3258,8 @@ dependencies = [ [[package]] name = "recipher" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b3561e1082283a4c064635b7886aa4d24db57a43ac31c55930c10797ab5cdeb" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "aes", "async-trait", @@ -4254,9 +4234,8 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stack-auth" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "072e420b2bb179e7627f2e9e5ee4080d1f939c6710ecf91524d52fc87e40cbd0" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "aquamarine", "cts-common", @@ -4273,16 +4252,13 @@ dependencies = [ "url", "uuid", "vitaminc", - "vitaminc-protected", "zeroize", - "zerokms-protocol", ] [[package]] name = "stack-profile" -version = "0.34.1-alpha.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd61bc4129d2258ec1ba89d742558308560fc0f585f9c24d478685def8efd14" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "dirs", "gethostname", @@ -4948,36 +4924,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "validator" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fb22e1a008ece370ce08a3e9e4447a910e92621bb49b85d6e48a45397e7cfa" -dependencies = [ - "idna", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7df16e474ef958526d1205f6dda359fdfab79d9aa6d54bafcb92dcd07673dca" -dependencies = [ - "darling", - "once_cell", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "valuable" version = "0.1.1" @@ -4998,11 +4944,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vitaminc" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8b739a2cb1e528e77a69267728532f52d2d5ce18ae2839e26c797859fe9015" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ - "vitaminc-aead", "vitaminc-encrypt", "vitaminc-protected", "vitaminc-random", @@ -5011,9 +4955,8 @@ dependencies = [ [[package]] name = "vitaminc-aead" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c29cef4d4b0d018c4223d366017d2a9756012acf76e25011aaca877f3c74904" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "bytes", "serde", @@ -5024,9 +4967,8 @@ dependencies = [ [[package]] name = "vitaminc-encrypt" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e3869aaf60ebb95ccbdfcf003985132325b4d1ac6f5d945ad2fbb9149afd3a" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "aws-lc-rs", "vitaminc-aead", @@ -5037,12 +4979,12 @@ dependencies = [ [[package]] name = "vitaminc-protected" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af693c39d3cd1c818ef6267539433c6ceca87840b12d24124adbc9c8ecba1709" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "bitvec", "digest", + "opaque-debug", "serde", "serde_bytes", "subtle", @@ -5052,9 +4994,8 @@ dependencies = [ [[package]] name = "vitaminc-protected-derive" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e74520596b66eec546ef18d5376f6f18cdaf874caca9fa39e03eb12f9abb76fa" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "proc-macro2", "quote", @@ -5063,11 +5004,11 @@ dependencies = [ [[package]] name = "vitaminc-random" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea9de431cb93359d293ec7e70d05d87117a57f34bfc5bc94f040b81d4dd1afd6" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ - "rand 0.10.1", + "rand 0.9.2", + "rand_chacha 0.9.0", "thiserror 2.0.18", "vitaminc-protected", "vitaminc-random-derives", @@ -5076,9 +5017,8 @@ dependencies = [ [[package]] name = "vitaminc-random-derives" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49d33ac4682235551d25c874525c20e03d4c863b39f556391f52f7a2083bfbdf" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "proc-macro2", "quote", @@ -5087,9 +5027,8 @@ dependencies = [ [[package]] name = "vitaminc-traits" -version = "0.1.0-pre4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c25a9e51d24c3befddd71e907dd4ae9f21cfbaae065fb0ef5202e5d21cd198d0" +version = "0.1.0-pre4" +source = "git+https://github.com/cipherstash/vitaminc?rev=4327afd#4327afd37b2991508ed0e2e160aebe84538d234c" dependencies = [ "anyhow", "bytes", @@ -5926,9 +5865,8 @@ dependencies = [ [[package]] name = "zerokms-protocol" -version = "0.12.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a2f045e2ee975a3d448419245c4621ea8844d2a004c63a96277181dc7cf8483" +version = "0.34.0" +source = "git+ssh://git@github.com/cipherstash/cipherstash-suite.git?branch=dan%2Fzerokms-unexpected-error-context#ee9bf49a3ea4bfd6a27b0e0342ed18e198a1f1a4" dependencies = [ "base64", "cipherstash-config", @@ -5940,9 +5878,7 @@ dependencies = [ "serde", "static_assertions", "thiserror 1.0.69", - "utoipa", "uuid", - "validator", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index 7b89f07..72ce436 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,13 +14,24 @@ ore-rs = "0.7.0" hex = "0.4.3" hex-literal = "0.3.4" rand = "0.8.5" -cipherstash-client = { version = "0.34.1-alpha.4", features = ["tokio"] } -stack-profile = "0.34.1-alpha.4" +# Temporarily pointed at cipherstash-suite branch carrying the +# RequestFailed Display/source fix (cipherstash-suite#1960) so the +# benches surface the real ZeroKMS error chain instead of the opaque +# "Unexpected error" catch-all. Revert to a crates.io version pin once +# the fix lands in a published cipherstash-client release. +cipherstash-client = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", branch = "dan/zerokms-unexpected-error-context", features = ["tokio"] } +stack-profile = { git = "ssh://git@github.com/cipherstash/cipherstash-suite.git", branch = "dan/zerokms-unexpected-error-context" } anyhow = "1.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" chrono = "0.4" fake = { version = "4.4.0", features = ["chrono"] } +# tracing-subscriber wires up the cipherstash-client / zerokms-protocol +# trace! emissions to stderr when RUST_LOG is set. Without a subscriber +# the trace calls are no-ops; with one, RUST_LOG=cipherstash_client=trace +# (etc.) surfaces the rich ViturRequestError display from the inner +# trace! at vitur_client::generate_keys. +tracing-subscriber = { version = "0.3", features = ["env-filter"] } [[bin]] name = "generate_data" @@ -38,6 +49,30 @@ path = "src/bin/encrypt_string.rs" name = "combine_benchmark" path = "src/bin/combine_benchmark.rs" +[[bin]] +name = "encrypt_json_small" +path = "src/bin/encrypt_json_small.rs" + +[[bin]] +name = "encrypt_json_large" +path = "src/bin/encrypt_json_large.rs" + +[[bin]] +name = "encrypt_ste_vec_small" +path = "src/bin/encrypt_ste_vec_small.rs" + +[[bin]] +name = "encrypt_ste_vec_large" +path = "src/bin/encrypt_ste_vec_large.rs" + +[[bin]] +name = "encrypt_category" +path = "src/bin/encrypt_category.rs" + +[[bin]] +name = "encrypt_combo" +path = "src/bin/encrypt_combo.rs" + [[bench]] name = "ore" harness = false @@ -52,4 +87,12 @@ harness = false [[bench]] name = "group_by" +harness = false + +[[bench]] +name = "json" +harness = false + +[[bench]] +name = "combo" harness = false \ No newline at end of file diff --git a/README.md b/README.md index 58dcba2..35f4daa 100644 --- a/README.md +++ b/README.md @@ -170,7 +170,15 @@ mise run bench:query:ore 1000000 mise run bench:query:all ``` -Results are saved to `results/query/*.json` +Each query bench writes two files to `results/query/` per row-count tier: + +- `_rows_.json` — criterion's NDJSON message stream (one + `benchmark-complete` event per scenario, with mean / median / etc.). +- `_metadata_.json` — JSON sidecar with one record per + scenario: the exact SQL the bench ran, the bound parameter (encrypted + payload as JSON, or empty for raw-SQL benches), the + `EXPLAIN (FORMAT JSON)` plan captured once at startup, and the list of + indexes the planner picked. Join the two files by the `id` field. #### 6. Generate Report diff --git a/benches/combo.rs b/benches/combo.rs new file mode 100644 index 0000000..147b7f8 --- /dev/null +++ b/benches/combo.rs @@ -0,0 +1,195 @@ +use cipherstash_client::{ + encryption::ScopedCipher, + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, + AutoStrategy, +}; +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{ + bench_assert, extract_indexes_used, init_scoped_cipher, write_metadata_file, EncryptedQuery, + EncryptedQueryBuilder, ScenarioMetadata, +}; +use sqlx::postgres::PgPoolOptions; +use sqlx::types::Json; +use std::sync::Arc; +use tokio::runtime::Runtime; + +// Composite-predicate scenarios over `combo_encrypted_` — a three-column +// table carrying `name` (match + hmac), `age` (ORE), `category` (hmac). Each +// scenario binds ONE encrypted parameter (the name pattern for LIKE) and +// references the other encrypted columns via extractor expressions in +// WHERE / ORDER BY / GROUP BY. That keeps the build_query path simple +// (single-column ColumnConfig) while still exercising composite-predicate +// shapes the EQL query-performance guide §6 describes. +// +// Scenarios: +// +// * bloom_ore_order_limit — bloom (LIKE) + ORE ORDER BY + LIMIT +// "Find the 10 youngest customers whose first name matches a pattern." +// The GIN bloom filter on `name` engages for the LIKE predicate; the +// btree on `eql_v2.ore_block_u64_8_256(age)` engages for the ORDER BY +// because the sort key matches the index expression syntactically +// (hybrid form — same rule as §4 of the perf guide). +// +// * filtered_group_by — bloom (LIKE) + HashAggregate on hmac category +// "Group customers by category, filtered by first-name pattern." Bloom +// filters the input set first; HashAggregate then groups the filtered +// rows by the 32-byte HMAC `category` extractor — small post-filter +// set, small group key, in-memory aggregate. +// +// * top_n_filtered_group_by — same as filtered_group_by with an outer +// `ORDER BY count(*) DESC LIMIT 10`. The dashboard analytic shape: +// "top 10 categories for customers matching X". Always emits 10 rows. + +static QUERY_TEMPLATES: &[(&str, &str)] = &[ + ( + "SELECT id FROM {TABLE} \ + WHERE name LIKE $1 \ + ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "bloom_ore_order_limit", + ), + ( + "SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} \ + WHERE name LIKE $1 \ + GROUP BY 1", + "filtered_group_by", + ), + ( + "SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} \ + WHERE name LIKE $1 \ + GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "top_n_filtered_group_by", + ), +]; + +async fn build_query( + cipher: Arc>, + query: &str, + pattern: &str, + table_name: &str, +) -> EncryptedQuery { + // ColumnConfig describes `name`'s indexes — match for LIKE / bloom, + // unique for equality. We pick the match index type explicitly below so + // build_query produces a bloom-filter-shaped ciphertext for the + // parameter. + let column_config = ColumnConfig::build("name") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()) + .add_index(Index::new_match()); + + let identifier = Identifier::new(table_name, "name"); + + EncryptedQueryBuilder::new(column_config, identifier) + .index_type(Index::new_match().index_type) + .statement(query) + .build_query(pattern, cipher) + .await + .expect("Failed to build encrypted query") +} + +fn criterion_benchmark(c: &mut Criterion) { + let rt = Runtime::new().unwrap(); + + let target_rows = std::env::var("TARGET_ROWS") + .unwrap_or_else(|_| "unknown".to_string()); + + let table_suffix = match target_rows.as_str() { + "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), + _ => String::new(), + }; + let table_name = format!("combo_encrypted{}", table_suffix); + + let (pool, cipher) = rt.block_on(async { + let database_url = + std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable must be set"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await + .expect("Failed to connect to database"); + + let cipher = init_scoped_cipher() + .await + .expect("Failed to initialize ScopedCipher"); + + (pool, cipher) + }); + + // "Bob" is the standard first-name pattern used by match.rs; same here + // for consistency. The bloom index trigrams should match a non-trivial + // fraction of names produced by `Name(EN)`. + let pattern = "Bob"; + + let queries = rt.block_on(async { + let mut queries = Vec::with_capacity(QUERY_TEMPLATES.len()); + for (query_template, _) in QUERY_TEMPLATES { + let query_str = query_template.replace("{TABLE}", &table_name); + let query = build_query(Arc::clone(&cipher), &query_str, pattern, &table_name).await; + queries.push(query); + } + queries + }); + + // Capture per-scenario metadata before the criterion loop. Combo + // scenarios return shapes incompatible with EncryptedQuery::execute + // (which is typed for `Vec<(i32, Json)>`), so we use + // sqlx directly here and in the iter loop below. + let metadata = rt.block_on(async { + let mut out = Vec::with_capacity(queries.len()); + for (i, query) in queries.iter().enumerate() { + let (_, scenario) = QUERY_TEMPLATES[i]; + let bench_id = format!("COMBO/combo/{}/{}", scenario, target_rows); + let explain = query.explain(&pool).await.expect("EXPLAIN failed"); + let indexes_used = extract_indexes_used(&explain); + let parameters = vec![query.parameter_json().expect("serialise parameter")]; + let rows = sqlx::query(&query.statement) + .bind(Json(&query.eql)) + .fetch_all(&pool) + .await + .expect("execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id, + query: query.statement.clone(), + parameters, + explain, + indexes_used, + rows_returned, + }); + } + out + }); + write_metadata_file("combo", &target_rows, metadata) + .expect("failed to write bench metadata sidecar"); + + let mut group = c.benchmark_group("COMBO"); + group.sample_size(10); + + for (i, query) in queries.into_iter().enumerate() { + let (_, scenario) = QUERY_TEMPLATES[i]; + let exec_id = format!("COMBO/combo/{}/{}", scenario, target_rows); + + let exec_id_inner = exec_id.clone(); + group.bench_function(format!("combo/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let rows = bench_assert( + sqlx::query(&query.statement) + .bind(Json(&query.eql)) + .fetch_all(&pool) + .await, + &exec_id_inner, + ); + // Drain the result set; we don't care about the exact + // payload shape, only that the query executed and returned + // rows. + black_box(rows.len()); + }) + }); + } + + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/benches/exact.rs b/benches/exact.rs index 4f7e36b..bf2d6da 100644 --- a/benches/exact.rs +++ b/benches/exact.rs @@ -5,14 +5,32 @@ use cipherstash_client::{ AutoStrategy, }; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use dbbenches::{ + bench_assert, extract_indexes_used, init_scoped_cipher, sample_plaintext_string, + write_metadata_file, EncryptedQuery, EncryptedQueryBuilder, ScenarioMetadata, +}; use sqlx::postgres::PgPoolOptions; use std::sync::Arc; use tokio::runtime::Runtime; -static QUERY_TEMPLATES: &[(&str, &str, &str)] = &[ - ("SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", "Bob Johnson", "eql_cast"), - ("SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", "Bob Johnson", "eql_hash"), +// (sql_template, scenario_name). The search term is derived at runtime from +// a sample decrypt of the target table (see `sample_plaintext_string`) — the +// previous hardcoded "Bob Johnson" matched zero rows at every tier because +// `fake::Name` doesn't generate that exact combination. +// SELECT shape (`id, value::jsonb`) matches what `EncryptedQuery::execute` +// expects to decode: `Vec<(i32, Json)>`. The previous +// `SELECT value FROM ...` shape only worked because the search term +// matched zero rows — sqlx never tried to decode a row and the type +// mismatch went unnoticed. +static QUERY_TEMPLATES: &[(&str, &str)] = &[ + ( + "SELECT id, value::jsonb FROM {TABLE} WHERE value = $1 LIMIT 1", + "eql_cast", + ), + ( + "SELECT id, value::jsonb FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "eql_hash", + ), ]; async fn build_query( @@ -22,7 +40,7 @@ async fn build_query( table_name: &str, ) -> EncryptedQuery { let column_config = ColumnConfig::build("value") - .casts_as(ColumnType::Text) + .casts_as(ColumnType::Utf8Str) .add_index(Index::new_unique()); let identifier = Identifier::new(table_name, "value"); @@ -65,31 +83,89 @@ fn criterion_benchmark(c: &mut Criterion) { (pool, cipher) }); + // Derive the search term from a real row in the table so the bench + // measures actual equality-query cost (index hit + 1-row return) rather + // than the previous "0 rows / LIMIT 1 early exit" path. + let search_term: String = rt.block_on(async { + sample_plaintext_string(&pool, Arc::clone(&cipher), &table_name) + .await + .expect("failed to sample plaintext from table — is it populated?") + }); + eprintln!( + "exact bench: using sampled search term `{}` from `{}`", + &search_term, &table_name + ); + let queries = rt.block_on(async { let mut queries = Vec::with_capacity(QUERY_TEMPLATES.len()); - for (query_template, x, _) in QUERY_TEMPLATES { + for (query_template, _) in QUERY_TEMPLATES { let query_str = query_template.replace("{TABLE}", &table_name); - let query = build_query(Arc::clone(&cipher), &query_str, *x, &table_name).await; + let query = + build_query(Arc::clone(&cipher), &query_str, &search_term, &table_name).await; queries.push(query); } queries }); + // Capture per-scenario metadata (exact SQL, bound parameter as JSON, + // EXPLAIN plan, indexes the planner used) once at startup, before the + // criterion loop runs. Writes `results/query/exact_metadata_.json`. + // We only emit metadata for the non-decrypt variant — the decrypt + // variant uses the same query plan, just with an extra client-side + // decrypt pass. + let metadata = rt.block_on(async { + let mut out = Vec::with_capacity(queries.len()); + for (i, query) in queries.iter().enumerate() { + let (_, scenario) = QUERY_TEMPLATES[i]; + let bench_id = format!("EXACT/exact/{}/{}", scenario, target_rows); + let explain = query.explain(&pool).await.expect("EXPLAIN failed"); + let indexes_used = extract_indexes_used(&explain); + let parameters = vec![query.parameter_json().expect("serialise parameter")]; + let rows = query + .execute(&pool) + .await + .expect("execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id, + query: query.statement.clone(), + parameters, + explain, + indexes_used, + rows_returned, + }); + } + out + }); + write_metadata_file("exact", &target_rows, metadata) + .expect("failed to write bench metadata sidecar"); + let mut group = c.benchmark_group("EXACT"); group.sample_size(10); for (i, query) in queries.into_iter().enumerate() { - let (_, _, scenario) = QUERY_TEMPLATES[i]; - + let (_, scenario) = QUERY_TEMPLATES[i]; + let exec_id = format!("EXACT/exact/{}/{}", scenario, target_rows); + let decrypt_id = format!("EXACT/exact_decrypt/{}/{}", scenario, target_rows); + + let exec_id_inner = exec_id.clone(); group.bench_function(format!("exact/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _: Vec<_> = query.execute(&pool).await.unwrap(); + let _: Vec<_> = bench_assert(query.execute(&pool).await, &exec_id_inner); }) }); + let decrypt_id_inner = decrypt_id.clone(); group.bench_function(format!("exact_decrypt/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + // String_encrypted column holds Utf8Str — decrypt to Vec. + // Was previously typed as Vec which would have panicked on + // try_from(Plaintext::Utf8Str → i32), but never triggered + // because the bench search term matched zero rows. + let _r: Vec = black_box(bench_assert( + query.execute_and_decrypt(&pool).await, + &decrypt_id_inner, + )); }) }); } diff --git a/benches/group_by.rs b/benches/group_by.rs index 474b2c2..de1cc21 100644 --- a/benches/group_by.rs +++ b/benches/group_by.rs @@ -1,30 +1,68 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{bench_assert, extract_indexes_used, write_metadata_file, ScenarioMetadata}; use sqlx::postgres::PgPoolOptions; +use sqlx::types::Json; use sqlx::Row; use tokio::runtime::Runtime; -// Two flavours of the same GROUP BY against the string_encrypted_* tables: +// Realistic-cardinality GROUP BY scenarios. Each scenario runs against a +// low-cardinality categorical column (`CAT_001`..`CAT_250`, uniform random, +// ingested by `encrypt_category` / SQL `prepare:category_plaintext`). The +// 250-bucket cardinality is roughly an ISO 3166-1 country code distribution — +// large enough that the hash-aggregate table is interesting, small enough +// that the result-set emission cost stays negligible relative to the per-row +// HMAC work. // -// 1. "eql_cast" — natural form: `GROUP BY value`. The hash discriminator for -// aggregation is provided by `eql_v2.hash_encrypted`, which is a plpgsql -// function called once per row. Not inlinable. +// Scenarios: // -// 2. "hmac_extractor" — explicit form: `GROUP BY eql_v2.hmac_256(value)`. The -// extractor is an inlinable single-statement SQL function (post 2.3), so the -// planner folds the body — `(val).data ->> 'hm'` — into the aggregation. +// * `low_cardinality_groups_encrypted` — `SELECT count(*) FROM (SELECT 1 +// FROM category_encrypted GROUP BY eql_v2.hmac_256(value)) g`. The +// extractor-form `GROUP BY` is the EQL recipe (cheap, in-memory +// HashAggregate); wrapping in `count(*)` emits exactly one row so the +// bench is unaffected by result-set marshalling. Companion plaintext +// scenario uses the same shape on an unindexed TEXT column to give the +// EQL overhead vs bare-PG aggregate baseline. // -// PostgreSQL builds an in-memory hash table for GROUP BY in both cases (the -// functional hash index on `eql_v2.hmac_256(value)` is only useful for -// equality lookups, not aggregation), so this is really a comparison of -// per-row hashing cost: plpgsql function call vs. inlined SQL. -static QUERY_TEMPLATES: &[(&str, &str)] = &[ +// * `top_n_groups_encrypted` — `SELECT eql_v2.hmac_256(value), count(*) +// FROM category_encrypted GROUP BY 1 ORDER BY count(*) DESC LIMIT 10`. +// The dashboard-style "top N categories by frequency" pattern. Returns +// 10 rows always (one per top bucket), so the bench measures the +// HashAggregate + sort, not result emission. Plaintext companion runs +// the same shape on the TEXT column. +// +// Earlier versions of this bench grouped by the full ~1-2 KB ciphertext +// payload of high-cardinality (`fake::Name`, ~99% unique) data; both the +// time and the result-set shape were dominated by emit cost, which made the +// bench look like "GROUP BY on encrypted data is slow" when really it was +// "emitting millions of rows per query is slow". The current shapes isolate +// what callers actually pay for the GROUP BY itself. +// +// QUERY_TEMPLATES entries: (sql_template, scenario_name, base_table_name). +// `{TABLE}` is replaced with `_`. +static QUERY_TEMPLATES: &[(&str, &str, &str)] = &[ + ( + "SELECT count(*) FROM \ + (SELECT 1 FROM {TABLE} GROUP BY eql_v2.hmac_256(value)) g", + "low_cardinality_groups_encrypted", + "category_encrypted", + ), + ( + "SELECT count(*) FROM \ + (SELECT 1 FROM {TABLE} GROUP BY value) g", + "low_cardinality_groups_plaintext", + "category_plaintext", + ), ( - "SELECT count(*) FROM {TABLE} GROUP BY value", - "eql_cast", + "SELECT eql_v2.hmac_256(value), count(*) FROM {TABLE} \ + GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "top_n_groups_encrypted", + "category_encrypted", ), ( - "SELECT count(*) FROM {TABLE} GROUP BY eql_v2.hmac_256(value)", - "hmac_extractor", + "SELECT value, count(*) FROM {TABLE} \ + GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "top_n_groups_plaintext", + "category_plaintext", ), ]; @@ -38,7 +76,6 @@ fn criterion_benchmark(c: &mut Criterion) { "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), _ => String::new(), }; - let table_name = format!("string_encrypted{}", table_suffix); let pool = rt.block_on(async { let database_url = @@ -51,29 +88,79 @@ fn criterion_benchmark(c: &mut Criterion) { .expect("Failed to connect to database") }); + // Build per-scenario queries up front so we can also run EXPLAIN once + // each before the criterion loop opens. The EXPLAIN pass writes a + // `results/query/group_by_metadata_.json` sidecar capturing the + // exact SQL, the planner's chosen plan, and any indexes the planner + // picked. See lib.rs::write_metadata_file for the schema. + let scenarios: Vec<(String, String)> = QUERY_TEMPLATES + .iter() + .map(|(query_template, scenario, base_table)| { + let table_name = format!("{}{}", base_table, table_suffix); + let query_str = query_template.replace("{TABLE}", &table_name); + let bench_id = format!("GROUP_BY/group_by/{}/{}", scenario, target_rows); + (bench_id, query_str) + }) + .collect(); + + let metadata = rt.block_on(async { + let mut out = Vec::with_capacity(scenarios.len()); + for (bench_id, query_str) in &scenarios { + let explain_sql = format!("EXPLAIN (FORMAT JSON) {}", query_str); + let plan: (Json,) = sqlx::query_as(&explain_sql) + .fetch_one(&pool) + .await + .expect("EXPLAIN failed for bench scenario"); + let explain = plan.0 .0; + let indexes_used = extract_indexes_used(&explain); + let rows = sqlx::query(query_str) + .fetch_all(&pool) + .await + .expect("execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id.clone(), + query: query_str.clone(), + parameters: Vec::new(), + explain, + indexes_used, + rows_returned, + }); + } + out + }); + + write_metadata_file("group_by", &target_rows, metadata) + .expect("failed to write bench metadata sidecar"); + let mut group = c.benchmark_group("GROUP_BY"); group.sample_size(10); - // The natural-form `GROUP BY value` scenario calls `eql_v2.hash_encrypted` - // (plpgsql, per row) for the hash discriminator. At 10k rows that's - // ~3.5 s per iteration; at 100k+ it scales roughly linearly. Criterion's - // default 5 s `measurement_time` can't fit a single sample. Extend so - // even the slow scenarios get the criterion-minimum 10 samples without - // a "Unable to complete 10 samples" warning. Inflated for headroom at - // 1M rows. - group.warm_up_time(std::time::Duration::from_secs(5)); - group.measurement_time(std::time::Duration::from_secs(60)); - - for (query_template, scenario) in QUERY_TEMPLATES { - let query_str = query_template.replace("{TABLE}", &table_name); - group.bench_function(format!("group_by/{}/{}", scenario, target_rows), |b| { + for (bench_id, query_str) in scenarios { + // bench_id is e.g. "GROUP_BY/group_by/low_cardinality_groups_encrypted/100000". + // criterion's group.bench_function joins the group name ("GROUP_BY") + // with the function name we pass; strip the leading "GROUP_BY/" so + // it doesn't get doubled. + let function_name = bench_id + .strip_prefix("GROUP_BY/") + .expect("bench_id missing GROUP_BY/ prefix") + .to_string(); + let scenario_id = bench_id.clone(); + group.bench_function(function_name, |b| { b.to_async(&rt).iter(|| async { - let rows = sqlx::query(&query_str) - .fetch_all(&pool) - .await - .expect("group_by query failed"); - // Drain the result to force the aggregation to materialise. - black_box(rows.iter().map(|r| r.get::(0)).sum::()) + let rows = bench_assert( + sqlx::query(&query_str).fetch_all(&pool).await, + &scenario_id, + ); + // Drain results to force aggregation to materialise. The + // count-wrapped scenarios return a single i64; the top-N + // scenarios return up to 10 (group-key bytes, count) rows + // and we just sum the counts. + if rows.len() == 1 { + black_box(rows[0].get::(0)); + } else { + black_box(rows.iter().map(|r| r.get::(1)).sum::()); + } }) }); } diff --git a/benches/json.rs b/benches/json.rs new file mode 100644 index 0000000..bf5aabd --- /dev/null +++ b/benches/json.rs @@ -0,0 +1,259 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use dbbenches::{bench_assert, extract_indexes_used, write_metadata_file, ScenarioMetadata}; +use sqlx::postgres::PgPoolOptions; +use sqlx::types::Json; +use sqlx::Row; +use tokio::runtime::Runtime; + +// JSON / ste_vec query benches. Three shapes that exercise three distinct +// planner paths — all using the extractor recipes the EQL query-performance +// guide recommends: +// +// field_eq — `WHERE eql_v2.hmac_256_terms(col) @> $1::jsonb`, +// parameter `[{"s":"","hm":""}]`. Engages the +// `GIN (eql_v2.hmac_256_terms(value))` index. One index +// covers field-level equality across every selector that +// carries an `hm` term, vs the per-selector +// `hash (eql_v2.hmac_256(col, ''))` recipe which +// needs one index per hot path. +// +// field_extract — `SELECT eql_v2.jsonb_path_query(col, '') FROM tbl LIMIT n`. +// No index. Measures the per-row cost of the inlinable +// `jsonb_path_query` body: `jsonb_array_elements((val).data -> 'sv') +// WHERE elem ->> 's' = selector`. Inlining means the body +// folds into the calling query — each row pays an array +// walk, not a plpgsql function call. +// +// field_group_by — `SELECT eql_v2.hmac_256(col, ''), count(*) FROM tbl +// GROUP BY 1`. No index needed; HashAggregate over the +// 32-byte HMAC group key fits in default `work_mem`. Same +// extractor-form recipe as §5 of the perf guide, scaled +// down to a field-level lookup inside an ste_vec doc. +// +// Setup: at startup the bench reads one sample row from the target table, +// extracts a (selector_hash, hmac_value) pair from `sv[0]`, and uses those in +// the queries. The pick is data-driven — the bench works against any +// ste_vec-shaped table without static knowledge of which selectors are hot — +// at the cost of the pick being arbitrary across runs. For comparison purposes +// the (selector, hmac) pair is stable within a single run. + +#[derive(Debug)] +struct Selector { + sel: String, + hmac: String, +} + +async fn pick_selector(pool: &sqlx::PgPool, table: &str) -> Selector { + // (value).data -> 'sv' is the array of ste_vec elements; element 0's `s` + // is a selector hash and `hm` is the HMAC term for that selector's value. + // We pick the first sv element that carries `hm` so the chosen selector + // is HMAC-indexed (i.e. addressable via hmac_256_terms / hmac_256(col, sel)). + let row = sqlx::query(&format!( + "SELECT (value).data -> 'sv' -> 0 ->> 's' AS sel, + (value).data -> 'sv' -> 0 ->> 'hm' AS hmac + FROM {table} + WHERE (value).data -> 'sv' -> 0 ->> 'hm' IS NOT NULL + LIMIT 1" + )) + .fetch_optional(pool) + .await + .expect("query for sample selector failed"); + + let row = row.unwrap_or_else(|| { + panic!( + "No sv elements carry `hm` in `{table}`. The bench's field-level scenarios \ + depend on the post-2.3 ste_vec shape (sv elements emit `hm` rather than `b3`), \ + but the cipherstash-client version pinned in this repo \ + (currently 0.34.1-alpha.4) still emits the pre-2.3 shape. Resolve by bumping \ + `cipherstash-client` to a version that emits the new ste_vec element shape, \ + then re-ingest via `mise run prepare:json_ste_vec_small `. See \ + U-004 in EQL's v2.3 upgrade notes for the payload change." + ) + }); + + Selector { + sel: row.get::("sel"), + hmac: row.get::("hmac"), + } +} + +fn criterion_benchmark(c: &mut Criterion) { + let rt = Runtime::new().unwrap(); + + let target_rows = std::env::var("TARGET_ROWS") + .unwrap_or_else(|_| "unknown".to_string()); + + let table_suffix = match target_rows.as_str() { + "10000" | "100000" | "1000000" | "10000000" => format!("_{}", target_rows), + _ => String::new(), + }; + let table_name = format!("json_ste_vec_small_encrypted{}", table_suffix); + + let (pool, selector) = rt.block_on(async { + let database_url = + std::env::var("DATABASE_URL").expect("DATABASE_URL environment variable must be set"); + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await + .expect("Failed to connect to database"); + + let selector = pick_selector(&pool, &table_name).await; + eprintln!( + "json bench picked selector `{}` (hmac ends in `{}`) from `{}`", + &selector.sel, + // last 8 chars of hmac, just to make runs visually distinguishable. + // Full hmac stays in `selector.hmac` for the field_eq parameter. + selector.hmac.chars().rev().take(8).collect::().chars().rev().collect::(), + table_name + ); + (pool, selector) + }); + + // Pre-build the field_eq parameter: a jsonb array with one + // `{"s": , "hm": }` element that matches at least the source + // row (and likely several more if the value isn't unique). + let needle = format!( + r#"[{{"s":"{}","hm":"{}"}}]"#, + selector.sel, selector.hmac + ); + + let q_field_eq = format!( + "SELECT id FROM {table_name} \ + WHERE eql_v2.hmac_256_terms(value) @> $1::jsonb \ + LIMIT 10" + ); + + let q_field_extract = format!( + "SELECT eql_v2.jsonb_path_query(value, '{}') FROM {table_name} LIMIT 1000", + selector.sel + ); + + let q_field_group_by = format!( + "SELECT eql_v2.hmac_256(value, '{}'), count(*) FROM {table_name} GROUP BY 1", + selector.sel + ); + + // Capture per-scenario metadata before the criterion loop. Writes + // `results/query/json_metadata_.json`. + let metadata_scenarios = rt.block_on(async { + let mut out: Vec = Vec::with_capacity(3); + + async fn explain_one( + pool: &sqlx::PgPool, + query: &str, + bind: Option<&str>, + ) -> serde_json::Value { + let explain_sql = format!("EXPLAIN (FORMAT JSON) {}", query); + let row: (Json,) = if let Some(b) = bind { + sqlx::query_as(&explain_sql) + .bind(b) + .fetch_one(pool) + .await + .expect("EXPLAIN failed") + } else { + sqlx::query_as(&explain_sql) + .fetch_one(pool) + .await + .expect("EXPLAIN failed") + }; + row.0 .0 + } + + let explain = explain_one(&pool, &q_field_eq, Some(&needle)).await; + let indexes_used = extract_indexes_used(&explain); + let rows = sqlx::query(&q_field_eq) + .bind(&needle) + .fetch_all(&pool) + .await + .expect("field_eq row-count execute failed"); + out.push(ScenarioMetadata { + id: format!("JSON/json/field_eq/{}", target_rows), + query: q_field_eq.clone(), + parameters: vec![serde_json::Value::String(needle.clone())], + explain, + indexes_used, + rows_returned: rows.len() as u64, + }); + + let explain = explain_one(&pool, &q_field_extract, None).await; + let indexes_used = extract_indexes_used(&explain); + let rows = sqlx::query(&q_field_extract) + .fetch_all(&pool) + .await + .expect("field_extract row-count execute failed"); + out.push(ScenarioMetadata { + id: format!("JSON/json/field_extract/{}", target_rows), + query: q_field_extract.clone(), + parameters: Vec::new(), + explain, + indexes_used, + rows_returned: rows.len() as u64, + }); + + let explain = explain_one(&pool, &q_field_group_by, None).await; + let indexes_used = extract_indexes_used(&explain); + let rows = sqlx::query(&q_field_group_by) + .fetch_all(&pool) + .await + .expect("field_group_by row-count execute failed"); + out.push(ScenarioMetadata { + id: format!("JSON/json/field_group_by/{}", target_rows), + query: q_field_group_by.clone(), + parameters: Vec::new(), + explain, + indexes_used, + rows_returned: rows.len() as u64, + }); + + out + }); + write_metadata_file("json", &target_rows, metadata_scenarios) + .expect("failed to write bench metadata sidecar"); + + let mut group = c.benchmark_group("JSON"); + group.sample_size(10); + + let field_eq_id = format!("JSON/json/field_eq/{}", target_rows); + let field_extract_id = format!("JSON/json/field_extract/{}", target_rows); + let field_group_by_id = format!("JSON/json/field_group_by/{}", target_rows); + + let field_eq_id_inner = field_eq_id.clone(); + group.bench_function(format!("json/field_eq/{}", target_rows), |b| { + b.to_async(&rt).iter(|| async { + let rows = bench_assert( + sqlx::query(&q_field_eq).bind(&needle).fetch_all(&pool).await, + &field_eq_id_inner, + ); + black_box(rows.iter().map(|r| r.get::(0)).sum::()) + }) + }); + + let field_extract_id_inner = field_extract_id.clone(); + group.bench_function(format!("json/field_extract/{}", target_rows), |b| { + b.to_async(&rt).iter(|| async { + let rows = bench_assert( + sqlx::query(&q_field_extract).fetch_all(&pool).await, + &field_extract_id_inner, + ); + black_box(rows.len()) + }) + }); + + let field_group_by_id_inner = field_group_by_id.clone(); + group.bench_function(format!("json/field_group_by/{}", target_rows), |b| { + b.to_async(&rt).iter(|| async { + let rows = bench_assert( + sqlx::query(&q_field_group_by).fetch_all(&pool).await, + &field_group_by_id_inner, + ); + black_box(rows.iter().map(|r| r.get::(1)).sum::()) + }) + }); + + group.finish(); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/benches/match.rs b/benches/match.rs index 1792aae..eb7ed25 100644 --- a/benches/match.rs +++ b/benches/match.rs @@ -5,7 +5,10 @@ use cipherstash_client::{ AutoStrategy, }; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use dbbenches::{ + bench_assert, extract_indexes_used, init_scoped_cipher, write_metadata_file, EncryptedQuery, + EncryptedQueryBuilder, ScenarioMetadata, +}; use sqlx::postgres::PgPoolOptions; use std::sync::Arc; use tokio::runtime::Runtime; @@ -23,7 +26,7 @@ async fn build_query( table_name: &str, ) -> EncryptedQuery { let column_config = ColumnConfig::build("value") - .casts_as(ColumnType::Text) + .casts_as(ColumnType::Utf8Str) .add_index(Index::new_match()); let identifier = Identifier::new(table_name, "value"); @@ -76,21 +79,58 @@ fn criterion_benchmark(c: &mut Criterion) { queries }); + // Capture per-scenario metadata (exact SQL, bound parameter, EXPLAIN + // plan, indexes used) before the criterion loop. Writes + // `results/query/match_metadata_.json`. + let metadata = rt.block_on(async { + let mut out = Vec::with_capacity(queries.len()); + for (i, query) in queries.iter().enumerate() { + let (_, _, scenario) = QUERY_TEMPLATES[i]; + let bench_id = format!("MATCH/match/{}/{}", scenario, target_rows); + let explain = query.explain(&pool).await.expect("EXPLAIN failed"); + let indexes_used = extract_indexes_used(&explain); + let parameters = vec![query.parameter_json().expect("serialise parameter")]; + let rows = query + .execute(&pool) + .await + .expect("execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id, + query: query.statement.clone(), + parameters, + explain, + indexes_used, + rows_returned, + }); + } + out + }); + write_metadata_file("match", &target_rows, metadata) + .expect("failed to write bench metadata sidecar"); + let mut group = c.benchmark_group("MATCH"); group.sample_size(10); for (i, query) in queries.into_iter().enumerate() { let (_, _, scenario) = QUERY_TEMPLATES[i]; - + let exec_id = format!("MATCH/match/{}/{}", scenario, target_rows); + let decrypt_id = format!("MATCH/match_decrypt/{}/{}", scenario, target_rows); + + let exec_id_inner = exec_id.clone(); group.bench_function(format!("match/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _: Vec<_> = query.execute(&pool).await.unwrap(); + let _: Vec<_> = bench_assert(query.execute(&pool).await, &exec_id_inner); }) }); + let decrypt_id_inner = decrypt_id.clone(); group.bench_function(format!("match_decrypt/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + let _r: Vec = black_box(bench_assert( + query.execute_and_decrypt(&pool).await, + &decrypt_id_inner, + )); }) }); } diff --git a/benches/ore.rs b/benches/ore.rs index bc4e8cb..1e737be 100644 --- a/benches/ore.rs +++ b/benches/ore.rs @@ -8,8 +8,12 @@ use cipherstash_client::{ AutoStrategy, }; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use dbbenches::{init_scoped_cipher, EncryptedQuery, EncryptedQueryBuilder}; +use dbbenches::{ + bench_assert, extract_indexes_used, init_scoped_cipher, init_tracing, write_metadata_file, + EncryptedQuery, EncryptedQueryBuilder, ScenarioMetadata, +}; use sqlx::postgres::PgPoolOptions; +use sqlx::types::Json; use std::sync::Arc; use tokio::runtime::Runtime; @@ -17,33 +21,46 @@ use tokio::runtime::Runtime; // range predicates on `eql_v2_encrypted` reduce to // `eql_v2.ore_block_u64_8_256(a) eql_v2.ore_block_u64_8_256(b)` and // structurally match a functional btree index on -// `eql_v2.ore_block_u64_8_256(value)` — so the natural-form scenarios below -// engage the index without rewriting. +// `eql_v2.ore_block_u64_8_256(value)`. Whether the planner *uses* that index +// depends on predicate selectivity — see the two scenario families below. // -// The ordered scenarios show three plan shapes side-by-side: +// **Non-selective baselines** (threshold 5000 against `Faker.fake::()` +// data — uniform across the full i32 range, so 5000 sits very close to the +// median, giving ~50% selectivity). With a LIMIT, the planner correctly picks +// `Seq Scan + LIMIT` over a bitmap index scan: at 50% selectivity it expects +// to find LIMIT matches within the first handful of pages, cheaper than the +// index-then-heap-fetch roundtrip. So these scenarios show empty +// `indexes_used: []` in the metadata sidecar — which is the planner choosing +// correctly, not the index failing to engage. The scenarios remain in the +// suite because they're the natural form a caller would write, and the +// timing tells us what that case actually costs. // -// range_lt_ordered_10 — natural form: WHERE val < $1 ORDER BY val LIMIT 10 -// → Bitmap Index Scan via the inlined `<`, plus -// a Top-N sort by `val` (the natural-form sort -// key doesn't match the index expression -// syntactically). Each comparison in the Sort -// step uses the inlined ORE-term path, so the -// Top-N is fast. +// **Selective scenarios with LIMIT** (thresholds 2_140_000_000 / 2_147_000_000 +// — out at the i32 tail). Selectivity drops to ~0.17% and ~0.011% respectively. +// The planner picks Index Scan at every tier (10k → 10M) when stats are +// current: walking the b-tree from the top and returning the first LIMIT rows +// is cheaper than scanning the whole table. // -// range_lt_hybrid_ordered_10 — natural WHERE, extractor ORDER BY: -// ORDER BY eql_v2.ore_block_u64_8_256(val). -// The sort key matches the index expression → -// plain ordered Index Scan, no Sort node. +// **Stats matter.** Without an `ANALYZE` after the table is re-ingested, the +// planner defaults to `~14%` selectivity for `>` comparisons and picks Seq +// Scan even for highly selective predicates. The bench's `prepare:_table` +// task now runs `ANALYZE ` after index creation specifically to avoid +// this silent-fallback failure mode. // -// range_lt_ore_ordered_10 — fully extractor on both clauses. After the `<` -// inlining the WHERE reduces to the same shape -// as the hybrid, so the plan is identical to -// hybrid. Kept for contrast / regression. +// **Selective scenarios without LIMIT** (`*_count` — `SELECT count(*) WHERE +// value threshold`). No LIMIT means the planner must process every +// matching row to compute the count; with a selective predicate this +// strongly favours Index Scan over Seq Scan at every tier. Companion to the +// `_LIMIT` variants — removes LIMIT-related cost-model edge cases. // -// The equality scenario from the previous bench (`WHERE value = $1`) is gone: -// the integer column carries only `ob`, not `hm`, so post-2.3 equality returns -// NULL → zero rows. See exact.rs for the meaningful equality benches. +// **Hybrid ordered range** uses extractor ORDER BY (`ORDER BY +// eql_v2.ore_block_u64_8_256(val)`) matching the functional index expression — +// rows stream out of the index already sorted (Index Scan, no Sort node). The +// natural-form variant (`ORDER BY value`) is the §4 sort-key trap and was +// dropped from this bench in an earlier pass — its cost (Top-N Sort over the +// full post-WHERE bitmap) is documented in the guide already. static QUERY_TEMPLATES: &[(&str, i32, &str)] = &[ + // ── Non-selective baselines (≈50% selectivity → Seq Scan + LIMIT) ── ( "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", 5000, @@ -64,11 +81,23 @@ static QUERY_TEMPLATES: &[(&str, i32, &str)] = &[ 5000, "range_lt_100", ), + // ── Selective predicates (~0.17% / ~0.011% selectivity → Index Scan) ── + // 2_140_000_000 sits 7.5M values short of i32::MAX — ~0.17% of the i32 + // range matches `value > 2_140_000_000` on uniform random data. ( - "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10", - 5000, - "range_lt_ordered_10", + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100", + 2_140_000_000, + "range_selective_gt_100", + ), + // 2_147_000_000 sits 483k values short of i32::MAX — ~0.011% selectivity. + // Even at 10k rows this returns ~1 row, but the planner can decide that + // before scanning; index engages reliably across tiers. + ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", + 2_147_000_000, + "range_highly_selective_gt_10", ), + // ── Hybrid ordered range (extractor in ORDER BY) ── ( "SELECT id,value::jsonb FROM {TABLE} \ WHERE value < $1 \ @@ -76,12 +105,24 @@ static QUERY_TEMPLATES: &[(&str, i32, &str)] = &[ 5000, "range_lt_hybrid_ordered_10", ), +]; + +// Count-style selective scenarios — no LIMIT, so the planner must process +// every matching row, which strongly favours Index Scan on the functional +// btree once selectivity is low. These reliably engage the index at every +// tier (10k → 10M) and are the canonical "yes the ORE index is doing real +// work" demonstration. SELECT count(*) returns a single row; the bench +// loop drains it and black_boxes the result. +static COUNT_QUERY_TEMPLATES: &[(&str, i32, &str)] = &[ + ( + "SELECT count(*) FROM {TABLE} WHERE value > $1", + 2_140_000_000, + "range_selective_gt_count", + ), ( - "SELECT id,value::jsonb FROM {TABLE} \ - WHERE eql_v2.ore_block_u64_8_256(value) < eql_v2.ore_block_u64_8_256($1::jsonb) \ - ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", - 5000, - "range_lt_ore_ordered_10", + "SELECT count(*) FROM {TABLE} WHERE value > $1", + 2_147_000_000, + "range_highly_selective_gt_count", ), ]; @@ -106,6 +147,10 @@ async fn build_query( } fn criterion_benchmark(c: &mut Criterion) { + // Wire up cipherstash-client / zerokms-protocol trace! emissions to + // stderr when RUST_LOG is set. No-op when unset. + init_tracing(); + let rt = Runtime::new().unwrap(); let target_rows = std::env::var("TARGET_ROWS") @@ -145,32 +190,123 @@ fn criterion_benchmark(c: &mut Criterion) { queries }); + // Count-style scenarios reuse the same build_query path (to encrypt + // the threshold as the bound parameter) but produce a different SQL + // shape — they're executed via raw sqlx in the iter loop below + // because EncryptedQuery::execute is typed for `Vec<(i32, + // Json)>`, which doesn't match a `SELECT count(*)` + // result. + let count_queries = rt.block_on(async { + let mut queries = Vec::with_capacity(COUNT_QUERY_TEMPLATES.len()); + for (query_template, x, _) in COUNT_QUERY_TEMPLATES { + let query_str = query_template.replace("{TABLE}", &table_name); + let query = build_query(Arc::clone(&cipher), &query_str, *x, &table_name).await; + queries.push(query); + } + queries + }); + + // Capture per-scenario metadata (exact SQL, bound parameter, EXPLAIN + // plan, indexes used) before the criterion loop. Writes + // `results/query/ore_metadata_.json`. + let metadata = rt.block_on(async { + let mut out = Vec::with_capacity(queries.len() + count_queries.len()); + for (i, query) in queries.iter().enumerate() { + let (_, _, scenario) = QUERY_TEMPLATES[i]; + let bench_id = format!("ORE/ore/{}/{}", scenario, target_rows); + let explain = query.explain(&pool).await.expect("EXPLAIN failed"); + let indexes_used = extract_indexes_used(&explain); + let parameters = vec![query.parameter_json().expect("serialise parameter")]; + let rows = query + .execute(&pool) + .await + .expect("execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id, + query: query.statement.clone(), + parameters, + explain, + indexes_used, + rows_returned, + }); + } + + // Count-scenarios: same metadata shape, but use raw sqlx (the + // count(*) return type doesn't match EncryptedQuery::execute). + for (i, query) in count_queries.iter().enumerate() { + let (_, _, scenario) = COUNT_QUERY_TEMPLATES[i]; + let bench_id = format!("ORE/ore/{}/{}", scenario, target_rows); + let explain = query.explain(&pool).await.expect("EXPLAIN failed"); + let indexes_used = extract_indexes_used(&explain); + let parameters = vec![query.parameter_json().expect("serialise parameter")]; + let rows = sqlx::query(&query.statement) + .bind(Json(&query.eql)) + .fetch_all(&pool) + .await + .expect("count(*) execute for row-count failed"); + let rows_returned = rows.len() as u64; + out.push(ScenarioMetadata { + id: bench_id, + query: query.statement.clone(), + parameters, + explain, + indexes_used, + rows_returned, + }); + } + out + }); + write_metadata_file("ore", &target_rows, metadata) + .expect("failed to write bench metadata sidecar"); + let mut group = c.benchmark_group("ORE"); group.sample_size(10); - // Some scenarios — notably the natural-form `WHERE val < $1 ORDER BY val - // LIMIT 10` — finish a single iteration in several hundred milliseconds - // because the Top-N sort runs over the post-WHERE bitmap rather than - // streaming from an ordered index (see U-005 in EQL's v2.3 upgrade - // notes). Criterion's default 5 s `measurement_time` only fits a few - // such samples, yielding very wide confidence intervals and false - // "regressed" alerts against any stored baseline. 30 s gives the slow - // scenarios room to settle while leaving fast ones (sub-ms to single - // ms) plenty of headroom. - group.warm_up_time(std::time::Duration::from_secs(5)); - group.measurement_time(std::time::Duration::from_secs(30)); + // All remaining scenarios run sub-ms to single-digit-ms per iteration, so + // criterion's default measurement budget is plenty. (Earlier versions of + // this bench needed a 30 s budget for the natural-form ordered range + // scenario; that scenario is gone — see the comment on `QUERY_TEMPLATES`.) for (i, query) in queries.into_iter().enumerate() { let (_, _, scenario) = QUERY_TEMPLATES[i]; + let exec_id = format!("ORE/ore/{}/{}", scenario, target_rows); + let decrypt_id = format!("ORE/ore_decrypt/{}/{}", scenario, target_rows); + let exec_id_inner = exec_id.clone(); group.bench_function(format!("ore/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _: Vec<_> = query.execute(&pool).await.unwrap(); + let _: Vec<_> = bench_assert(query.execute(&pool).await, &exec_id_inner); }) }); + let decrypt_id_inner = decrypt_id.clone(); group.bench_function(format!("ore_decrypt/{}/{}", scenario, target_rows), |b| { b.to_async(&rt).iter(|| async { - let _r: Vec = black_box(query.execute_and_decrypt(&pool).await.unwrap()); + let _r: Vec = black_box(bench_assert( + query.execute_and_decrypt(&pool).await, + &decrypt_id_inner, + )); + }) + }); + } + + // Count-style scenarios — single iter loop each, raw sqlx (count(*) + // return type doesn't match EncryptedQuery::execute). No `_decrypt` + // variant — there's nothing to decrypt in a count result. + for (i, query) in count_queries.into_iter().enumerate() { + let (_, _, scenario) = COUNT_QUERY_TEMPLATES[i]; + let exec_id = format!("ORE/ore/{}/{}", scenario, target_rows); + let exec_id_inner = exec_id.clone(); + group.bench_function(format!("ore/{}/{}", scenario, target_rows), |b| { + b.to_async(&rt).iter(|| async { + let rows = bench_assert( + sqlx::query(&query.statement) + .bind(Json(&query.eql)) + .fetch_all(&pool) + .await, + &exec_id_inner, + ); + black_box(rows.len()); }) }); } diff --git a/docker-compose.yml b/docker-compose.yml index ae40242..c23005b 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.8' services: postgres: - image: postgres:17 + image: pgvector/pgvector:pg17 container_name: ore-benches-postgres environment: POSTGRES_USER: postgres diff --git a/mise.toml b/mise.toml index b2f0909..a928bab 100644 --- a/mise.toml +++ b/mise.toml @@ -40,6 +40,48 @@ docker exec -i ore-benches-postgres psql -U postgres -d template1 -c "CREATE DAT echo "Database reset complete. Run 'mise run setup-db' to set up tables and data." """ +[tasks.truncate] +description = "Truncate all bench tables (keeps EQL install + schema; just wipes rows)" +depends = ["postgres"] +run = """ +#!/usr/bin/env bash +set -e + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +echo "Truncating all bench tables in public schema..." +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres <<'SQL' +DO $$ +DECLARE + r record; + table_list text := ''; +BEGIN + FOR r IN + SELECT tablename + FROM pg_tables + WHERE schemaname = 'public' + AND (tablename LIKE '%_encrypted%' OR tablename LIKE '%_plaintext%') + ORDER BY tablename + LOOP + table_list := table_list || 'public.' || quote_ident(r.tablename) || ', '; + END LOOP; + + IF table_list = '' THEN + RAISE NOTICE 'No bench tables found to truncate.'; + ELSE + table_list := rtrim(table_list, ', '); + RAISE NOTICE 'Truncating: %', table_list; + EXECUTE 'TRUNCATE TABLE ' || table_list || ' RESTART IDENTITY CASCADE'; + END IF; +END $$; +SQL + +echo "Truncate complete. EQL version untouched." +""" + [tasks.setup-db] description = "Set up the test database (create tables and load data)" depends = ["postgres"] @@ -76,20 +118,27 @@ cargo build --release [tasks."bench:ingest:_run"] description = "Internal: Run a generic ingest benchmark" -depends = ["bench:build"] +depends = ["postgres", "bench:build"] run = """ #!/usr/bin/env bash set -e +[ -f .env ] && set -a && source .env && set +a BENCH_NAME="$1" +TABLE_NAME="$2" +NUM_RECORDS="${3:-500,1000,10000}" -if [ -z "$BENCH_NAME" ]; then - echo "Error: BENCH_NAME argument must be provided" +if [ -z "$BENCH_NAME" ] || [ -z "$TABLE_NAME" ]; then + echo "Error: BENCH_NAME and TABLE_NAME arguments must be provided" + echo "Usage: mise run bench:ingest:_run [num_records]" exit 1 fi echo "Running $BENCH_NAME ingest benchmark..." -mise x -- hyperfine --export-json target/${BENCH_NAME}_hyperfine.json -L num_records 500,1000,10000 --runs 2 "NUM_RECORDS={num_records} ./target/release/$BENCH_NAME" +mise x -- hyperfine --export-json target/${BENCH_NAME}_hyperfine.json \ + -L num_records "${NUM_RECORDS}" --runs 2 \ + --prepare "docker exec ore-benches-postgres psql -U postgres -d postgres -c 'TRUNCATE TABLE ${TABLE_NAME};'" \ + "NUM_RECORDS={num_records} ./target/release/$BENCH_NAME" echo "Combining results..." ./target/release/combine_benchmark "$BENCH_NAME" @@ -99,19 +148,68 @@ echo "Benchmark complete! Results written to results/ingest/${BENCH_NAME}_combin [tasks."bench:ingest:encrypt_int"] description = "Run encrypt_int ingest benchmark and combine results" -run = "mise run bench:ingest:_run encrypt_int" +run = "mise run bench:ingest:_run encrypt_int integer_encrypted" [tasks."bench:ingest:encrypt_string"] description = "Run encrypt_string ingest benchmark and combine results" -run = "mise run bench:ingest:_run encrypt_string" +run = "mise run bench:ingest:_run encrypt_string string_encrypted" + +[tasks."bench:ingest:json-small"] +description = "Run encrypt_json_small (no-index baseline) ingest benchmark" +run = "mise run bench:ingest:_run encrypt_json_small json_small_encrypted" + +[tasks."bench:ingest:json-large"] +description = "Run encrypt_json_large (no-index baseline) ingest benchmark" +run = "mise run bench:ingest:_run encrypt_json_large json_large_encrypted" -[tasks."bench:ingest:encrypt_json_small"] -description = "Run encrypt_json_small ingest benchmark and combine results" -run = "mise run bench:ingest:_run encrypt_json_small" +[tasks."bench:ingest:json-ste-vec-small"] +description = "Run encrypt_ste_vec_small (SteVec-indexed) ingest benchmark" +run = "mise run bench:ingest:_run encrypt_ste_vec_small json_ste_vec_small_encrypted $1" + +[tasks."bench:ingest:json-ste-vec-small-gin"] +description = "Run encrypt_ste_vec_small ingest benchmark with the GIN index pre-created (measures index-write cost amortised over insert path)" +depends = ["postgres", "bench:build"] +run = """ +#!/usr/bin/env bash +set -e +[ -f .env ] && set -a && source .env && set +a + +BENCH_NAME="encrypt_ste_vec_small" +TABLE_NAME="json_ste_vec_small_encrypted" +NUM_RECORDS="${1:-500,1000,10000}" + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +echo "Truncating table and creating GIN index before ingest..." +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres -c "TRUNCATE TABLE ${TABLE_NAME};" +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres < sql/indexes/${TABLE_NAME}_down.sql +docker exec -i ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres < sql/indexes/${TABLE_NAME}_up.sql + +echo "Running $BENCH_NAME ingest benchmark (with GIN index)..." +mkdir -p results/ingest +hyperfine --export-json results/ingest/${BENCH_NAME}_gin_hyperfine.json \ + -L num_records "${NUM_RECORDS}" --runs 2 \ + --prepare "docker exec ore-benches-postgres psql -U postgres -d postgres -c 'TRUNCATE TABLE ${TABLE_NAME};'" \ + "NUM_RECORDS={num_records} ./target/release/$BENCH_NAME" + +echo "Benchmark complete! Results written to results/ingest/${BENCH_NAME}_gin_hyperfine.json" +""" + +[tasks."bench:ingest:json-ste-vec-large"] +description = "Run encrypt_ste_vec_large (SteVec-indexed) ingest benchmark" +run = "mise run bench:ingest:_run encrypt_ste_vec_large json_large_encrypted" [tasks."bench:ingest"] description = "Run all ingest benchmarks sequentially" -depends = ["bench:ingest:encrypt_int", "bench:ingest:encrypt_string", "bench:ingest:encrypt_json_small"] +depends = [ + "bench:ingest:encrypt_int", + "bench:ingest:encrypt_string", + "bench:ingest:json-small", + "bench:ingest:json-large", +] [tasks."prepare:_table"] description = "Internal: Prepare a table with target row count" @@ -162,13 +260,46 @@ fi echo "Dropping indexes..." docker exec -i ore-benches-postgres psql -U postgres -d postgres < sql/indexes/${TABLE_NAME}_down.sql -ROWS_TO_INSERT=$((TARGET_ROWS - CURRENT_ROWS)) -echo "Inserting $ROWS_TO_INSERT additional rows..." -NUM_RECORDS=$ROWS_TO_INSERT TABLE_SUFFIX="_${TARGET_ROWS}" ./target/release/$BINARY_NAME +# ZeroKMS occasionally returns "Unexpected error" mid-stream on long encrypt +# runs (typically 150-400k rows in), killing the binary. The binary writes +# rows transactionally per batch, so a re-run from the current row count +# picks up where we left off. Retry the inner binary until the table +# reaches the target (or MAX_ATTEMPTS — typically <5 needed even at 10M). +MAX_ATTEMPTS=30 +attempt=1 +while true; do + CURRENT_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') + if [ "$CURRENT_ROWS" -ge "$TARGET_ROWS" ]; then + echo "Table reached $CURRENT_ROWS rows (>= $TARGET_ROWS)." + break + fi + if [ "$attempt" -gt "$MAX_ATTEMPTS" ]; then + echo "Error: exceeded $MAX_ATTEMPTS attempts, table has $CURRENT_ROWS / $TARGET_ROWS rows." + exit 1 + fi + ROWS_TO_INSERT=$((TARGET_ROWS - CURRENT_ROWS)) + echo "Attempt $attempt: inserting $ROWS_TO_INSERT additional rows..." + if NUM_RECORDS=$ROWS_TO_INSERT TABLE_SUFFIX="_${TARGET_ROWS}" ./target/release/$BINARY_NAME; then + echo "Attempt $attempt: succeeded." + else + echo "Attempt $attempt: failed (likely ZeroKMS transient), retrying after backoff..." + sleep 5 + fi + attempt=$((attempt + 1)) +done echo "Creating indexes..." docker exec -i ore-benches-postgres psql -U postgres -d postgres < sql/indexes/${TABLE_NAME}_up.sql +# ANALYZE the freshly-loaded table so the planner has accurate +# selectivity stats for the functional indexes. Without this, the +# planner uses default selectivity assumptions (e.g. ~14% for `>`) +# and reliably picks Seq Scan over Index Scan for low-selectivity +# predicates — which silently looks like a benchmark of "EQL is slow" +# when really it's "stats are stale". Costs seconds even at 10M rows. +echo "Running ANALYZE..." +docker exec -i ore-benches-postgres psql -U postgres -d postgres -c "ANALYZE $TABLE_NAME;" + FINAL_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') echo "Preparation complete! Final row count: $FINAL_ROWS" """ @@ -181,6 +312,131 @@ run = "mise run prepare:_table string_encrypted encrypt_string $1" description = "Prepare integer_encrypted table with target row count" run = "mise run prepare:_table integer_encrypted encrypt_int $1" +[tasks."prepare:json_ste_vec_small"] +description = "Prepare json_ste_vec_small_encrypted table with target row count" +run = "mise run prepare:_table json_ste_vec_small_encrypted encrypt_ste_vec_small $1" + +[tasks."prepare:category_encrypted"] +description = "Prepare category_encrypted_ table with ~250 low-cardinality categorical values" +run = "mise run prepare:_table category_encrypted encrypt_category $1" + +[tasks."prepare:combo_encrypted"] +description = "Prepare combo_encrypted_ table with three encrypted columns (name + age + category)" +run = "mise run prepare:_table combo_encrypted encrypt_combo $1" + +[tasks."prepare:category_plaintext"] +description = "Prepare category_plaintext_ table with ~250 low-cardinality categorical strings (CAT_001..CAT_250, uniform random)" +depends = ["postgres"] +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run prepare:category_plaintext " + exit 1 +fi + +case "$TARGET_ROWS" in + 10000|100000|1000000|10000000) + ;; + *) + echo "Error: TARGET_ROWS must be one of: 10000, 100000, 1000000, 10000000" + exit 1 + ;; +esac + +TABLE_NAME="category_plaintext_${TARGET_ROWS}" + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +CURRENT_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') + +echo "Current rows in $TABLE_NAME: $CURRENT_ROWS" +echo "Target rows: $TARGET_ROWS" + +if [ "$CURRENT_ROWS" -ge "$TARGET_ROWS" ]; then + echo "Table already has $CURRENT_ROWS rows (>= $TARGET_ROWS). No action needed." + exit 0 +fi + +ROWS_TO_INSERT=$((TARGET_ROWS - CURRENT_ROWS)) +echo "Inserting $ROWS_TO_INSERT random category values (CAT_001..CAT_250, uniform)..." + +# `format('CAT_%s', lpad(((random()*249)::int + 1)::text, 3, '0'))` matches the +# Rust FakeCategory output `format!("CAT_{:03}", n)`. 250 distinct buckets. +docker exec ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres -c " + INSERT INTO $TABLE_NAME (value) + SELECT 'CAT_' || lpad(((random() * 249)::int + 1)::text, 3, '0') + FROM generate_series(1, $ROWS_TO_INSERT) g; +" + +FINAL_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') +echo "Preparation complete! Final row count: $FINAL_ROWS" +""" + +[tasks."prepare:string_plaintext"] +description = "Prepare string_plaintext_ table with random high-cardinality strings (md5)" +depends = ["postgres"] +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run prepare:string_plaintext " + exit 1 +fi + +case "$TARGET_ROWS" in + 10000|100000|1000000|10000000) + ;; + *) + echo "Error: TARGET_ROWS must be one of: 10000, 100000, 1000000, 10000000" + exit 1 + ;; +esac + +TABLE_NAME="string_plaintext_${TARGET_ROWS}" + +echo "Waiting for PostgreSQL to be ready..." +until docker exec ore-benches-postgres pg_isready -U postgres > /dev/null 2>&1; do + sleep 1 +done + +CURRENT_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') + +echo "Current rows in $TABLE_NAME: $CURRENT_ROWS" +echo "Target rows: $TARGET_ROWS" + +if [ "$CURRENT_ROWS" -ge "$TARGET_ROWS" ]; then + echo "Table already has $CURRENT_ROWS rows (>= $TARGET_ROWS). No action needed." + exit 0 +fi + +ROWS_TO_INSERT=$((TARGET_ROWS - CURRENT_ROWS)) +echo "Inserting $ROWS_TO_INSERT random rows (md5 of (random, ordinal))..." + +# md5(random()::text || g::text) is high-cardinality 32-char hex per row. +# Single SQL insert in PG is far faster than per-row roundtrips — completes +# 10M rows in tens of seconds, no encryption-client dependency. +docker exec ore-benches-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres -c " + INSERT INTO $TABLE_NAME (value) + SELECT md5(random()::text || g::text) + FROM generate_series(1, $ROWS_TO_INSERT) g; +" + +FINAL_ROWS=$(docker exec ore-benches-postgres psql -U postgres -d postgres -t -c "SELECT COUNT(*) FROM $TABLE_NAME;" | tr -d ' ') +echo "Preparation complete! Final row count: $FINAL_ROWS" +""" + [tasks."bench:query:ore"] description = "Run ORE query benchmark" run = """ @@ -281,7 +537,7 @@ echo "Benchmark complete! Results written to $OUTPUT_FILE" """ [tasks."bench:query:group_by"] -description = "Run GROUP BY query benchmark" +description = "Run GROUP BY query benchmark (low-cardinality categorical data + plaintext baseline)" run = """ #!/usr/bin/env bash set -e @@ -299,8 +555,11 @@ if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then exit 1 fi -echo "Preparing string_encrypted table with $TARGET_ROWS rows..." -mise run prepare:string_encrypted "$TARGET_ROWS" +echo "Preparing category_encrypted table with $TARGET_ROWS rows (~250 distinct buckets)..." +mise run prepare:category_encrypted "$TARGET_ROWS" + +echo "Preparing category_plaintext table with $TARGET_ROWS rows (plaintext baseline)..." +mise run prepare:category_plaintext "$TARGET_ROWS" echo "Cleaning old benchmark data..." rm -rf target/criterion/data/main/GROUP_BY target/criterion/reports/GROUP_BY @@ -313,6 +572,72 @@ TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench group_by --message-format jso echo "Benchmark complete! Results written to $OUTPUT_FILE" """ +[tasks."bench:query:combo"] +description = "Run COMBO query benchmark (composite predicates on combo_encrypted)" +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run bench:query:combo " + exit 1 +fi + +if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then + echo "Error: target row count must be a positive integer" + exit 1 +fi + +echo "Preparing combo_encrypted table with $TARGET_ROWS rows..." +mise run prepare:combo_encrypted "$TARGET_ROWS" + +echo "Cleaning old benchmark data..." +rm -rf target/criterion/data/main/COMBO target/criterion/reports/COMBO + +echo "Running COMBO query benchmark..." +mkdir -p results/query +OUTPUT_FILE="results/query/combo_rows_${TARGET_ROWS}.json" +TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench combo --message-format json > "$OUTPUT_FILE" + +echo "Benchmark complete! Results written to $OUTPUT_FILE" +""" + +[tasks."bench:query:json"] +description = "Run JSON / ste_vec query benchmark (field equality / extraction / GROUP BY)" +run = """ +#!/usr/bin/env bash +set -e + +TARGET_ROWS="$1" + +if [ -z "$TARGET_ROWS" ]; then + echo "Error: target row count argument required" + echo "Usage: mise run bench:query:json " + exit 1 +fi + +if ! [[ "$TARGET_ROWS" =~ ^[0-9]+$ ]]; then + echo "Error: target row count must be a positive integer" + exit 1 +fi + +echo "Preparing json_ste_vec_small_encrypted table with $TARGET_ROWS rows..." +mise run prepare:json_ste_vec_small "$TARGET_ROWS" + +echo "Cleaning old benchmark data..." +rm -rf target/criterion/data/main/JSON target/criterion/reports/JSON + +echo "Running JSON query benchmark..." +mkdir -p results/query +OUTPUT_FILE="results/query/json_rows_${TARGET_ROWS}.json" +TARGET_ROWS="$TARGET_ROWS" cargo criterion --bench json --message-format json > "$OUTPUT_FILE" + +echo "Benchmark complete! Results written to $OUTPUT_FILE" +""" + [tasks."bench:query:all"] description = "Run all query benchmarks with multiple row counts (10k, 100k, 1M, 10M)" run = """ @@ -324,7 +649,9 @@ ROW_COUNTS=(10000 100000 1000000 10000000) echo "========================================" echo "Starting comprehensive benchmark suite" echo "Row counts: ${ROW_COUNTS[*]}" -echo "Benchmarks: exact, match, ore, group_by" +echo "Benchmarks: exact, match, ore, group_by, combo" +echo "(bench:query:json is parked until cipherstash-client emits the" +echo " post-2.3 ste_vec shape — run it directly when ready.)" echo "========================================" echo "" @@ -344,14 +671,18 @@ for ROWS in "${ROW_COUNTS[@]}"; do mise run bench:query:match "$ROWS" echo "" - echo "[3/4] Running ORE benchmark with $ROWS rows..." + echo "[3/5] Running ORE benchmark with $ROWS rows..." mise run bench:query:ore "$ROWS" echo "" - echo "[4/4] Running GROUP BY benchmark with $ROWS rows..." + echo "[4/5] Running GROUP BY benchmark with $ROWS rows..." mise run bench:query:group_by "$ROWS" echo "" + echo "[5/5] Running COMBO benchmark with $ROWS rows..." + mise run bench:query:combo "$ROWS" + echo "" + echo "Completed benchmarks for $ROWS rows" echo "" done diff --git a/report/BENCHMARK_REPORT.md b/report/BENCHMARK_REPORT.md index 558c516..5570146 100644 --- a/report/BENCHMARK_REPORT.md +++ b/report/BENCHMARK_REPORT.md @@ -1,14 +1,20 @@ # Benchmark Report -This report summarizes the performance benchmarks for encrypted database operations. +This report summarises the performance benchmarks for encrypted database operations. Per-query-type detail lives on its own page — click through from the Query Performance section below. ## Table of Contents 1. [Ingest Throughput](#ingest-throughput) + - [Int](#int) + - [Json Small](#json-small) + - [Ste Vec Small](#ste-vec-small) + - [String](#string) 2. [Query Performance](#query-performance) - - [EXACT Queries](#exact-queries) - - [MATCH Queries](#match-queries) - - [ORE Queries](#ore-queries) + - [COMBO Queries](combo.md) + - [EXACT Queries](exact.md) + - [GROUP_BY Queries](group_by.md) + - [MATCH Queries](match.md) + - [ORE Queries](ore.md) --- @@ -16,6 +22,16 @@ This report summarizes the performance benchmarks for encrypted database operati This section measures the throughput of inserting encrypted records into the database. +### Comparison at 10,000 Records + +Comparing all benchmark types at 10,000 records. + +![Throughput Comparison at 10,000 records](ingest_comparison_throughput_10000.png) + +![Total Time Comparison at 10,000 records](ingest_comparison_time_10000.png) + +![Total Time Comparison at 10,000 records (excluding ste_vec_large)](ingest_comparison_time_10000_filtered.png) + ### Int Tests insertion of encrypted integer values. @@ -26,11 +42,13 @@ Tests insertion of encrypted integer values. | 1,000 | 1.11K | 0.90s | 17.83 MB | | 10,000 | 1.34K | 7.48s | 20.34 MB | -![Ingest Throughput - int](ingest_int_chart.png) +![Ingest Throughput - int](ingest_int_throughput_chart.png) + +![Ingest Total Time - int](ingest_int_time_chart.png) ### Json Small -Tests insertion of small encrypted JSON objects. +Tests insertion of small encrypted JSON objects (first_name, last_name, age, email). | Records | Throughput (records/sec) | Total Time | Avg Memory | |---------|--------------------------|------------|------------| @@ -38,420 +56,47 @@ Tests insertion of small encrypted JSON objects. | 1,000 | 1.45K | 0.69s | 27.47 MB | | 10,000 | 2.22K | 4.51s | 45.33 MB | -![Ingest Throughput - json_small](ingest_json_small_chart.png) +![Ingest Throughput - json_small](ingest_json_small_throughput_chart.png) -### String +![Ingest Total Time - json_small](ingest_json_small_time_chart.png) -Tests insertion of encrypted string values. +### Ste Vec Small + +Tests insertion of small JSON objects with SteVec (searchable encrypted vector) indexing. | Records | Throughput (records/sec) | Total Time | Avg Memory | |---------|--------------------------|------------|------------| -| 500 | 559.65 | 0.89s | 14.12 MB | -| 1,000 | 1.86K | 0.54s | 16.19 MB | -| 10,000 | 2.83K | 3.54s | 18.23 MB | - -![Ingest Throughput - string](ingest_string_chart.png) - -## Query Performance - -This section measures query performance across different data set sizes. Each query is tested with and without decryption of results. - -### EXACT Queries - -#### eql_cast - -**Description:** Exact match using EQL cast operator - -**SQL Query:** -```sql -SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1 -``` - -**Parameter:** `Bob Johnson` - -**Table: `string_encrypted_{rows}` with encrypted string values. Index: UNIQUE index on the encrypted value column.** - -**Indexes:** -```sql -CREATE INDEX -string_encrypted_10000_hash_index -ON string_encrypted_10000 using hash ( - eql_v2.hmac_256(value) -); - -CREATE INDEX -string_encrypted_10000_gin_index -ON string_encrypted_10000 USING GIN ( - eql_v2.bloom_filter(value) -); - -CREATE INDEX -string_encrypted_10000_eql_index -ON string_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -*⚠️ = Query time exceeds 100ms* - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 422.00μs | 415.23μs | -| 100,000 | 400.64μs | 427.65μs | -| 1,000,000 | ⚠️ 8.012s | ⚠️ 8.012s | - -![Query Performance - EXACT/eql_cast](query_exact_eql_cast_chart.png) - -#### eql_hash - -**Description:** Exact match using EQL HMAC-256 hash function - -**SQL Query:** -```sql -SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1 -``` - -**Parameter:** `Bob Johnson` - -**Table: `string_encrypted_{rows}` with encrypted string values. Index: Hash-based unique index using `eql_v2.hmac_256`.** - -**Indexes:** -```sql -CREATE INDEX -string_encrypted_10000_hash_index -ON string_encrypted_10000 using hash ( - eql_v2.hmac_256(value) -); - -CREATE INDEX -string_encrypted_10000_gin_index -ON string_encrypted_10000 USING GIN ( - eql_v2.bloom_filter(value) -); - -CREATE INDEX -string_encrypted_10000_eql_index -ON string_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 393.98μs | 397.50μs | -| 100,000 | 392.83μs | 404.50μs | -| 1,000,000 | 401.06μs | 408.97μs | - -![Query Performance - EXACT/eql_hash](query_exact_eql_hash_chart.png) - -### MATCH Queries - -#### eql_bloom - -**Description:** Pattern matching using EQL bloom filter containment - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10 -``` - -**Parameter:** `Johnson` - -**Table: `string_encrypted_{rows}` with encrypted string values. Index: Bloom filter index using `eql_v2.bloom_filter`. Query returns LIMIT 10 results.** - -**Indexes:** -```sql -CREATE INDEX -string_encrypted_10000_hash_index -ON string_encrypted_10000 using hash ( - eql_v2.hmac_256(value) -); - -CREATE INDEX -string_encrypted_10000_gin_index -ON string_encrypted_10000 USING GIN ( - eql_v2.bloom_filter(value) -); - -CREATE INDEX -string_encrypted_10000_eql_index -ON string_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 1.07ms | 28.26ms | -| 1,000,000 | 17.53ms | 42.35ms | - -![Query Performance - MATCH/eql_bloom](query_match_eql_bloom_chart.png) - -#### eql_cast_firstname - -**Description:** Pattern matching on first name using EQL cast and LIKE - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 -``` - -**Parameter:** `Bob` - -**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** - -**Indexes:** -```sql -CREATE INDEX -string_encrypted_10000_hash_index -ON string_encrypted_10000 using hash ( - eql_v2.hmac_256(value) -); - -CREATE INDEX -string_encrypted_10000_gin_index -ON string_encrypted_10000 USING GIN ( - eql_v2.bloom_filter(value) -); - -CREATE INDEX -string_encrypted_10000_eql_index -ON string_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -*⚠️ = Query time exceeds 100ms* - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 751.37μs | 27.53ms | -| 1,000,000 | ⚠️ 386.64ms | ⚠️ 418.49ms | - -![Query Performance - MATCH/eql_cast_firstname](query_match_eql_cast_firstname_chart.png) - -#### eql_cast_lastname +| 10,000 | 4.03K | 2.48s | 31.90 MB | -**Description:** Pattern matching on last name using EQL cast and LIKE +![Ingest Throughput - ste_vec_small](ingest_ste_vec_small_throughput_chart.png) -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 -``` +![Ingest Total Time - ste_vec_small](ingest_ste_vec_small_time_chart.png) -**Parameter:** `Johnson` - -**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** - -**Indexes:** -```sql -CREATE INDEX -string_encrypted_10000_hash_index -ON string_encrypted_10000 using hash ( - eql_v2.hmac_256(value) -); - -CREATE INDEX -string_encrypted_10000_gin_index -ON string_encrypted_10000 USING GIN ( - eql_v2.bloom_filter(value) -); - -CREATE INDEX -string_encrypted_10000_eql_index -ON string_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -*⚠️ = Query time exceeds 100ms* - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 1.25ms | 30.30ms | -| 1,000,000 | ⚠️ 132.59ms | ⚠️ 157.06ms | - -![Query Performance - MATCH/eql_cast_lastname](query_match_eql_cast_lastname_chart.png) - -### ORE Queries - -#### exact - -**Description:** Exact match query on encrypted integer - -**SQL Query:** -```sql -SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1 -``` - -**Parameter:** `5000` - -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query returns LIMIT 1 result.** - -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -*⚠️ = Query time exceeds 100ms* - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 464.23μs | 495.74μs | -| 100,000 | ⚠️ 1.905s | ⚠️ 1.901s | - -![Query Performance - ORE/exact](query_ore_exact_chart.png) - -#### range_gt_10 - -**Description:** Range query (greater than) returning 10 results - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10 -``` - -**Parameter:** `5000` - -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value > 5000 LIMIT 10.** - -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 2.39ms | 29.57ms | -| 100,000 | 1.53ms | 27.97ms | - -![Query Performance - ORE/range_gt_10](query_ore_range_gt_10_chart.png) - -#### range_gt_100 - -**Description:** Range query (greater than) returning 100 results - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100 -``` - -**Parameter:** `5000` - -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value > 5000 LIMIT 100.** - -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 14.33ms | 51.92ms | -| 100,000 | 12.35ms | 52.45ms | - -![Query Performance - ORE/range_gt_100](query_ore_range_gt_100_chart.png) - -#### range_lt_10 - -**Description:** Range query (less than) returning 10 results - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10 -``` - -**Parameter:** `5000` - -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 LIMIT 10.** - -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 2.71ms | 27.30ms | -| 100,000 | 1.66ms | 28.69ms | - -![Query Performance - ORE/range_lt_10](query_ore_range_lt_10_chart.png) - -#### range_lt_100 - -**Description:** Range query (less than) returning 100 results - -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100 -``` - -**Parameter:** `5000` - -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 LIMIT 100.** - -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` - -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | 14.85ms | 53.07ms | -| 100,000 | 12.49ms | 52.96ms | - -![Query Performance - ORE/range_lt_100](query_ore_range_lt_100_chart.png) - -#### range_lt_ordered_10 - -**Description:** Ordered range query (less than) with ORDER BY +### String -**SQL Query:** -```sql -SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10 -``` +Tests insertion of encrypted string values. -**Parameter:** `5000` +| Records | Throughput (records/sec) | Total Time | Avg Memory | +|---------|--------------------------|------------|------------| +| 500 | 559.65 | 0.89s | 14.12 MB | +| 1,000 | 1.86K | 0.54s | 16.19 MB | +| 10,000 | 2.83K | 3.54s | 18.23 MB | -**Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. Index: ORE index supporting equality and range queries. Query: WHERE value < 5000 ORDER BY value LIMIT 10.** +![Ingest Throughput - string](ingest_string_throughput_chart.png) -**Indexes:** -```sql -CREATE INDEX -integer_encrypted_10000_eql_index -ON integer_encrypted_10000 ( - value eql_v2.encrypted_operator_class -); -``` +![Ingest Total Time - string](ingest_string_time_chart.png) -*⚠️ = Query time exceeds 100ms* +## Query Performance -| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) | -|---------------|-------------------------|---------------------------| -| 10,000 | ⚠️ 633.49ms | ⚠️ 655.54ms | -| 100,000 | ⚠️ 5.453s | ⚠️ 5.495s | +Per-query-type detail is broken out into separate pages — click into a scenario family for the SQL, per-tier timings, the indexes the planner picked, and the EXPLAIN plan tree. -![Query Performance - ORE/range_lt_ordered_10](query_ore_range_lt_ordered_10_chart.png) +| Query Type | Scenarios | Tiers | Largest-tier median (no decrypt) | Detail | +|-|-|-|-|-| +| COMBO | `bloom_ore_order_limit`, `filtered_group_by`, `top_n_filtered_group_by` | 10,000, 100,000, 1,000,000, 10,000,000 | 98.05ms | [open](combo.md) | +| EXACT | `eql_cast`, `eql_hash` | 10,000, 100,000, 1,000,000, 10,000,000 | 454.21μs | [open](exact.md) | +| GROUP_BY | `low_cardinality_groups_encrypted`, `low_cardinality_groups_plaintext`, `top_n_groups_encrypted`, `top_n_groups_plaintext` | 10,000, 100,000, 1,000,000, 10,000,000 | 864.52ms | [open](group_by.md) | +| MATCH | `eql_bloom`, `eql_cast_firstname`, `eql_cast_lastname` | 10,000, 100,000, 1,000,000, 10,000,000 | 151.23ms | [open](match.md) | +| ORE | `range_gt_10`, `range_gt_100`, `range_highly_selective_gt_10`, `range_highly_selective_gt_count`, `range_lt_10`, `range_lt_100`, `range_lt_hybrid_ordered_10`, `range_selective_gt_100`, `range_selective_gt_count` | 10,000, 100,000, 1,000,000, 10,000,000 | 573.45ms | [open](ore.md) | --- diff --git a/report/combo.md b/report/combo.md new file mode 100644 index 0000000..251daf4 --- /dev/null +++ b/report/combo.md @@ -0,0 +1,1187 @@ +# COMBO Queries + +[← Back to overview](./BENCHMARK_REPORT.md) + +Per-tier query performance. Each scenario lists its SQL, the indexes available on the target table, the indexes the planner actually picked per tier, the timing table, and the full EXPLAIN plan in a collapsed block. + +## bloom_ore_order_limit + +**Description:** Composite predicate: filter by name pattern (bloom), order by age (ORE), limit 10 + +**SQL Query:** +```sql +SELECT id FROM {TABLE} WHERE name LIKE $1 ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10 +``` + +**Parameter:** `Bob` + +**Table: `combo_encrypted_{rows}` with three encrypted columns — `name` (match + hmac), `age` (ORE), `category` (hmac). Indexes: functional GIN on `eql_v2.bloom_filter(name)`, functional btree on `eql_v2.ore_block_u64_8_256(age)`, functional hash on `eql_v2.hmac_256(category)`. **The bloom GIN index engages for the LIKE predicate**, narrowing the input to ~0.01–0.1% of rows; the planner then sorts the small filtered set by `eql_v2.ore_block_u64_8_256(age)` and returns the top 10. The ORE btree doesn't engage here — PostgreSQL can't merge two unrelated indexes on different columns (bloom on `name`, btree on `age`), so the ORDER BY is satisfied by a Sort node above the Bitmap Heap Scan. With the bloom narrowing so aggressively, that Sort is cheap; the cost is dominated by the bloom + heap fetch.** + +**Indexes available on the table:** +```sql +CREATE INDEX +combo_encrypted_10000_name_gin_index +ON combo_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_10000_age_ore_index +ON combo_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_10000_category_hash_index +ON combo_encrypted_10000 USING hash ( + eql_v2.hmac_256(category) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `combo_encrypted_10000_name_gin_index` +- 100,000: `combo_encrypted_100000_name_gin_index` +- 1,000,000: `combo_encrypted_1000000_name_gin_index` +- 10,000,000: `combo_encrypted_10000000_name_gin_index` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 9 | 1.33ms | N/A | +| 100,000 | 10 | 3.04ms | N/A | +| 1,000,000 | 10 | 28.18ms | N/A | +| 10,000,000 | 10 | ⚠️ 208.49ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Sort + Bitmap Heap Scan on combo_encrypted_10000 + Bitmap Index Scan using combo_encrypted_10000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1603,1789,1164,10,1555}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1603,1789,1164,10,1555}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 60.74, + "Total Cost": 60.75 + } + ], + "Startup Cost": 60.74, + "Total Cost": 60.75 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Sort + Bitmap Heap Scan on combo_encrypted_100000 + Bitmap Index Scan using combo_encrypted_100000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{10,1789,1555,36,1603,1164}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{10,1789,1555,36,1603,1164}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 97.87, + "Total Cost": 97.87 + } + ], + "Startup Cost": 97.87, + "Total Cost": 97.87 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Sort + Bitmap Heap Scan on combo_encrypted_1000000 + Bitmap Index Scan using combo_encrypted_1000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1789,1164,10,1555,36}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1789,1164,10,1555,36}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.48 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 316.49, + "Total Cost": 316.5 + } + ], + "Startup Cost": 316.49, + "Total Cost": 316.5 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Sort + Bitmap Heap Scan on combo_encrypted_10000000 + Bitmap Index Scan using combo_encrypted_10000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,10,1603,1555,36}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,10,1603,1555,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.61 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 2300.62, + "Total Cost": 2300.62 + } + ], + "Startup Cost": 2300.62, + "Total Cost": 2300.62 + } + } +] +``` + +
+ +![Query Performance - COMBO/bloom_ore_order_limit](query_combo_bloom_ore_order_limit_chart.png) + +## filtered_group_by + +**Description:** Composite predicate: filter by name pattern, GROUP BY category + +**SQL Query:** +```sql +SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} WHERE name LIKE $1 GROUP BY 1 +``` + +**Parameter:** `Bob` + +**Table: `combo_encrypted_{rows}`. Query: `SELECT eql_v2.hmac_256(category), count(*) FROM tbl WHERE name LIKE $1 GROUP BY 1`. Bloom filter on `name` filters the input set; HashAggregate then groups the small post-filter set by the 32-byte category HMAC. With ~0.01-0.1% of names matching a typical bloom pattern and 250 category buckets, the aggregate stage is essentially free — the cost is bloom filter scan plus per-matching-row HMAC.** + +**Indexes available on the table:** +```sql +CREATE INDEX +combo_encrypted_10000_name_gin_index +ON combo_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_10000_age_ore_index +ON combo_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_10000_category_hash_index +ON combo_encrypted_10000 USING hash ( + eql_v2.hmac_256(category) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `combo_encrypted_10000_name_gin_index` +- 100,000: `combo_encrypted_100000_name_gin_index` +- 1,000,000: `combo_encrypted_1000000_name_gin_index` +- 10,000,000: `combo_encrypted_10000000_name_gin_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 9 | 954.55μs | N/A | +| 100,000 | 42 | 1.03ms | N/A | +| 1,000,000 | 235 | 6.11ms | N/A | +| 10,000,000 | 250 | 43.43ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_10000 + Bitmap Index Scan using combo_encrypted_10000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,10,1555,1789,1603,36}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,10,1555,1789,1603,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.49 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 60.5, + "Total Cost": 60.5 + } + ], + "Startup Cost": 60.5, + "Strategy": "Sorted", + "Total Cost": 60.52 + } + } +] +``` + +**100,000 rows** + +``` +Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_100000 + Bitmap Index Scan using combo_encrypted_100000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,10,1164,36,1555,1789}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,10,1164,36,1555,1789}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.61 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 97.62, + "Total Cost": 97.63 + } + ], + "Startup Cost": 97.62, + "Strategy": "Sorted", + "Total Cost": 97.64 + } + } +] +``` + +**1,000,000 rows** + +``` +Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_1000000 + Bitmap Index Scan using combo_encrypted_1000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,36,1789,1603,1164,10}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,36,1789,1603,1164,10}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.24 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 316.25, + "Total Cost": 316.25 + } + ], + "Startup Cost": 316.25, + "Strategy": "Sorted", + "Total Cost": 316.27 + } + } +] +``` + +**10,000,000 rows** + +``` +Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_10000000 + Bitmap Index Scan using combo_encrypted_10000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,1555,10,36,1603}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,1555,10,36,1603}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.36 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 2300.37, + "Total Cost": 2300.38 + } + ], + "Startup Cost": 2300.37, + "Strategy": "Sorted", + "Total Cost": 2300.39 + } + } +] +``` + +
+ +![Query Performance - COMBO/filtered_group_by](query_combo_filtered_group_by_chart.png) + +## top_n_filtered_group_by + +**Description:** Dashboard analytic: top 10 categories for customers matching a name pattern + +**SQL Query:** +```sql +SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10 +``` + +**Parameter:** `Bob` + +**Table: `combo_encrypted_{rows}`. Query: `SELECT eql_v2.hmac_256(category), count(*) FROM tbl WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10`. Same shape as `filtered_group_by` with an outer Top-N sort + LIMIT 10. Realistic analytics shape for surfacing the categories that contain the most customers matching a filter, without revealing the underlying names or category labels.** + +**Indexes available on the table:** +```sql +CREATE INDEX +combo_encrypted_10000_name_gin_index +ON combo_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_10000_age_ore_index +ON combo_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_10000_category_hash_index +ON combo_encrypted_10000 USING hash ( + eql_v2.hmac_256(category) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `combo_encrypted_10000_name_gin_index` +- 100,000: `combo_encrypted_100000_name_gin_index` +- 1,000,000: `combo_encrypted_1000000_name_gin_index` +- 10,000,000: `combo_encrypted_10000000_name_gin_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 9 | 837.68μs | N/A | +| 100,000 | 10 | 916.23μs | N/A | +| 1,000,000 | 10 | 5.03ms | N/A | +| 10,000,000 | 10 | 43.19ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_10000 + Bitmap Index Scan using combo_encrypted_10000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1164,10,1555}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1164,10,1555}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.49 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 60.5, + "Total Cost": 60.5 + } + ], + "Startup Cost": 60.5, + "Strategy": "Sorted", + "Total Cost": 60.52 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 60.53, + "Total Cost": 60.53 + } + ], + "Startup Cost": 60.53, + "Total Cost": 60.53 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_100000 + Bitmap Index Scan using combo_encrypted_100000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.61 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 97.62, + "Total Cost": 97.63 + } + ], + "Startup Cost": 97.62, + "Strategy": "Sorted", + "Total Cost": 97.64 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 97.65, + "Total Cost": 97.66 + } + ], + "Startup Cost": 97.65, + "Total Cost": 97.66 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_1000000 + Bitmap Index Scan using combo_encrypted_1000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,1164,1603,36,10,1789}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,1164,1603,36,10,1789}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.24 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 316.25, + "Total Cost": 316.25 + } + ], + "Startup Cost": 316.25, + "Strategy": "Sorted", + "Total Cost": 316.27 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 316.28, + "Total Cost": 316.28 + } + ], + "Startup Cost": 316.28, + "Total Cost": 316.28 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Sort + Bitmap Heap Scan on combo_encrypted_10000000 + Bitmap Index Scan using combo_encrypted_10000000_name_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1555,10,1164,1789,36}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1555,10,1164,1789,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.36 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 2300.37, + "Total Cost": 2300.38 + } + ], + "Startup Cost": 2300.37, + "Strategy": "Sorted", + "Total Cost": 2300.39 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 2300.4, + "Total Cost": 2300.41 + } + ], + "Startup Cost": 2300.4, + "Total Cost": 2300.41 + } + } +] +``` + +
+ +![Query Performance - COMBO/top_n_filtered_group_by](query_combo_top_n_filtered_group_by_chart.png) + diff --git a/report/exact.md b/report/exact.md new file mode 100644 index 0000000..121e681 --- /dev/null +++ b/report/exact.md @@ -0,0 +1,444 @@ +# EXACT Queries + +[← Back to overview](./BENCHMARK_REPORT.md) + +Per-tier query performance. Each scenario lists its SQL, the indexes available on the target table, the indexes the planner actually picked per tier, the timing table, and the full EXPLAIN plan in a collapsed block. + +## eql_cast + +**Description:** Exact match using EQL cast operator + +**SQL Query:** +```sql +SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1 +``` + +**Parameter:** `Bob Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: UNIQUE index on the encrypted value column.** + +**Indexes available on the table:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `string_encrypted_10000_hash_index` +- 100,000: `string_encrypted_100000_hash_index` +- 1,000,000: `string_encrypted_1000000_hash_index` +- 10,000,000: `string_encrypted_10000000_hash_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 497.31μs | 25.63ms | +| 100,000 | 1 | 488.75μs | 25.52ms | +| 1,000,000 | 1 | 452.76μs | 25.55ms | +| 10,000,000 | 1 | 469.54μs | 25.63ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Index Scan using string_encrypted_10000_hash_index on string_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405'::text)", + "Index Name": "string_encrypted_10000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Index Scan using string_encrypted_100000_hash_index on string_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7'::text)", + "Index Name": "string_encrypted_100000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Index Scan using string_encrypted_1000000_hash_index on string_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f'::text)", + "Index Name": "string_encrypted_1000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "string_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 21105.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.22 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Index Scan using string_encrypted_10000000_hash_index on string_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677'::text)", + "Index Name": "string_encrypted_10000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 8, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 38.14 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.77 + } + } +] +``` + +
+ +![Query Performance - EXACT/eql_cast](query_exact_eql_cast_chart.png) + +## eql_hash + +**Description:** Exact match using EQL HMAC-256 hash function + +**SQL Query:** +```sql +SELECT value FROM {TABLE} WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1 +``` + +**Parameter:** `Bob Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: Hash-based unique index using `eql_v2.hmac_256`.** + +**Indexes available on the table:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `string_encrypted_10000_hash_index` +- 100,000: `string_encrypted_100000_hash_index` +- 1,000,000: `string_encrypted_1000000_hash_index` +- 10,000,000: `string_encrypted_10000000_hash_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 430.15μs | 25.40ms | +| 100,000 | 1 | 437.40μs | 25.68ms | +| 1,000,000 | 1 | 452.30μs | 25.50ms | +| 10,000,000 | 1 | 455.17μs | 25.72ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Index Scan using string_encrypted_10000_hash_index on string_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405'::text)", + "Index Name": "string_encrypted_10000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Index Scan using string_encrypted_100000_hash_index on string_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7'::text)", + "Index Name": "string_encrypted_100000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Index Scan using string_encrypted_1000000_hash_index on string_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f'::text)", + "Index Name": "string_encrypted_1000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "string_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 21105.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.22 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Index Scan using string_encrypted_10000000_hash_index on string_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677'::text)", + "Index Name": "string_encrypted_10000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 8, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 38.14 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.77 + } + } +] +``` + +
+ +![Query Performance - EXACT/eql_hash](query_exact_eql_hash_chart.png) + diff --git a/report/group_by.md b/report/group_by.md new file mode 100644 index 0000000..d1b516f --- /dev/null +++ b/report/group_by.md @@ -0,0 +1,1652 @@ +# GROUP_BY Queries + +[← Back to overview](./BENCHMARK_REPORT.md) + +Per-tier query performance. Each scenario lists its SQL, the indexes available on the target table, the indexes the planner actually picked per tier, the timing table, and the full EXPLAIN plan in a collapsed block. + +## low_cardinality_groups_encrypted + +**Description:** Low-cardinality GROUP BY (~250 buckets) on `eql_v2.hmac_256(value)`, wrapped in `count(*)` to isolate aggregation cost from emit cost + +**SQL Query:** +```sql +SELECT count(*) FROM (SELECT 1 FROM {TABLE} GROUP BY eql_v2.hmac_256(value)) g +``` + +**Table: `category_encrypted_{rows}` with encrypted categorical values (`CAT_001`..`CAT_250`, uniform random — ~250 distinct buckets). The encrypted value carries an `hm` HMAC term via the `unique` search index. **Index: hash index on `eql_v2.hmac_256(value)`, but `GROUP BY` doesn't engage it directly** — the planner picks `HashAggregate`, building an in-memory hash table keyed on the 32-byte HMAC. With only 250 distinct keys the hash table fits comfortably in default `work_mem`. The outer `count(*)` keeps the result-set emission at exactly one row, so wall-clock time tracks aggregation cost. The companion `low_cardinality_groups_plaintext` scenario runs the same query shape against an unindexed TEXT column for a baseline.** + +**Indexes available on the table:** +```sql +CREATE INDEX +category_encrypted_10000_hash_index +ON category_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 2.73ms | N/A | +| 100,000 | 1 | 27.33ms | N/A | +| 1,000,000 | 1 | ⚠️ 124.61ms | N/A | +| 10,000,000 | 1 | ⚠️ 1.466s | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Aggregate + Aggregate (Hashed) + Seq Scan on category_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_10000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 36, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 580.0 + } + ], + "Startup Cost": 605.0, + "Strategy": "Hashed", + "Total Cost": 608.12 + } + ], + "Startup Cost": 611.25, + "Strategy": "Plain", + "Total Cost": 611.26 + } + } +] +``` + +**100,000 rows** + +``` +Aggregate + Aggregate (Hashed) + Seq Scan on category_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_100000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 36, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 32, + "Relation Name": "category_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 5796.0 + } + ], + "Startup Cost": 6046.0, + "Strategy": "Hashed", + "Total Cost": 6049.12 + } + ], + "Startup Cost": 6052.25, + "Strategy": "Plain", + "Total Cost": 6052.26 + } + } +] +``` + +**1,000,000 rows** + +``` +Aggregate + Group + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 32, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416665, + "Plan Width": 32, + "Relation Name": "category_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 50663.31 + } + ], + "Startup Cost": 51704.97, + "Strategy": "Hashed", + "Total Cost": 51708.1 + } + ], + "Sort Key": [ + "((((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 51718.05, + "Total Cost": 51718.68 + } + ], + "Startup Cost": 52718.08, + "Total Cost": 52776.41, + "Workers Planned": 2 + } + ], + "Startup Cost": 52718.08, + "Total Cost": 52778.29 + } + ], + "Startup Cost": 52781.41, + "Strategy": "Plain", + "Total Cost": 52781.42 + } + } +] +``` + +**10,000,000 rows** + +``` +Aggregate + Group + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 8, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": true, + "Optimization": true + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 32, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166667, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 506629.33 + } + ], + "Startup Cost": 517046.0, + "Strategy": "Hashed", + "Total Cost": 517049.13 + } + ], + "Sort Key": [ + "((((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 517059.08, + "Total Cost": 517059.71 + } + ], + "Startup Cost": 518059.11, + "Total Cost": 518117.45, + "Workers Planned": 2 + } + ], + "Startup Cost": 518059.11, + "Total Cost": 518119.32 + } + ], + "Startup Cost": 518122.45, + "Strategy": "Plain", + "Total Cost": 518122.46 + } + } +] +``` + +
+ +![Query Performance - GROUP_BY/low_cardinality_groups_encrypted](query_group_by_low_cardinality_groups_encrypted_chart.png) + +## low_cardinality_groups_plaintext + +**Description:** Plaintext baseline: low-cardinality GROUP BY on a plain TEXT column, same query shape as the encrypted scenario + +**SQL Query:** +```sql +SELECT count(*) FROM (SELECT 1 FROM {TABLE} GROUP BY value) g +``` + +**Table: `category_plaintext_{rows}` with the same `CAT_001`..`CAT_250` distribution (uniform random, populated by SQL via `mise run prepare:category_plaintext` — no encryption-client dependency). Index: none. The wall-clock delta between this and `low_cardinality_groups_encrypted` is the EQL recipe's overhead relative to a bare-PG aggregate at the same row count and cardinality.** + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 1.51ms | N/A | +| 100,000 | 1 | 9.69ms | N/A | +| 1,000,000 | 1 | 40.15ms | N/A | +| 10,000,000 | 1 | ⚠️ 430.47ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Aggregate + Aggregate (Hashed) + Seq Scan on category_plaintext_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 12, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000", + "Startup Cost": 0.0, + "Total Cost": 155.0 + } + ], + "Startup Cost": 180.0, + "Strategy": "Hashed", + "Total Cost": 182.5 + } + ], + "Startup Cost": 185.62, + "Strategy": "Plain", + "Total Cost": 185.63 + } + } +] +``` + +**100,000 rows** + +``` +Aggregate + Aggregate (Hashed) + Seq Scan on category_plaintext_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_100000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 12, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 8, + "Relation Name": "category_plaintext_100000", + "Startup Cost": 0.0, + "Total Cost": 1541.0 + } + ], + "Startup Cost": 1791.0, + "Strategy": "Hashed", + "Total Cost": 1793.5 + } + ], + "Startup Cost": 1796.62, + "Strategy": "Plain", + "Total Cost": 1796.63 + } + } +] +``` + +**1,000,000 rows** + +``` +Aggregate + Group + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_1000000.value" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 12, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_1000000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 8, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416667, + "Plan Width": 8, + "Relation Name": "category_plaintext_1000000", + "Startup Cost": 0.0, + "Total Cost": 9572.67 + } + ], + "Startup Cost": 10614.33, + "Strategy": "Hashed", + "Total Cost": 10616.83 + } + ], + "Sort Key": [ + "category_plaintext_1000000.value" + ], + "Startup Cost": 10626.79, + "Total Cost": 10627.42 + } + ], + "Startup Cost": 11626.82, + "Total Cost": 11685.15, + "Workers Planned": 2 + } + ], + "Startup Cost": 11626.82, + "Total Cost": 11686.4 + } + ], + "Startup Cost": 11689.53, + "Strategy": "Plain", + "Total Cost": 11689.54 + } + } +] +``` + +**10,000,000 rows** + +``` +Aggregate + Group + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000000.value" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 12, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 8, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166608, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000000", + "Startup Cost": 0.0, + "Total Cost": 95721.08 + } + ], + "Startup Cost": 106137.6, + "Strategy": "Hashed", + "Total Cost": 106140.1 + } + ], + "Sort Key": [ + "category_plaintext_10000000.value" + ], + "Startup Cost": 106150.06, + "Total Cost": 106150.69 + } + ], + "Startup Cost": 107150.08, + "Total Cost": 107208.42, + "Workers Planned": 2 + } + ], + "Startup Cost": 107150.08, + "Total Cost": 107209.67 + } + ], + "Startup Cost": 107212.8, + "Strategy": "Plain", + "Total Cost": 107212.81 + } + } +] +``` + +
+ +![Query Performance - GROUP_BY/low_cardinality_groups_plaintext](query_group_by_low_cardinality_groups_plaintext_chart.png) + +## top_n_groups_encrypted + +**Description:** Dashboard analytic: top 10 categories by frequency, EQL recipe form + +**SQL Query:** +```sql +SELECT eql_v2.hmac_256(value), count(*) FROM {TABLE} GROUP BY 1 ORDER BY count(*) DESC LIMIT 10 +``` + +**Table: `category_encrypted_{rows}` (same data as the `low_cardinality_*` scenarios above). Query: `SELECT eql_v2.hmac_256(value), count(*) FROM tbl GROUP BY 1 ORDER BY count(*) DESC LIMIT 10`. The bench always emits 10 rows regardless of input size, so the cost is dominated by the inner HashAggregate (per-row HMAC + hash-table insert) plus a tiny sort over the 250 group entries. Realistic shape for analytics queries that surface the most common categories in an encrypted dataset.** + +**Indexes available on the table:** +```sql +CREATE INDEX +category_encrypted_10000_hash_index +ON category_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 2.87ms | N/A | +| 100,000 | 10 | 27.79ms | N/A | +| 1,000,000 | 10 | 95.87ms | N/A | +| 10,000,000 | 10 | ⚠️ 1.312s | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 580.0 + } + ], + "Startup Cost": 630.0, + "Strategy": "Hashed", + "Total Cost": 633.12 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 638.53, + "Total Cost": 639.15 + } + ], + "Startup Cost": 638.53, + "Total Cost": 638.55 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 32, + "Relation Name": "category_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 5796.0 + } + ], + "Startup Cost": 6296.0, + "Strategy": "Hashed", + "Total Cost": 6299.12 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 6304.53, + "Total Cost": 6305.15 + } + ], + "Startup Cost": 6304.53, + "Total Cost": 6304.55 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416665, + "Plan Width": 32, + "Relation Name": "category_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 50663.31 + } + ], + "Startup Cost": 52746.63, + "Strategy": "Hashed", + "Total Cost": 52749.76 + } + ], + "Sort Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 52759.72, + "Total Cost": 52760.34 + } + ], + "Startup Cost": 53759.74, + "Total Cost": 53818.08, + "Workers Planned": 2 + } + ], + "Startup Cost": 53759.74, + "Strategy": "Sorted", + "Total Cost": 53823.7 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 53829.1, + "Total Cost": 53829.73 + } + ], + "Startup Cost": 53829.1, + "Total Cost": 53829.13 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 8, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": true, + "Optimization": true + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166667, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 506629.33 + } + ], + "Startup Cost": 527462.67, + "Strategy": "Hashed", + "Total Cost": 527465.79 + } + ], + "Sort Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 527475.75, + "Total Cost": 527476.38 + } + ], + "Startup Cost": 528475.78, + "Total Cost": 528534.11, + "Workers Planned": 2 + } + ], + "Startup Cost": 528475.78, + "Strategy": "Sorted", + "Total Cost": 528539.74 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 528545.14, + "Total Cost": 528545.76 + } + ], + "Startup Cost": 528545.14, + "Total Cost": 528545.16 + } + } +] +``` + +
+ +![Query Performance - GROUP_BY/top_n_groups_encrypted](query_group_by_top_n_groups_encrypted_chart.png) + +## top_n_groups_plaintext + +**Description:** Plaintext baseline: top 10 categories by frequency on a plain TEXT column + +**SQL Query:** +```sql +SELECT value, count(*) FROM {TABLE} GROUP BY 1 ORDER BY count(*) DESC LIMIT 10 +``` + +**Table: `category_plaintext_{rows}`. Same query shape as the encrypted top-N scenario; the delta is the EQL recipe's overhead for the same shape on the same cardinality data.** + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.61ms | N/A | +| 100,000 | 10 | 10.15ms | N/A | +| 1,000,000 | 10 | 38.71ms | N/A | +| 10,000,000 | 10 | ⚠️ 461.75ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000", + "Startup Cost": 0.0, + "Total Cost": 155.0 + } + ], + "Startup Cost": 205.0, + "Strategy": "Hashed", + "Total Cost": 207.5 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 212.9, + "Total Cost": 213.53 + } + ], + "Startup Cost": 212.9, + "Total Cost": 212.93 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 8, + "Relation Name": "category_plaintext_100000", + "Startup Cost": 0.0, + "Total Cost": 1541.0 + } + ], + "Startup Cost": 2041.0, + "Strategy": "Hashed", + "Total Cost": 2043.5 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 2048.9, + "Total Cost": 2049.53 + } + ], + "Startup Cost": 2048.9, + "Total Cost": 2048.93 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416667, + "Plan Width": 8, + "Relation Name": "category_plaintext_1000000", + "Startup Cost": 0.0, + "Total Cost": 9572.67 + } + ], + "Startup Cost": 11656.0, + "Strategy": "Hashed", + "Total Cost": 11658.5 + } + ], + "Sort Key": [ + "value" + ], + "Startup Cost": 11668.46, + "Total Cost": 11669.08 + } + ], + "Startup Cost": 12668.48, + "Total Cost": 12726.82, + "Workers Planned": 2 + } + ], + "Startup Cost": 12668.48, + "Strategy": "Sorted", + "Total Cost": 12731.82 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 12737.22, + "Total Cost": 12737.85 + } + ], + "Startup Cost": 12737.22, + "Total Cost": 12737.25 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Sort + Aggregate (Sorted) + Gather Merge + Sort + Aggregate (Hashed) + Seq Scan on category_plaintext_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166608, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000000", + "Startup Cost": 0.0, + "Total Cost": 95721.08 + } + ], + "Startup Cost": 116554.12, + "Strategy": "Hashed", + "Total Cost": 116556.62 + } + ], + "Sort Key": [ + "value" + ], + "Startup Cost": 116566.58, + "Total Cost": 116567.21 + } + ], + "Startup Cost": 117566.6, + "Total Cost": 117624.94, + "Workers Planned": 2 + } + ], + "Startup Cost": 117566.6, + "Strategy": "Sorted", + "Total Cost": 117629.94 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 117635.34, + "Total Cost": 117635.97 + } + ], + "Startup Cost": 117635.34, + "Total Cost": 117635.37 + } + } +] +``` + +
+ +![Query Performance - GROUP_BY/top_n_groups_plaintext](query_group_by_top_n_groups_plaintext_chart.png) + diff --git a/report/ingest_comparison_throughput_10000.png b/report/ingest_comparison_throughput_10000.png new file mode 100644 index 0000000..f7dd014 Binary files /dev/null and b/report/ingest_comparison_throughput_10000.png differ diff --git a/report/ingest_comparison_time_10000.png b/report/ingest_comparison_time_10000.png new file mode 100644 index 0000000..abe3212 Binary files /dev/null and b/report/ingest_comparison_time_10000.png differ diff --git a/report/ingest_comparison_time_10000_filtered.png b/report/ingest_comparison_time_10000_filtered.png new file mode 100644 index 0000000..1240015 Binary files /dev/null and b/report/ingest_comparison_time_10000_filtered.png differ diff --git a/report/ingest_int_chart.png b/report/ingest_int_chart.png deleted file mode 100644 index f3438f5..0000000 Binary files a/report/ingest_int_chart.png and /dev/null differ diff --git a/report/ingest_int_throughput_chart.png b/report/ingest_int_throughput_chart.png new file mode 100644 index 0000000..2d256d1 Binary files /dev/null and b/report/ingest_int_throughput_chart.png differ diff --git a/report/ingest_int_time_chart.png b/report/ingest_int_time_chart.png new file mode 100644 index 0000000..b324cfa Binary files /dev/null and b/report/ingest_int_time_chart.png differ diff --git a/report/ingest_json_small_chart.png b/report/ingest_json_small_chart.png deleted file mode 100644 index 037ad2e..0000000 Binary files a/report/ingest_json_small_chart.png and /dev/null differ diff --git a/report/ingest_json_small_throughput_chart.png b/report/ingest_json_small_throughput_chart.png new file mode 100644 index 0000000..7f13b80 Binary files /dev/null and b/report/ingest_json_small_throughput_chart.png differ diff --git a/report/ingest_json_small_time_chart.png b/report/ingest_json_small_time_chart.png new file mode 100644 index 0000000..e6cbbd0 Binary files /dev/null and b/report/ingest_json_small_time_chart.png differ diff --git a/report/ingest_ste_vec_small_throughput_chart.png b/report/ingest_ste_vec_small_throughput_chart.png new file mode 100644 index 0000000..b7db65a Binary files /dev/null and b/report/ingest_ste_vec_small_throughput_chart.png differ diff --git a/report/ingest_ste_vec_small_time_chart.png b/report/ingest_ste_vec_small_time_chart.png new file mode 100644 index 0000000..5b755ec Binary files /dev/null and b/report/ingest_ste_vec_small_time_chart.png differ diff --git a/report/ingest_string_chart.png b/report/ingest_string_chart.png deleted file mode 100644 index f25b46e..0000000 Binary files a/report/ingest_string_chart.png and /dev/null differ diff --git a/report/ingest_string_throughput_chart.png b/report/ingest_string_throughput_chart.png new file mode 100644 index 0000000..b23d353 Binary files /dev/null and b/report/ingest_string_throughput_chart.png differ diff --git a/report/ingest_string_time_chart.png b/report/ingest_string_time_chart.png new file mode 100644 index 0000000..db4a916 Binary files /dev/null and b/report/ingest_string_time_chart.png differ diff --git a/report/match.md b/report/match.md new file mode 100644 index 0000000..d41391a --- /dev/null +++ b/report/match.md @@ -0,0 +1,823 @@ +# MATCH Queries + +[← Back to overview](./BENCHMARK_REPORT.md) + +Per-tier query performance. Each scenario lists its SQL, the indexes available on the target table, the indexes the planner actually picked per tier, the timing table, and the full EXPLAIN plan in a collapsed block. + +## eql_bloom + +**Description:** Pattern matching using EQL bloom filter containment + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10 +``` + +**Parameter:** `Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: Bloom filter index using `eql_v2.bloom_filter`. Query returns LIMIT 10 results.** + +**Indexes available on the table:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `string_encrypted_10000_gin_index` +- 100,000: `string_encrypted_100000_gin_index` +- 1,000,000: `string_encrypted_1000000_gin_index` +- 10,000,000: `string_encrypted_10000000_gin_index` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.02ms | 28.36ms | +| 100,000 | 10 | 3.48ms | 27.41ms | +| 1,000,000 | 10 | 21.50ms | 44.84ms | +| 10,000,000 | 10 | ⚠️ 215.72ms | ⚠️ 237.82ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000 + Bitmap Index Scan using string_encrypted_10000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1659,2024,543,1967,518,1381,242,1185,450,290,835,820,1987,765,1846,237,461,44,1609,523,1715,1988,1098,702,97,574,1665,1061,513}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 264.6 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1659,2024,543,1967,518,1381,242,1185,450,290,835,820,1987,765,1846,237,461,44,1609,523,1715,1988,1098,702,97,574,1665,1061,513}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + ], + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_100000 + Bitmap Index Scan using string_encrypted_100000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,518,1659,1988,1098,44,765,574,513,2024,290,450,702,543,1967,1196,1381,1715,1185,97,237,1609,1061,1846,1665,242,820,835,1987,523}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 458.47 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,518,1659,1988,1098,44,765,574,513,2024,290,450,702,543,1967,1196,1381,1715,1185,97,237,1609,1061,1846,1665,242,820,835,1987,523}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + ], + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_1000000 + Bitmap Index Scan using string_encrypted_1000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1967,1988,702,2024,1665,1185,290,835,765,461,523,1987,1715,1659,543,518,820,574,1098,450,242,1061,237,1609,97,513,1381,44,1846}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1526.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1967,1988,702,2024,1665,1185,290,835,765,461,523,1987,1715,1659,543,518,820,574,1098,450,242,1061,237,1609,97,513,1381,44,1846}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + ], + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000000 + Bitmap Index Scan using string_encrypted_10000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{574,702,1846,237,1659,44,242,1967,1196,518,290,1381,1665,450,1609,835,2024,513,1098,765,820,1715,1185,1987,97,1061,1988,523,543,461}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 11270.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{574,702,1846,237,1659,44,242,1967,1196,518,290,1381,1665,450,1609,835,2024,513,1098,765,820,1715,1185,1987,97,1061,1988,523,543,461}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + ], + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + } +] +``` + +
+ +![Query Performance - MATCH/eql_bloom](query_match_eql_bloom_chart.png) + +## eql_cast_firstname + +**Description:** Pattern matching on first name using EQL cast and LIKE + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 +``` + +**Parameter:** `Bob` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** + +**Indexes available on the table:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `string_encrypted_10000_gin_index` +- 100,000: `string_encrypted_100000_gin_index` +- 1,000,000: `string_encrypted_1000000_gin_index` +- 10,000,000: `string_encrypted_10000000_gin_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 729.02μs | 28.41ms | +| 100,000 | 10 | 1.04ms | 25.62ms | +| 1,000,000 | 10 | 4.65ms | 28.34ms | +| 10,000,000 | 10 | 35.48ms | 60.96ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000 + Bitmap Index Scan using string_encrypted_10000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1603,1164,10,1555,1789}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1603,1164,10,1555,1789}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + ], + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_100000 + Bitmap Index Scan using string_encrypted_100000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1555,10,36,1603,1164,1789}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1555,10,36,1603,1164,1789}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + ], + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_1000000 + Bitmap Index Scan using string_encrypted_1000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,10,1164,1555,1603,1789}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 307.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,10,1164,1555,1603,1789}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 307.85, + "Total Cost": 312.36 + } + ], + "Startup Cost": 307.85, + "Total Cost": 312.36 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000000 + Bitmap Index Scan using string_encrypted_10000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2254.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 2254.85, + "Total Cost": 2259.36 + } + ], + "Startup Cost": 2254.85, + "Total Cost": 2259.36 + } + } +] +``` + +
+ +![Query Performance - MATCH/eql_cast_firstname](query_match_eql_cast_firstname_chart.png) + +## eql_cast_lastname + +**Description:** Pattern matching on last name using EQL cast and LIKE + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value LIKE $1 LIMIT 10 +``` + +**Parameter:** `Johnson` + +**Table: `string_encrypted_{rows}` with encrypted string values. Index: MATCH index for substring searches. Query returns LIMIT 10 results.** + +**Indexes available on the table:** +```sql +CREATE INDEX +string_encrypted_10000_hash_index +ON string_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); + +CREATE INDEX +string_encrypted_10000_gin_index +ON string_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `string_encrypted_10000_gin_index` +- 100,000: `string_encrypted_100000_gin_index` +- 1,000,000: `string_encrypted_1000000_gin_index` +- 10,000,000: `string_encrypted_10000000_gin_index` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.55ms | 30.64ms | +| 100,000 | 10 | 3.12ms | 27.96ms | +| 1,000,000 | 10 | 21.38ms | 44.58ms | +| 10,000,000 | 10 | ⚠️ 210.49ms | ⚠️ 241.26ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000 + Bitmap Index Scan using string_encrypted_10000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1381,1185,1609,835,1715,513,1967,543,461,1098,237,523,1987,820,1196,1846,1665,242,765,290,1061,702,44,1659,97,574,518,2024,450,1988}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 264.6 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1381,1185,1609,835,1715,513,1967,543,461,1098,237,523,1987,820,1196,1846,1665,242,765,290,1061,702,44,1659,97,574,518,2024,450,1988}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + ], + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_100000 + Bitmap Index Scan using string_encrypted_100000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1185,518,820,835,1987,237,574,1715,702,1988,290,1196,513,242,97,44,1609,461,1381,2024,765,1659,1967,1665,523,1846,450,1098,543,1061}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 458.47 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1185,518,820,835,1987,237,574,1715,702,1988,290,1196,513,242,97,44,1609,461,1381,2024,765,1659,1967,1665,523,1846,450,1098,543,1061}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + ], + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_1000000 + Bitmap Index Scan using string_encrypted_1000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1987,543,1609,574,765,835,461,1967,513,1665,97,523,1185,1061,450,1846,702,1659,2024,518,1196,1098,242,237,1381,1715,1988,44,820,290}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1526.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1987,543,1609,574,765,835,461,1967,513,1665,97,523,1185,1061,450,1846,702,1659,2024,518,1196,1098,242,237,1381,1715,1988,44,820,290}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + ], + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Bitmap Heap Scan on string_encrypted_10000000 + Bitmap Index Scan using string_encrypted_10000000_gin_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,450,513,765,1846,2024,1665,543,97,242,1609,835,1061,290,1987,1381,1715,237,1967,574,1185,44,523,702,1196,1988,1098,820,518,1659}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 11270.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,450,513,765,1846,2024,1665,543,97,242,1609,835,1061,290,1987,1381,1715,237,1967,574,1185,44,523,702,1196,1988,1098,820,518,1659}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + ], + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + } +] +``` + +
+ +![Query Performance - MATCH/eql_cast_lastname](query_match_eql_cast_lastname_chart.png) + diff --git a/report/ore.md b/report/ore.md new file mode 100644 index 0000000..08a912d --- /dev/null +++ b/report/ore.md @@ -0,0 +1,2166 @@ +# ORE Queries + +[← Back to overview](./BENCHMARK_REPORT.md) + +Per-tier query performance. Each scenario lists its SQL, the indexes available on the target table, the indexes the planner actually picked per tier, the timing table, and the full EXPLAIN plan in a collapsed block. + +## range_gt_10 + +**Description:** Range query (greater than) returning 10 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. The bare-form `<` / `>` operators inline to `eql_v2.ore_block_u64_8_256(a) op eql_v2.ore_block_u64_8_256(b)` post-2.3, so the index engages without query rewriting. Query: WHERE value > 5000 LIMIT 10.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.09ms | 26.92ms | +| 100,000 | 10 | 1.61ms | 29.41ms | +| 1,000,000 | 10 | 1.34ms | 29.73ms | +| 10,000,000 | 10 | 1.42ms | 29.93ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6505e5d0db03c5dd653e9ad5bbbf37b01663a79c310597f2cca4feea88f7f863fdf7e0a642334bc851ef546007bab4c16748773788325e7693c2983f64e84420fefe66ebd55fba175369ff1cb035880cace69ada40eaa9c4e562258c34290667bbe9f9e089e37dee0a7fa68a1d6ecbb0e227b1711af6f0c662e7b9f665d2460a0460e1c7c84171e8115895dca66cfde0a3d5c59e35674c512b243ce1e9d6a2ec34d88a8d54d49cb3ed640b680b20d58dd07744ee54fcccb4e383b625ffacc120fe18629047851013df66e79cccf101ba839bb63c98bfa01121a41bf239c283e288df5d9730e3f463e905c464c9f7be623a47c2b4f9f948270cd132c67cbb3ef0e32320e83d411a6b4427aed3f657e7d\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7766.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcbfbaaf8c7a29ce322f2feca2f5d3c6e328479bb189afe2e41b80a02090795ddbb699a2e1bffcd2230148afe271b8c45a54f37c24a512ac8a25770563056b21c1d266bc81d1f57e26823716a03123c9ab2eb62ad6638179e7fa5e5e429a09c6462b4f91bf55a6a67dee3ec8989db162b9043b601675f777bfbdb67ae8099a830b561298bdf02bcde34e856ee07d24b63ecb4aa992f069413c89977f7f843a352873a8d9b8dcee7f144d2777d467d872804291cdfbc6a23e2e0a5d2e6577a575de6c23eacec41b5fb2a12749cec33753d81e6e51d58ad801dcb4f8f2ea4e52591bf9f3ed15f7ab4f3ae314bfa07216e11091fbd9752548b51cbd1b595653eb340ad259388bbdb8187a324e364151bf267c\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77911.0 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc62a3c03889bfda8d82b216c4c6410faf2006e3d1ba7ade1f8a5773f57be7c3889d905819937b3b99776e0b980b91841c9b1a3f100dc7369dbb5ab31b515155266325bfa0d72dca1d2f2397116230d2452b04424d8677fce4568b2aca0d381b807750d9853d700ebb2eb6ee72ac727a61726856e98b5ac66186a66ae9d10fe8e22c22cf2535b2debf2ed031c20f591367d37596733f4c86af0723c4cc47eb19ba05546b15b79775cae964d41415ad63a25b33bef2a82ce8c0fe7ed9e7d2082270a657241339382f54cf688e06dacb697a11d45c1407d15a9f1a3f7e3fa63a2535d8a96499a19775650b806548e0eedcad5c9416620d39a210fa374b0371139a68d0fa07b7ea6fc98d9a579fb5f9cf8332\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 495003, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 776611.81 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce035ad53ca2690eed1e71042c260c9e6ee809838442e212025aab171a1e201c10b8f1ed816c170862c88e71d8f1bbb6ea753a69763773f04aa828616f2dd406571a5105ffb7f0fd2645e30ab97bd8db9695307bc53fef51485e3703569531275349e644604a43d3dc36351733b7ab42841f7e31c17334884cab9c34c825f3e4f1eb5ca73ed4ae08cd4472b1de7923671aa4023c454c0477c0b6bb635e84ffa6a933f1b8bbd2247eb853b54615ff841f7df80eb76849f616aef146bd19016cb3248887cbf00ecfd99745dc8bbf3aaeb514286a2cab99df87029a71ff87e63358b9d0688b079fb4c720e5d1461b38f5b2cfb3c42be361bdce13d4ea5b336f9e8e58d8844c007786f9f4c3abb0fb42e9fc9\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5050002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7791074.54 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } +] +``` + +
+ +![Query Performance - ORE/range_gt_10](query_ore_range_gt_10_chart.png) + +## range_gt_100 + +**Description:** Range query (greater than) returning 100 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value > 5000 LIMIT 100.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 100 | 6.49ms | 42.04ms | +| 100,000 | 100 | 7.05ms | 45.03ms | +| 1,000,000 | 100 | 7.69ms | 45.22ms | +| 10,000,000 | 100 | 8.14ms | 45.46ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf77977b33152775a0849e0fb9e90d1b5724a136449d77f85f9623e8a6ee61f10e0d8f485ea13f3e7522cfed28560e0a59a0c03c4b547b09f9da863d6889b7453b1c0c0e5b54222a6259b22ed2b98f752603ce6628b08da4e993c6165b3d7fdaf8ae72965268d0e524c2f0603d44d47e9c0fb410e16e2b1a4ee3cdd465a2c541aad8cc6273d11c66daf989bbd1b1536b816041cb55ab273f1882f078247272f15ccd5e7a1293dcfc299aa809bb595a54eb89afe5f91948671bf96d684828b23d22f6ce70c119dadf107c6882a2c9c7fc478dc285f3c3268ceb2fea1f52e991aae7182e4422c8e41c3e1b07844a705c7687118ea35ab9c896c944fdf4298ad5825005f80ecbaaad437e4bd489ff0d1441e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7766.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.9 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3943e443c9ca6f4a982f878e9289d6a48ac5f9ef9aa8d64610a04e000b51a7a85953d8d28eb42c358a9bcb0b42258c2aa8df440203737f4ecbc1d7dcfd885d9a18e8a0c1f7e6faf95ed6107733228ec20d2f416ef1b95dc6a92d119ac82e0f83bb9e9a8adcac7b037e751ce2182b695ed8903ab442c10b38a96249e1b0775ccd94ae45b14329e72262fb9c5e28b917f68c32a7b22df72e08df89f928b2342ed47719918426305f4f80b36ec1313156ea576bbbc3c51666af80c1bec0a677dfdb264d13cd09c2b84b1eb7d3555811ba9e436f2c22429952e9f2e4e5258e62f70d3290cf6ecbd6e7ceb95dfe74ef647c9a8a09e9366682d1e0b9d532a305bfd5c1ece2f3d9ad55c2b32df39f76a540a267\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77911.0 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3a5e60fce4b20c5f84cdf50c14bb7a2d93695db169f646450ac3a5839e639cbd8b2fbaadd3d61d8aee86fb79d304fe3eff4cc04dda0fc39bdcded21ce5d97a3278149bf39f3933c1e689331931d97d079476e424b629c12ad329b6b41806200bbb52c37f553a6093a27a8a65eee6261473a9db28624a3847e95e9065dfcee285883f8d2711165d2cee42679e5c28b2be736f603179abcef7a841dff93d11a12f4f3e4aca7c87a8eed898416b23207dc4cd4c7b320f19517754dd16c3967a9c052d2503f8109595ac3c5ca3cf1c8591dcca454c3e3c415a57dcc9219781d4ac55ec1341c6496303e0af009865c1fa553745301a5c839de1d06216e0c31a6c193b692b545994e1d8bd1ed874bdd9f29b21\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 495003, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 776611.81 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf22472e31028b9267367f6ae1d7fda813082cc9cede20d048630743a6358ec81ec542cc9f6638716caebf2ce1f3762a70e5907b839e860e32106815dca3b98bb4969532c49f6ad74a4315ffe634396b78b23adbb4846f88d9a3cd0598023a858f9a7753d96f8339f75788a1d5b79f25feced5e50cffeb151ea84df8e7ecb1ce650d5f8df0c69ef1e48f9d6e3957861dcc67a7072167564a1813f95f16d860d59631db8e9ea7428bcf21fd4706f395b021f320f2ce0202437cd94de9512285cfa2ccb8080509ce91e0c4567e5894e9aef6af305ac3deb09565ed88596b21fd8f80021e5ee348af72b7c6e39195a8c5359a5a4b90d1dbd6d0275879c823624b255a7aae72714955c9987ab9437af111958\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5050002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7791074.54 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } +] +``` + +
+ +![Query Performance - ORE/range_gt_100](query_ore_range_gt_100_chart.png) + +## range_highly_selective_gt_10 + +**Description:** Highly selective range query (~0.011% selectivity) with LIMIT 10 + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10 +``` + +**Parameter:** `2147000000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value > 2_147_000_000 LIMIT 10. Threshold sits 483k values below `i32::MAX` (~0.011% selectivity). Engages the ORE btree at every tier (with current stats — see the note on `range_selective_gt_100`). Useful as the upper-bound demonstration of how cheap a selective range lookup becomes when the functional index engages.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `integer_encrypted_10000_ore_index` +- 100,000: `integer_encrypted_100000_ore_index` +- 1,000,000: `integer_encrypted_1000000_ore_index` +- 10,000,000: `integer_encrypted_10000000_ore_index` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 3 | 1.43ms | 29.65ms | +| 100,000 | 8 | 883.26μs | 27.69ms | +| 1,000,000 | 10 | 1.11ms | 28.47ms | +| 10,000,000 | 10 | ⚠️ 3.157s | ⚠️ 3.605s | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Index Scan using integer_encrypted_10000_ore_index on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3670b0657354ad4a7421ca41d370e370ff590a6b30fe2af4027fa71292f0e45ac799af17fb03cafe6be194889d475340b068b3fae2b2c12943b5c72e09c2e8299fc9549f3d90e06beb4b7e115ff92c5d982130fceb631a012c1322f858a5426a8765e9803d47a570d7d4b3bc9c311122d9c8dd1235314b4b423d38be0ca0203f990b9610edfe06e1f081c5a36c43316ef6394f9e76b4460031fcb6f0e20a2c90b0801c50a2663bf5f442d47d59266e3279dfaf34b249b4e60518b671af379d156f42f6311b475dbaae20f9db0a1db11a29231de62e70bf65889b9395cb4b00fc9056dfc254cea86d313be589ed5a46fe921ad46fb991ff6bc3b6784eef66189b75e6d0e00661387099c3b52495247cc159\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.54, + "Total Cost": 229.9 + } + ], + "Startup Cost": 0.54, + "Total Cost": 46.41 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Index Scan using integer_encrypted_100000_ore_index on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36be52a8e1a0ba9ecad24828bfb15d8aba9d468853d6224316b9899ee388a0e35b84e9617e64f848ff68574fec6d156cd2c5e65253ed45558cda5b28324f5da2edd5d7858baadc96ee0f670887a7e7ef91815b506074bb0bbb390d2c101f30cd2212650fb306e18af5014af77ac727d7fe921145425de18f46d170d9d09f69c7e94191a4d9f3fc0b90bcd30e25d306a1d4d38276b35483d076745c11eebf13cf73b71ab4204ff2e1e372c01f2b90e9c6f3ae24d60b67d8a63796665e005ce57e9a69e00d1c8de465d52942972eba441695c6a52fc4c8fa6fd89c06044ef8857624f8ccdb2329040d4e9a043a335c8bb7db8f94c790b501c3d67993f6f9ba9d1525574a92f099e499d1e2a5843a986f9124\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 2258.41 + } + ], + "Startup Cost": 0.67, + "Total Cost": 45.82 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_1000000_ore_index on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36826025d5cccf199ed561780d68e3f75a38dc99751d8f63a595ec23b8f2f37ff3da38d3ec2cc33796b230696cb12da7b98fd2727e7fba44500e9751626a532b4348105c6cf120473fbb73abc2457b147f06c825823fcf3151941e7f4864973da05e29cdb222744a3be998783538888e06673213bd43ebfecd3b17910ef45ffa0c022f5ccba16d575a8f60afc94c4c23a8ba9e4e7b7b104e25053b46a20208237cd7a61df5bb17c36f6e4fb06081d6397884f6a4c9fe0c2468973a1aeff11b9cef9f5b65b017ba46bb9b0cc4c30dbf4369ea81ba25a16dd54de7d478260a946dc800999ca00925622c07ba831d002454865013eb4d8e7a4616395e6e9f7d8b7671a7879332cbd5f470985cb90f3c264995\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 22557.45 + } + ], + "Startup Cost": 0.8, + "Total Cost": 45.91 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_10000000_ore_index on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36b9581b419d45178f30a9a1425f682756e3bdfbb522e3ae4b80e8ce1396a389b264d8022ba559ca8817d1bad7b3dd81c3fae9777aad6410b408d953019daf32eb05ddaa96c7c307d44f5f562258b020e845f7225c1f7a24d2bc579cea64ed2466d3443af5da3191984de5ef5d676a3be46ac355a6e12de53fa351bf664472b87e4f8a84afee754fb4de1d907d8c93dfe73cbc2cfbdbf0d7d0b71f106de7d77b5dfe34a4fc4fc1723d32268d84dfa3c2b3eeba29fbd74be16a38e18ba0d22a1efa91de07ff11fb8be9a6a341f7da6d641af43018f1987d5b2aceb44e68592d1fa032f56cb4dba6226a4cddcb76d6e47b214ec07204ac1fd370df4588df09fb18e9fe9bb541594b3c0e15632acdd041728e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 225527.79 + } + ], + "Startup Cost": 0.94, + "Total Cost": 46.04 + } + } +] +``` + +
+ +![Query Performance - ORE/range_highly_selective_gt_10](query_ore_range_highly_selective_gt_10_chart.png) + +## range_highly_selective_gt_count + +**Description:** Highly selective range count (~0.011% selectivity), no LIMIT + +**SQL Query:** +```sql +SELECT count(*) FROM {TABLE} WHERE value > $1 +``` + +**Parameter:** `2147000000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: `SELECT count(*) FROM tbl WHERE value > 2_147_000_000`. Tighter selectivity than `range_selective_gt_count`; near-floor cost for an indexed lookup.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `integer_encrypted_10000_ore_index` +- 100,000: `integer_encrypted_100000_ore_index` +- 1,000,000: `integer_encrypted_1000000_ore_index` +- 10,000,000: `integer_encrypted_10000000_ore_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 850.69μs | N/A | +| 100,000 | 1 | 1.02ms | N/A | +| 1,000,000 | 1 | 5.55ms | N/A | +| 10,000,000 | 1 | 19.96ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Aggregate + Bitmap Heap Scan on integer_encrypted_10000 + Bitmap Index Scan using integer_encrypted_10000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36ca01feb59b53a7fd3ec6c294403e0cae2f48e415c42c793a57bca9c9401973eb8ec69c36c2666090eec127850a13fa5739a8b2a4355604b79b3cfedb0230770970707cb62140e7e842ebfd292cfe957f0fa584e76cb7234fdaa826b1f97a98f10afbbc2cae030607a9450893cbd7b464ed9d61c8beeb67a0bc3e125d8911d9091e2b3525dd5ceae3cb99153363aebed8d9184296d198d25b68c82ba42bf1e193d97bbd2f3c58c359d48efd3aa1468f83b720cfba85742b14e70818e39a881303cf1e38f2a3b5c86b7380485e0fb0a79de67098e2c9aa8a7f3f587b86d4f87b2931f5a69d65ebd8d01fc3c65496cbc73d02888eb69744d8c06f28f1a6ffb93d854a252ba483dbf1d79cc7ba4a6829b3c4\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36ca01feb59b53a7fd3ec6c294403e0cae2f48e415c42c793a57bca9c9401973eb8ec69c36c2666090eec127850a13fa5739a8b2a4355604b79b3cfedb0230770970707cb62140e7e842ebfd292cfe957f0fa584e76cb7234fdaa826b1f97a98f10afbbc2cae030607a9450893cbd7b464ed9d61c8beeb67a0bc3e125d8911d9091e2b3525dd5ceae3cb99153363aebed8d9184296d198d25b68c82ba42bf1e193d97bbd2f3c58c359d48efd3aa1468f83b720cfba85742b14e70818e39a881303cf1e38f2a3b5c86b7380485e0fb0a79de67098e2c9aa8a7f3f587b86d4f87b2931f5a69d65ebd8d01fc3c65496cbc73d02888eb69744d8c06f28f1a6ffb93d854a252ba483dbf1d79cc7ba4a6829b3c4\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 214.36 + } + ], + "Startup Cost": 214.49, + "Strategy": "Plain", + "Total Cost": 214.5 + } + } +] +``` + +**100,000 rows** + +``` +Aggregate + Bitmap Heap Scan on integer_encrypted_100000 + Bitmap Index Scan using integer_encrypted_100000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e368f1931ce1aaed0f0d318ba891c284a36d19dfe4ce9734d5bcccf4b9651d28863dec1c887347ec8025f748b7c81f23a1cd808d61a996f0269c4c72909fbb60650e7f31320af6118e2b428052d5fd7960617cf51b7845f5c6c1ad5c3c67d6b69823cdb08715a368123f2b1b6f04f3611243e36663effedbb3ac9e55822e9d44ad66f5e3cc6b55cb9b997b68039e050f2bf5c6709dca85cd3055974c152606ccd04771d3f5ca11fadbeca51df522fcfe4ef64bccd12ba8e9f96e21764abbb339bd37f3f0b3f8fc767b023e99b8b6dedd952885a1867760b9bb357f786cde2983bdac807ddfbbe166dc6c95524526461e5b8058722912abae104e29277b6e185b05c16823094d0599047663f8259bd3fc6f2\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 160.42 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e368f1931ce1aaed0f0d318ba891c284a36d19dfe4ce9734d5bcccf4b9651d28863dec1c887347ec8025f748b7c81f23a1cd808d61a996f0269c4c72909fbb60650e7f31320af6118e2b428052d5fd7960617cf51b7845f5c6c1ad5c3c67d6b69823cdb08715a368123f2b1b6f04f3611243e36663effedbb3ac9e55822e9d44ad66f5e3cc6b55cb9b997b68039e050f2bf5c6709dca85cd3055974c152606ccd04771d3f5ca11fadbeca51df522fcfe4ef64bccd12ba8e9f96e21764abbb339bd37f3f0b3f8fc767b023e99b8b6dedd952885a1867760b9bb357f786cde2983bdac807ddfbbe166dc6c95524526461e5b8058722912abae104e29277b6e185b05c16823094d0599047663f8259bd3fc6f2\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 160.54, + "Total Cost": 2109.63 + } + ], + "Startup Cost": 2110.88, + "Strategy": "Plain", + "Total Cost": 2110.89 + } + } +] +``` + +**1,000,000 rows** + +``` +Aggregate + Gather + Aggregate + Bitmap Heap Scan on integer_encrypted_1000000 + Bitmap Index Scan using integer_encrypted_1000000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 2083, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36336ff616214277b1f9a6899ff2fb29346bf2f5c3a21d9eb5d5d6cf0dc00240357a33aafcd12627cbf3992b39f610d077f9226a19af9b25cc95151efdb252be4e2d587b5c259e89390549fb08c6c868134b46199626902ea1f21c2fb68c5ce1f9189f75add605ce84b08ba514b0c7db8b9226350fb7af98e052037f121a305d1a73b27f80d20be84baffc513e7a8234d3709825c65b66cd35462d28bc25f3bbb1fb5a1b51007fe9d1546883962b42a5606ad48d38b1c79c768eaf1b21bd8fd52ca8b9d933bcc3878aba92719f35aac23166144ff1c237a89bdb5e3de96c81be1128e7e839832e23cbf82abcbfafecd214a440a0092f03adf2c9f3e46e5712f3323d254efbb3de9f5cbb698fa9013d1ea6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1598.3 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36336ff616214277b1f9a6899ff2fb29346bf2f5c3a21d9eb5d5d6cf0dc00240357a33aafcd12627cbf3992b39f610d077f9226a19af9b25cc95151efdb252be4e2d587b5c259e89390549fb08c6c868134b46199626902ea1f21c2fb68c5ce1f9189f75add605ce84b08ba514b0c7db8b9226350fb7af98e052037f121a305d1a73b27f80d20be84baffc513e7a8234d3709825c65b66cd35462d28bc25f3bbb1fb5a1b51007fe9d1546883962b42a5606ad48d38b1c79c768eaf1b21bd8fd52ca8b9d933bcc3878aba92719f35aac23166144ff1c237a89bdb5e3de96c81be1128e7e839832e23cbf82abcbfafecd214a440a0092f03adf2c9f3e46e5712f3323d254efbb3de9f5cbb698fa9013d1ea6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 1599.55, + "Total Cost": 19587.07 + } + ], + "Startup Cost": 19592.28, + "Strategy": "Plain", + "Total Cost": 19592.29 + } + ], + "Single Copy": false, + "Startup Cost": 20592.28, + "Total Cost": 20592.49, + "Workers Planned": 2 + } + ], + "Startup Cost": 20592.49, + "Strategy": "Plain", + "Total Cost": 20592.5 + } + } +] +``` + +**10,000,000 rows** + +``` +Aggregate + Gather + Aggregate + Bitmap Heap Scan on integer_encrypted_10000000 + Bitmap Index Scan using integer_encrypted_10000000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 20833, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3636a48cacc6fa21cf8b6d7e9397f66d65db0bf1139c96af507702882ec0a2b2e6788ed111afd249f56cfd3ab4345e84ff9c24a3d868f851280738122f536435565d32364de6a0ce34331f73783093fe7d25b468c99da1ba0f27cdce6fe1cbd01142f5fa9c226ebefde9fdf008cc082e47e151a647218343e65430dc173e30dfd2e73d8194c5260d63c3576f2e31b1a7bb22ca6af9cbb6becdb745325c2dd4241fadc83b7a650ec9be1ec1c808b7a9ce3c7cee5eb0706c4bc89df7f7b3c3bb11352cca1986ab8b1bc3d9d02d2c30039258bf6c0a045f6933e4c532028601e760996e0e463b5cad6bf39064caebf7f8b6a2ae3946bdcb70fbebefb6d729ad9cb1406564f445922fb1653bf5c6183ea56fbd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 15963.93 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3636a48cacc6fa21cf8b6d7e9397f66d65db0bf1139c96af507702882ec0a2b2e6788ed111afd249f56cfd3ab4345e84ff9c24a3d868f851280738122f536435565d32364de6a0ce34331f73783093fe7d25b468c99da1ba0f27cdce6fe1cbd01142f5fa9c226ebefde9fdf008cc082e47e151a647218343e65430dc173e30dfd2e73d8194c5260d63c3576f2e31b1a7bb22ca6af9cbb6becdb745325c2dd4241fadc83b7a650ec9be1ec1c808b7a9ce3c7cee5eb0706c4bc89df7f7b3c3bb11352cca1986ab8b1bc3d9d02d2c30039258bf6c0a045f6933e4c532028601e760996e0e463b5cad6bf39064caebf7f8b6a2ae3946bdcb70fbebefb6d729ad9cb1406564f445922fb1653bf5c6183ea56fbd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 15976.43, + "Total Cost": 195823.06 + } + ], + "Startup Cost": 195875.15, + "Strategy": "Plain", + "Total Cost": 195875.16 + } + ], + "Single Copy": false, + "Startup Cost": 196875.15, + "Total Cost": 196875.36, + "Workers Planned": 2 + } + ], + "Startup Cost": 196875.36, + "Strategy": "Plain", + "Total Cost": 196875.37 + } + } +] +``` + +
+ +![Query Performance - ORE/range_highly_selective_gt_count](query_ore_range_highly_selective_gt_count_chart.png) + +## range_lt_10 + +**Description:** Range query (less than) returning 10 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value < 5000 LIMIT 10.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.64ms | 28.29ms | +| 100,000 | 10 | 1.51ms | 28.77ms | +| 1,000,000 | 10 | 1.61ms | 29.31ms | +| 10,000,000 | 10 | 1.72ms | 30.15ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bceda16bf25f19b2ba0c94d71aae8910336edbe8f825a9f1be66459c95f7d5ce637ffd968733af28c55772302718b1537642462eae63269ca3e1b1806a4285ea492b8b37638b391569cf41a9958e7c039252ea8645bcdb8b1104998e7eec88bb77ca2eca6e5c67125bff1dbb77ba8545eec1a301162fef42843b650e8f058ba0c1a91e9cb871057791d996b8de16fcb07d261a98f909f2be733592615197af1670d7d9d0691d9615721cd2a76f48db165128a311ba268e1cf2c26039f0b2c48bcaca64d340d0dbd03b7cbe0c44cdf32e9deb4fc11ceea9c799693678136e8a8934a696410c4dd99dc339af41270c2b5fa709e60ba4768d1440d612f7895df7724840a5c6f493f382091b10f8aadc17d266\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7791.25 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcaa6d7dda1508dcb025ba4530f8c3283179584ab0db22d5f36e29f6ecec3892e371e95c1cb17c18fd442b575b22772c54a8f37e09eecc2b7ebd17426304de2d8c3d51b8b751081eb9681847729ec9fe0f6126b2d97d6606391df657ebd98df675340fe7813d96d776ceeefdbeabd6b602ba4d42e0d56c08a164cb88a1c14d81d49e4a88c62d536e581ecbe33674dbe0e97a9d22a8b3349e133bc2c0641086d916143b94c13c91426c0bc9ff4c365f07bdcd95a441f89de86a5d67b6ac1c0c03e7d9d744a045ccc675536d3d1e929381be28eda544056e9c8106f7062e69e6442dba0aa8af37a4c53298a24e7b08c0ca08434d405bb77041336f27d8aec49fb16f101fec1a03dd72fc9f28a6e5084d02dd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77660.75 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1f10ea56d47b8492c75f1339860acd4db023a4fcd171ec5d4697c28095e685544b67b814c2ed713ac34de8068c7b4ed893a668246f7494028dd7591cb861b84561dbb641380a18cb04cbd414456b7a08c1e10a9813c6cc2c50ccde3fe28aadcd8ef4960cb6114ac2dd81a2e060240adc0ac941879b1280595677c4edef6403049b3f0f043a4b722bad4daa5617cd9311d1015b47e7a1a693ec0cb1e6253bcf60b8d379950b516793044422f1914c421979291af0da9bd487bdaa416bb66e365212f03dd67a8f0824d2399141ac9ac19d7e7d5098b8fe7274c3db4a7ce80579fb9eb78fc9c6701c2496d901bd624ff9e93e67fc0f3a2d1a282a29f662273606e22f2c7d79631cf462aa5ffafa19632d53\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 779111.56 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3f0e300ff67bc4d9fee3701c15fd2a1379f439472f348072a34d3f9e6dfc5ce064217764ce8b4d315ad49b082c9b558dd12a8de0b0c42022f1ebe75a86cf5cedd7f8a9a8446da81e80db2e3c8959ac852eee567cae6de44594030ced59d4ce678e56033858cb3ba2f7553aeebcd6fec71a72837339d1ce83b8ed6a66f88568d6769afa9ef42abbbd8f68dccfc307ad6a1ac90dd2c3f8b146db56bbfafdad3f08d921085fd9663a490327334c5021a249c5f9e3778f9b4ebdfbc85a24b4ae50921d7e553e55e07f7aa2afbdcf19bc9c7f2cfa52237826319241571e936806059603958a1b582ccfd35346335856af92aa6d8a1587b331b3359c39837c88063ba6a17ceefa37b187db9920dd4f8ba88ee5\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7766074.29 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } +] +``` + +
+ +![Query Performance - ORE/range_lt_10](query_ore_range_lt_10_chart.png) + +## range_lt_100 + +**Description:** Range query (less than) returning 100 results + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value < 5000 LIMIT 100.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 100,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 1,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ +- 10,000,000: _none — planner picked a sequential / hash-aggregate / sort plan_ + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 100 | 7.13ms | 46.12ms | +| 100,000 | 100 | 6.87ms | 46.49ms | +| 1,000,000 | 100 | 7.51ms | 45.65ms | +| 10,000,000 | 100 | 7.58ms | 45.56ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc981f0239ae333c99d66e5d01c963193aaa470df62b2cf1d8fadc9dacfefbf678db1d341af31e204af6bedb5687884f5926aecccff21542589f17ccd5d92f58039d7cb9bc26558dcbe00ad147970e8efd3c8dfe3c269ecd91a9eebd4169d2509d9c9593ce79991fa754adee5102cb0f6bd53e197d022d06f31e56e1a7c964b87fd1e2de5c0e3a5c7bc2bf8dde1b96b79bde395c2bae3528d2b8f03bbe012db7858b2fcdfd76140c593eefbfbcb6f096f7e267094ebcbfcf2b97e1d63355f7402900e78841ae4d014f529dc4ac6726ceefd7f53b331dac99225d26122bc018fb3ef32ef60e18632be85cce7c73801c2094c8eb1f0c966755c54c626568cf3c01bd6f9968d16011a17308379262242d3faf\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7791.25 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.31 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1c2266c60d3f36b6fec5b21c89ab896040fdcebe88c40452415319fbf1105cdc7fcb7a7b777f1357c695bf6c21c1002124c4e8195aade6ea2e0cc76a6aad644587ac052d449bdeb7eb2b6a4689bc34cea01fc52422cb7a2e816c8e27b87d26c1af5ee9d9a3dd1e66b3d65b59d4808307ff87f869f4e7e2b38c974414242243d321317ab87c8b111901468c4f8f94f377ca888e719e08a6dfa57b3b1be60a1e263b350f4eacde5727edabb2a2be584febfafe0d22ece42e758b818ba3afa824f43b905fa626164dfacacd011d54c8594feaf7ac4faf0c2f43944f8f6f739d27293e75a09c7aeaf4e5d326ae9e4f5c3d01009b14effabb4e6b28e60998e387b55f09d06171bd6d4187011f6abf4292b954\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77660.75 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6a8b6086d0750409358d7141ee7450549514d09b6b1a827332087189e81351a040fabc979b3346f720e5114878db511790c234464edff1c5e59cab46a193b96539dc941cdfcac58b29f905f12e479cb1d26cefc26b569cd911b604d60f80556b989eaa5bf3e3d1715072db7f740692572acb594cdef91fcb53780f0ef54d2938ca7505af0d24e96abaad261abc0279f155168079957d8173918856c0d830cf751668ca7f2c1135c748b7446dfdce13a150b6b1e64923f01ea372d4dab76b4b924995eae1e7ecd91fe36476585bf1ab4a0552bd4c39830be772c47f2ee89a7343f2daaa62ce49e6e70d774892737171676dbff0c58468e23b653a9f2ae33a51b79ec16f6ef653b1aeb454c618041a73b\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 779111.56 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Seq Scan on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc43a1ddec1ade1332d580d84e400ad9bf21691674d9edec0a1ca27d2c2d11e7c071cb97f10b33a98bc723350a42423ab0dd795c5a8347e3988a57f57599d058b161c97821aadcfaa8106ba32a7e21dbe4b46b57f4a2a1d79b56e96fd3d35520a235cda31312ecdcc17aec5b43aded4495b31006a25d72dca981c939e0351b3dfcfe98cf25896c488f13541336442e82cddbc625fb593b534672cac0b3a3dd30bd63be28eae0f3540007fc26fcbf7cb79633325cd94c3ce52b9260e85ec9368c777849d03910f89a6be4afbeb542104f507e5a4d4f9275d2922fa250c56b443739cccf1f5e74f71728219714d637e4773fdbebd76e6ec9a3d5fe303715a9d0f0a604840ba7f9df2af6aa1dc5cf16e406c6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7766074.29 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } +] +``` + +
+ +![Query Performance - ORE/range_lt_100](query_ore_range_lt_100_chart.png) + +## range_lt_hybrid_ordered_10 + +**Description:** Ordered range query (hybrid form: natural WHERE, extractor ORDER BY) + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10 +``` + +**Parameter:** `5000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value < 5000 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10. The sort key matches the index expression syntactically, so rows stream out of the index already ordered — no Sort node. See §4 of the EQL query-performance guide for the natural-form sort-key trap that this shape avoids.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `integer_encrypted_10000_ore_index` +- 100,000: `integer_encrypted_100000_ore_index` +- 1,000,000: `integer_encrypted_1000000_ore_index` +- 10,000,000: `integer_encrypted_10000000_ore_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 10 | 1.96ms | 30.28ms | +| 100,000 | 10 | 1.51ms | 29.06ms | +| 1,000,000 | 10 | 1.34ms | 28.90ms | +| 10,000,000 | 10 | 1.16ms | 29.07ms | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Index Scan using integer_encrypted_10000_ore_index on integer_encrypted_10000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc14347b7005145baed64bf5fd2b8c091f589680a0075cc7b0ffc370b8403d88e39ef58e2e11513beaeb537b61e17653181c5098ad15b1b4938d2295de2d7182221083e77a080cf8d5811fcbbbb8915865d1c1ca4f1ee713737a75b21e2874b003d9a5e9ec064049a77b210642d44390b830b7ed1001be4cdeed88ba168bc01d5714ddac2c8ba033bd00da6aa4eea70669b3ca6214f798d3abca3debbbdc0aac1bd8110a55015cd6dc522f8e1fe161cb6de2b1f60456d5041488cd50dc15f9ddec1076b2202a0291c2a34a28459ffc061ef95890d8829788296cb6a4c54c8ed3e6c886fce7a37ed38c84c42f83f79eb0581b6592858e80879d01d855bcb646e76612af9987ffdf73d0d65127b8409d5388\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 68, + "Relation Name": "integer_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.54, + "Total Cost": 9909.19 + } + ], + "Startup Cost": 0.54, + "Total Cost": 20.16 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Index Scan using integer_encrypted_100000_ore_index on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc45bfb34f421b183dbc0afce3324395f8bef03f4e86acd2d9873d90821dc67ee31528425717dd7ab738e15f40335adcdc3460689f78a87b3db6030b688cda7c956ced6821448aca5d76a79c74742ab7fc12523bdd5a82c94083a5faf23c56b77c0ab28ef07cb4fac38cd5059659a362986d4f172f43e3ed178b00925553d54b5a63f17f625b6e99cb9af47e1b2cded836d6f8d160fb9c4f329c684bd947b22f2cfec1fca5ee9a194ff77a41f351cfd33a4412fc82acd01de3347123f23dd773f6e4427dbea13f354adc736dc7f592d97d68349758f1c25e889fcce2a04c3d6c3bee1fc2ea724dde039c2f7b817e5ef7549a198ac130d560296230209d4c52ca200438f350a726ffb9231d9b70100fb30e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 68, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 98196.21 + } + ], + "Startup Cost": 0.67, + "Total Cost": 20.51 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_1000000_ore_index on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcc7454297a75c940d0951c142be9814e95ec61cd4924e18ceef6e5339422e134138e197fb11a9b5ffaf528ecfdd29106b069eb2006af8da90a4adbf1e870ef0dfdeb2c01cb92b7ea432a9c5f320ff1f7fbb94bb2ee96eaef5d9980765a818a423adec67987cb6bd8ea297fb9c70c8be9c8238514f049602b581d884494a25d1c51b0bf2c7cffd3ed35846e7b19b4a7f7ae42f1871e99ea271f9596c446135319b172fdd89d1c4c718d9443fedfcd83f6199e3eca994f50f771e1b86e0baeded94fee1e70065464c7c38b9395bafd86ae52a3a81641fe4cce0fc7a7d1573dfc0e6e264097915a6688509a5cf1693b73ce4c9baa47dba4f86437f05411bb2d99915740198d4c43c6c2e2921c75cd7ab1943\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 68, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 990161.03 + } + ], + "Startup Cost": 0.8, + "Total Cost": 20.41 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_10000000_ore_index on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc24f6a359f41fa3cb965233c1f31d65223e5fd83fa64ff6710ae83260a215b9d9b4d148c6297672bab63eb4affa1c28e64db59dd5af66b045c7d6be898b226b92ae831f7603e284bb1fefaa90bc751f632bb090d4438d5f600fb7289fd77b5485af1071fa0fc7f1bdcc45fbdffa5bb08e330bcf5987b536e9bba026c6f030ce6564f7107a72dbeaa665eceaacaa37f766d8bf8026a214aaaf8c79467ed8db91eb01414832c4742e38f909e8b234049d6e80c34d6533388ec2305aedc60868a03d63986a148a7952194a8ac88f122b8273a30ac4c14b1cb76adecce5a397aa7db67f507bd3d5b86e8e080e4c7cfb8bf96c59e31254b3fe5685f67c6414e79b01174f5146ddd77969c4a9f330134252ef67\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 68, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 19385383.19 + } + ], + "Startup Cost": 0.94, + "Total Cost": 40.1 + } + } +] +``` + +
+ +![Query Performance - ORE/range_lt_hybrid_ordered_10](query_ore_range_lt_hybrid_ordered_10_chart.png) + +## range_selective_gt_100 + +**Description:** Selective range query (~0.17% selectivity) with LIMIT 100 + +**SQL Query:** +```sql +SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100 +``` + +**Parameter:** `2140000000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: WHERE value > 2_140_000_000 LIMIT 100. The threshold sits 7.5M values below `i32::MAX`, so ~0.17% of rows match on `Faker.fake::()` uniform random data. Engages the ORE btree at every tier (10k → 10M) — walking the b-tree from the top and returning the first 100 matches is cheaper than scanning the table once the planner knows the predicate is selective. **Note on stats**: this requires up-to-date planner stats on the functional index expression (`ANALYZE
` after re-ingest). Without current stats the planner falls back to default `>` selectivity (~14%) and picks Seq Scan, which is silent but produces misleading timing. The bench's `prepare:_table` now ANALYZE's automatically.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `integer_encrypted_10000_ore_index` +- 100,000: `integer_encrypted_100000_ore_index` +- 1,000,000: `integer_encrypted_1000000_ore_index` +- 10,000,000: `integer_encrypted_10000000_ore_index` + +*⚠️ = Query time exceeds 100ms* + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 21 | 1.21ms | 32.00ms | +| 100,000 | 100 | 2.02ms | 41.51ms | +| 1,000,000 | 100 | 1.90ms | 38.62ms | +| 10,000,000 | 100 | ⚠️ 2.092s | ⚠️ 2.262s | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Limit + Bitmap Heap Scan on integer_encrypted_10000 + Bitmap Index Scan using integer_encrypted_10000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 50, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91dae460933df85e4969c1af944c2e28978bc4808c2e4f10131b732b607dac7eb48f29e66b0599ad7182328009dd2b61f89ba48fd10657e90a6c1f16fd41e97fbaf99a11818257f963c1bc6eecde30663acdc615d65a0653b21704d00ff0a3173de2d878f31fcfdc9c34c77ebc71b41f1e4f0dd617395e5797ae691fc2e5864765f567790a9db72d781467b7f6e1b83cef0fb5a34b54983d0a195334289bf80c6f03ea0c7a1011e4c0177758c82b54eb4b5cd429895f5f79bba741349e330d04b4c5fea589b5765cc5a8584e55c86728e0cc19ef5c808bec946522e12d6c97d690da317f5f493c51d0eb8ee79a859e2864d057a50c5cfc93cc0807e18b9aaa251e349afc80ff526bcbf63b9dc41ffc567\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91dae460933df85e4969c1af944c2e28978bc4808c2e4f10131b732b607dac7eb48f29e66b0599ad7182328009dd2b61f89ba48fd10657e90a6c1f16fd41e97fbaf99a11818257f963c1bc6eecde30663acdc615d65a0653b21704d00ff0a3173de2d878f31fcfdc9c34c77ebc71b41f1e4f0dd617395e5797ae691fc2e5864765f567790a9db72d781467b7f6e1b83cef0fb5a34b54983d0a195334289bf80c6f03ea0c7a1011e4c0177758c82b54eb4b5cd429895f5f79bba741349e330d04b4c5fea589b5765cc5a8584e55c86728e0cc19ef5c808bec946522e12d6c97d690da317f5f493c51d0eb8ee79a859e2864d057a50c5cfc93cc0807e18b9aaa251e349afc80ff526bcbf63b9dc41ffc567\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 226.86 + } + ], + "Startup Cost": 16.92, + "Total Cost": 226.86 + } + } +] +``` + +**100,000 rows** + +``` +Limit + Index Scan using integer_encrypted_100000_ore_index on integer_encrypted_100000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9358a15a5e641746b7c6b66e189423d4c88a64df34327a742e1ece8193d81f95d623e0dfd605ded1cdb56a0690278539530b9d2c2437dcc5bf6c7811fe180ca2b2290c0ed9dec1a8c7c9370dc255211b22c425a0a074c63b77b441a0b4eacdfbe703fa8abf7ca3d5a53d4f9c796d8129d90bc964f7a9f92f38560e4c5bd3a1e774bf50bcad83d1ad8346da0b6228f28030edf79ee04a6445ccef6208586fba71e916b61706536965a95cceab3c54a89478da21a3d6c88d86845a142501a1f80d9a18d33fbee14ec3b393ae83304e7d3b4f64ee3a20e45395ba1ca08b86bdc553e22b4583c26b8e66db16f0eeafaf24ef3295156365e60099fba4b0c2f4a946c9cfc7415acb93a1061ecc738114f45caa0\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 2258.41 + } + ], + "Startup Cost": 0.67, + "Total Cost": 452.22 + } + } +] +``` + +**1,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_1000000_ore_index on integer_encrypted_1000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cc6e472988d60f56a47cba7d9f30e0b64788545ad1dae1999c46fa0b156e1d563f48daebc786bb70ddd61e32974a69ff117a5e76328f922ba4b6a728aee7aee75e06f47c38560954532333812d8322f8c433d41947ca9c3d626dd95cdf01ab694e17346cd07c1c1869c471ab70218ed87648af057fb257188b8a25dc0b0f1974c3b3c7c20ecbf543001e7eb4c5e0ef7b997122321b55f36f294c760a1a172897c72096fe39bbc637ee039159d7f5a5383ae1f4d27c5aed077d2b3e70f7f4a598195da798e683799c8b902de06cd5639baaf9dfe6c3ee74434131ad9b6ff51b7e2c2c777714cfe9c8dbbba410f6696b1543feabece5b01e8c58ea66190e540b112a9b4837b01342bc11dd829309f33937\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 22557.45 + } + ], + "Startup Cost": 0.8, + "Total Cost": 451.93 + } + } +] +``` + +**10,000,000 rows** + +``` +Limit + Index Scan using integer_encrypted_10000000_ore_index on integer_encrypted_10000000 +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b94da6a5c9730d37d11cfa0560bc682cabfa753c419e4719a7b1568265a12319e2b810be016244a215aa315ce894faf33a304c17197f68ddc0c5203ca82fd55a34870e5f445a834781ec684e007b489678f925aa5ea2083eda4bace925157a22ee9c1f48d64c33d18907cba79f728961e13d1457e95644139c3df24d89ffeb31d195b06d4893ca4d8a90cbadeed07fdba653fb4c62ee72e9e2c00336ba41dfc6160151c5370f7344881919a877daa7d473d628ed92b04e39da3e29347b705829051cc6cefdc8151e26582eaaa618fee547cf762daa98399af7347ed463730a56f6801c3495c5e0f880f51bf6820df041c0e16f67d4e85b0582a3f4d52fe493c66ab0f6378b831e6fe5edadb596c59260eb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 225527.79 + } + ], + "Startup Cost": 0.94, + "Total Cost": 451.99 + } + } +] +``` + +
+ +![Query Performance - ORE/range_selective_gt_100](query_ore_range_selective_gt_100_chart.png) + +## range_selective_gt_count + +**Description:** Selective range count (~0.17% selectivity), no LIMIT + +**SQL Query:** +```sql +SELECT count(*) FROM {TABLE} WHERE value > $1 +``` + +**Parameter:** `2140000000` + +**Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. Query: `SELECT count(*) FROM tbl WHERE value > 2_140_000_000`. With no LIMIT the planner must process every matching row, which at low selectivity strongly favours Index Scan over Seq Scan. The companion to `range_selective_gt_100` — removes any LIMIT-related cost-model edge cases and demonstrates the index path in pure form.** + +**Indexes available on the table:** +```sql +CREATE INDEX +integer_encrypted_10000_ore_index +ON integer_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(value) +); +``` + +**Indexes used by the planner (per data set size):** + +- 10,000: `integer_encrypted_10000_ore_index` +- 100,000: `integer_encrypted_100000_ore_index` +- 1,000,000: `integer_encrypted_1000000_ore_index` +- 10,000,000: `integer_encrypted_10000000_ore_index` + +| Data Set Size | Rows Returned | Query Time (no decrypt) | Query Time (with decrypt) | +|---------------|---------------|-------------------------|---------------------------| +| 10,000 | 1 | 958.35μs | N/A | +| 100,000 | 1 | 1.46ms | N/A | +| 1,000,000 | 1 | 7.79ms | N/A | +| 10,000,000 | 1 | 77.18ms | N/A | + +_Rows Returned is the actual count from a one-shot pre-bench execution. For LIMIT-bounded queries it matches the LIMIT (or is lower when the table doesn't have enough matching rows); for aggregates wrapped in `count(*)` it's 1._ + +
+EXPLAIN plans (per data set size) + +**10,000 rows** + +``` +Aggregate + Bitmap Heap Scan on integer_encrypted_10000 + Bitmap Index Scan using integer_encrypted_10000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91a80367663852bdfcbc395253c06c9c19d4bb4234c922426de81be8473af8ab59a928fbff4b7f6f70d275c6b00206fb739b00718ed29aeebbbad1fa73bd2ed0789d978867c805e75a42d2517e204e9a807d88bd71a40c8c975cf9bafef627ffefdd245ebb16b7959f956a5916e058dc6f757866458c67afb9f17f60aa1fa4366d91f9ed39cc0d642c80329c3d762ed4a70d7818ac373604b2a15f1efcdb7af4605006becd7e953169cf2c0a1ef5c970875ce3c033f1d15e9ae7c04ef0e0674774397cddbaedbb588d1ad491ea5e1d74bb13f55290e2e9ea95cce66ee2f7e36963557a39358de046dd56a7d263254b0abde73b81fcab424245c1a5aaaf4c6d29ea997cecf2ccc24eeb8fa1181ee17c050\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91a80367663852bdfcbc395253c06c9c19d4bb4234c922426de81be8473af8ab59a928fbff4b7f6f70d275c6b00206fb739b00718ed29aeebbbad1fa73bd2ed0789d978867c805e75a42d2517e204e9a807d88bd71a40c8c975cf9bafef627ffefdd245ebb16b7959f956a5916e058dc6f757866458c67afb9f17f60aa1fa4366d91f9ed39cc0d642c80329c3d762ed4a70d7818ac373604b2a15f1efcdb7af4605006becd7e953169cf2c0a1ef5c970875ce3c033f1d15e9ae7c04ef0e0674774397cddbaedbb588d1ad491ea5e1d74bb13f55290e2e9ea95cce66ee2f7e36963557a39358de046dd56a7d263254b0abde73b81fcab424245c1a5aaaf4c6d29ea997cecf2ccc24eeb8fa1181ee17c050\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 214.36 + } + ], + "Startup Cost": 214.49, + "Strategy": "Plain", + "Total Cost": 214.5 + } + } +] +``` + +**100,000 rows** + +``` +Aggregate + Bitmap Heap Scan on integer_encrypted_100000 + Bitmap Index Scan using integer_encrypted_100000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cb2fa1de61f20783cf700958dbdc86fe842e6501d43305c38a1e009b32d508c312c90ef12f3ac4761c63cc40f96b16726ab527a83508f025835c1c571285a81aa11ef90d28d65f2f60ca84e39f1b8e8e1fddaec53a536e4c7c4bb61fb061fae99c9c2dcfd81f5e407f2298f9f1042a707e3e4a338928c3797845b44f4a2815cd68515c4c80b6c391ae477bbc321223c9509010c237d2322552bfbbfd7fd507b1015feb169590fa5c6622cd5041cfd866e4fd7765f25198786a4aabcecfeca4ce9f898c47d786639785f602dcc06e5a78547b07f498e8f3d2da57cb9c07aa7aaaec29f1f5fc237fb80c3742d2723e91ca1c6a4d99ccf4207a412828212f02e1872ba17e28d316c8338cd43190be359dfb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 160.42 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cb2fa1de61f20783cf700958dbdc86fe842e6501d43305c38a1e009b32d508c312c90ef12f3ac4761c63cc40f96b16726ab527a83508f025835c1c571285a81aa11ef90d28d65f2f60ca84e39f1b8e8e1fddaec53a536e4c7c4bb61fb061fae99c9c2dcfd81f5e407f2298f9f1042a707e3e4a338928c3797845b44f4a2815cd68515c4c80b6c391ae477bbc321223c9509010c237d2322552bfbbfd7fd507b1015feb169590fa5c6622cd5041cfd866e4fd7765f25198786a4aabcecfeca4ce9f898c47d786639785f602dcc06e5a78547b07f498e8f3d2da57cb9c07aa7aaaec29f1f5fc237fb80c3742d2723e91ca1c6a4d99ccf4207a412828212f02e1872ba17e28d316c8338cd43190be359dfb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 160.54, + "Total Cost": 2109.63 + } + ], + "Startup Cost": 2110.88, + "Strategy": "Plain", + "Total Cost": 2110.89 + } + } +] +``` + +**1,000,000 rows** + +``` +Aggregate + Gather + Aggregate + Bitmap Heap Scan on integer_encrypted_1000000 + Bitmap Index Scan using integer_encrypted_1000000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 2083, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9303e5e42d7aa93e853d4cd2cfd026e2b789aec720254a8e67101993039721b076eb3afb9eb0dfe84b93129133a06d9f8bb6ac7aad0eec110cb7d286dcc591ed6c2430fdb333bcb29dd1c18d029fea02819000a1713c8e1abddd3fb338620b1808d5636b4027888fc67079bfddca56c591a7f8a1cf70a8d0281b6dd446584d5deadd261e420c30908be061542fdde4bbb6f669b6915e473cf9c8955806c044f274e14d4277c6a331b2cc0c01b411263e9b07047af7fa93efd92ed73cba8c9499bc6869ccac4c63ff6aae4fad5545917c50c275cc17c21b7edd5511e505618f6651cc1b3d9eecb932838a4533635e8651f89a2947701a3b39ceb6f134a679a293b6f25034382cbd274fb90b1a488c53693\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1598.3 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9303e5e42d7aa93e853d4cd2cfd026e2b789aec720254a8e67101993039721b076eb3afb9eb0dfe84b93129133a06d9f8bb6ac7aad0eec110cb7d286dcc591ed6c2430fdb333bcb29dd1c18d029fea02819000a1713c8e1abddd3fb338620b1808d5636b4027888fc67079bfddca56c591a7f8a1cf70a8d0281b6dd446584d5deadd261e420c30908be061542fdde4bbb6f669b6915e473cf9c8955806c044f274e14d4277c6a331b2cc0c01b411263e9b07047af7fa93efd92ed73cba8c9499bc6869ccac4c63ff6aae4fad5545917c50c275cc17c21b7edd5511e505618f6651cc1b3d9eecb932838a4533635e8651f89a2947701a3b39ceb6f134a679a293b6f25034382cbd274fb90b1a488c53693\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 1599.55, + "Total Cost": 19587.07 + } + ], + "Startup Cost": 19592.28, + "Strategy": "Plain", + "Total Cost": 19592.29 + } + ], + "Single Copy": false, + "Startup Cost": 20592.28, + "Total Cost": 20592.49, + "Workers Planned": 2 + } + ], + "Startup Cost": 20592.49, + "Strategy": "Plain", + "Total Cost": 20592.5 + } + } +] +``` + +**10,000,000 rows** + +``` +Aggregate + Gather + Aggregate + Bitmap Heap Scan on integer_encrypted_10000000 + Bitmap Index Scan using integer_encrypted_10000000_ore_index +``` + +Full `EXPLAIN (FORMAT JSON)`: + +```json +[ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 20833, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9c22306bb84f2ee781c0cb8f7d53003060948ab2ed3082927e8862e763fa2342a844ff626ab7fe272b282a43d4e0c68d8c0d6a3874b55845ede4a7703ac1cba89ef0a4218b287cc7c21458d042a0664196c4eb69769dbaa42e692a0a14a23523453cc5186247a554401d396c8659a21420c6d22ea18e03dc07820a4dcf1c15045cefd19f78505615b38ea28d297f05fdda6da1ea2af15e5e09a5adb5f364a00ef6f72370675bb96f4c0ac07a8f7e56a5319f20543b1978620990d71c1089600ce66d6121202d28663652ad230098e1da5856d5874f2438c3a87f3c5cac4d906885bc95325fca5794b131cb8590ff5081e67ec424fb85f94a5c243d8589487a0aa86f4fc09859e72eeed9ad139336d9112\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 15963.93 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9c22306bb84f2ee781c0cb8f7d53003060948ab2ed3082927e8862e763fa2342a844ff626ab7fe272b282a43d4e0c68d8c0d6a3874b55845ede4a7703ac1cba89ef0a4218b287cc7c21458d042a0664196c4eb69769dbaa42e692a0a14a23523453cc5186247a554401d396c8659a21420c6d22ea18e03dc07820a4dcf1c15045cefd19f78505615b38ea28d297f05fdda6da1ea2af15e5e09a5adb5f364a00ef6f72370675bb96f4c0ac07a8f7e56a5319f20543b1978620990d71c1089600ce66d6121202d28663652ad230098e1da5856d5874f2438c3a87f3c5cac4d906885bc95325fca5794b131cb8590ff5081e67ec424fb85f94a5c243d8589487a0aa86f4fc09859e72eeed9ad139336d9112\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 15976.43, + "Total Cost": 195823.06 + } + ], + "Startup Cost": 195875.15, + "Strategy": "Plain", + "Total Cost": 195875.16 + } + ], + "Single Copy": false, + "Startup Cost": 196875.15, + "Total Cost": 196875.36, + "Workers Planned": 2 + } + ], + "Startup Cost": 196875.36, + "Strategy": "Plain", + "Total Cost": 196875.37 + } + } +] +``` + +
+ +![Query Performance - ORE/range_selective_gt_count](query_ore_range_selective_gt_count_chart.png) + diff --git a/report/query_combo_bloom_ore_order_limit_chart.png b/report/query_combo_bloom_ore_order_limit_chart.png new file mode 100644 index 0000000..6aa8fd7 Binary files /dev/null and b/report/query_combo_bloom_ore_order_limit_chart.png differ diff --git a/report/query_combo_filtered_group_by_chart.png b/report/query_combo_filtered_group_by_chart.png new file mode 100644 index 0000000..bc63f26 Binary files /dev/null and b/report/query_combo_filtered_group_by_chart.png differ diff --git a/report/query_combo_top_n_filtered_group_by_chart.png b/report/query_combo_top_n_filtered_group_by_chart.png new file mode 100644 index 0000000..cc6a0f6 Binary files /dev/null and b/report/query_combo_top_n_filtered_group_by_chart.png differ diff --git a/report/query_exact_eql_cast_chart.png b/report/query_exact_eql_cast_chart.png index 5d82364..ba4333f 100644 Binary files a/report/query_exact_eql_cast_chart.png and b/report/query_exact_eql_cast_chart.png differ diff --git a/report/query_exact_eql_hash_chart.png b/report/query_exact_eql_hash_chart.png index b957900..656e7cd 100644 Binary files a/report/query_exact_eql_hash_chart.png and b/report/query_exact_eql_hash_chart.png differ diff --git a/report/query_group_by_low_cardinality_groups_encrypted_chart.png b/report/query_group_by_low_cardinality_groups_encrypted_chart.png new file mode 100644 index 0000000..3dd45cb Binary files /dev/null and b/report/query_group_by_low_cardinality_groups_encrypted_chart.png differ diff --git a/report/query_group_by_low_cardinality_groups_plaintext_chart.png b/report/query_group_by_low_cardinality_groups_plaintext_chart.png new file mode 100644 index 0000000..ead7e82 Binary files /dev/null and b/report/query_group_by_low_cardinality_groups_plaintext_chart.png differ diff --git a/report/query_group_by_top_n_groups_encrypted_chart.png b/report/query_group_by_top_n_groups_encrypted_chart.png new file mode 100644 index 0000000..e269159 Binary files /dev/null and b/report/query_group_by_top_n_groups_encrypted_chart.png differ diff --git a/report/query_group_by_top_n_groups_plaintext_chart.png b/report/query_group_by_top_n_groups_plaintext_chart.png new file mode 100644 index 0000000..89bba82 Binary files /dev/null and b/report/query_group_by_top_n_groups_plaintext_chart.png differ diff --git a/report/query_match_eql_bloom_chart.png b/report/query_match_eql_bloom_chart.png index 5883abf..6406647 100644 Binary files a/report/query_match_eql_bloom_chart.png and b/report/query_match_eql_bloom_chart.png differ diff --git a/report/query_match_eql_cast_firstname_chart.png b/report/query_match_eql_cast_firstname_chart.png index ff36eed..e16220f 100644 Binary files a/report/query_match_eql_cast_firstname_chart.png and b/report/query_match_eql_cast_firstname_chart.png differ diff --git a/report/query_match_eql_cast_lastname_chart.png b/report/query_match_eql_cast_lastname_chart.png index d66ed14..c9caeb1 100644 Binary files a/report/query_match_eql_cast_lastname_chart.png and b/report/query_match_eql_cast_lastname_chart.png differ diff --git a/report/query_ore_exact_chart.png b/report/query_ore_exact_chart.png deleted file mode 100644 index 343cd2f..0000000 Binary files a/report/query_ore_exact_chart.png and /dev/null differ diff --git a/report/query_ore_range_gt_100_chart.png b/report/query_ore_range_gt_100_chart.png index 2603098..b67d131 100644 Binary files a/report/query_ore_range_gt_100_chart.png and b/report/query_ore_range_gt_100_chart.png differ diff --git a/report/query_ore_range_gt_10_chart.png b/report/query_ore_range_gt_10_chart.png index 63c8a2d..959c805 100644 Binary files a/report/query_ore_range_gt_10_chart.png and b/report/query_ore_range_gt_10_chart.png differ diff --git a/report/query_ore_range_highly_selective_gt_10_chart.png b/report/query_ore_range_highly_selective_gt_10_chart.png new file mode 100644 index 0000000..80b6bdd Binary files /dev/null and b/report/query_ore_range_highly_selective_gt_10_chart.png differ diff --git a/report/query_ore_range_highly_selective_gt_count_chart.png b/report/query_ore_range_highly_selective_gt_count_chart.png new file mode 100644 index 0000000..f42dd5d Binary files /dev/null and b/report/query_ore_range_highly_selective_gt_count_chart.png differ diff --git a/report/query_ore_range_lt_100_chart.png b/report/query_ore_range_lt_100_chart.png index 76f36b4..b957a4d 100644 Binary files a/report/query_ore_range_lt_100_chart.png and b/report/query_ore_range_lt_100_chart.png differ diff --git a/report/query_ore_range_lt_10_chart.png b/report/query_ore_range_lt_10_chart.png index a5e5de7..28a8ea9 100644 Binary files a/report/query_ore_range_lt_10_chart.png and b/report/query_ore_range_lt_10_chart.png differ diff --git a/report/query_ore_range_lt_hybrid_ordered_10_chart.png b/report/query_ore_range_lt_hybrid_ordered_10_chart.png new file mode 100644 index 0000000..dd02ea4 Binary files /dev/null and b/report/query_ore_range_lt_hybrid_ordered_10_chart.png differ diff --git a/report/query_ore_range_lt_ordered_10_chart.png b/report/query_ore_range_lt_ordered_10_chart.png deleted file mode 100644 index 8d1de44..0000000 Binary files a/report/query_ore_range_lt_ordered_10_chart.png and /dev/null differ diff --git a/report/query_ore_range_selective_gt_100_chart.png b/report/query_ore_range_selective_gt_100_chart.png new file mode 100644 index 0000000..5bfa8d6 Binary files /dev/null and b/report/query_ore_range_selective_gt_100_chart.png differ diff --git a/report/query_ore_range_selective_gt_count_chart.png b/report/query_ore_range_selective_gt_count_chart.png new file mode 100644 index 0000000..18584c8 Binary files /dev/null and b/report/query_ore_range_selective_gt_count_chart.png differ diff --git a/report_benchmarks.py b/report_benchmarks.py index 35c7700..958759a 100755 --- a/report_benchmarks.py +++ b/report_benchmarks.py @@ -47,6 +47,28 @@ class QueryResult: median_ns: float +@dataclass +class ScenarioMetadata: + """Per-scenario metadata captured at bench startup (lib.rs sidecar). + + The bench writes one of these per (scenario, row_count) tier into + `results/query/_metadata_.json` alongside the criterion + timing data. We use it to enrich the report with the actual SQL ran, + which indexes the planner picked, and what the plan looked like. + """ + query_type: str # e.g. "EXACT" + query_name: str # e.g. "eql_cast" + row_count: int + query: str # SQL with $N placeholders intact + parameters: list # bound values as JSON (encrypted payload for EQL scenarios) + explain: list # PG's EXPLAIN (FORMAT JSON) output (top-level array) + indexes_used: List[str] + # Actual row count from a one-shot pre-bench execution. None when the + # sidecar predates the actual-rows capture and we're falling back to + # the planner estimate from `explain[0]["Plan"]["Plan Rows"]`. + rows_returned: Optional[int] = None + + class BenchmarkReporter: def __init__(self, results_dir: Path, output_file: Path, sql_dir: Optional[Path] = None): self.results_dir = results_dir @@ -54,13 +76,16 @@ def __init__(self, results_dir: Path, output_file: Path, sql_dir: Optional[Path] self.sql_dir = sql_dir or Path("sql") self.ingest_results: List[IngestResult] = [] self.query_results: List[QueryResult] = [] + # Keyed by (query_type, query_name, row_count) so a scenario can + # look up its own per-tier metadata in O(1). + self.metadata: Dict[Tuple[str, str, int], ScenarioMetadata] = {} self.index_cache: Dict[str, str] = {} # Cache for index SQL def load_ingest_results(self): """Load ingest benchmark results""" ingest_dir = self.results_dir / "ingest" - for bench_type in ["int", "json_small", "string"]: + for bench_type in ["int", "json_small", "json_large", "string", "ste_vec_small", "ste_vec_large"]: file_path = ingest_dir / f"encrypt_{bench_type}_combined.json" if not file_path.exists(): @@ -132,6 +157,39 @@ def load_query_results(self): median_ns=median_ns )) + def load_query_metadata(self): + """Load `*_metadata_*.json` sidecars written by each bench at startup.""" + query_dir = self.results_dir / "query" + meta_pattern = re.compile(r'^(.+)_metadata_(\d+)$') + for json_file in query_dir.glob("*_metadata_*.json"): + m = meta_pattern.match(json_file.stem) + if not m: + continue + # The prefix in the filename (e.g. "exact", "group_by") drives the + # criterion bench name, not the query_type — we get the real + # query_type from the bench id inside each scenario record. + row_count = int(m.group(2)) + with open(json_file) as f: + doc = json.load(f) + for s in doc.get("scenarios", []): + bench_id = s.get("id", "") + parts = bench_id.split("/") + if len(parts) < 3: + continue + query_type = parts[0] # "EXACT", "ORE", "GROUP_BY", ... + scenario_name = parts[2] # "eql_cast", "range_gt_10", ... + key = (query_type, scenario_name, row_count) + self.metadata[key] = ScenarioMetadata( + query_type=query_type, + query_name=scenario_name, + row_count=row_count, + query=s.get("query", ""), + parameters=s.get("parameters", []), + explain=s.get("explain", []), + indexes_used=s.get("indexes_used", []), + rows_returned=s.get("rows_returned"), + ) + def format_time(self, ns: float, include_indicator: bool = True) -> str: """Format nanoseconds into human-readable time with performance indicator @@ -196,10 +254,6 @@ def get_query_sql_and_param(self, query_type: str, query_name: str) -> Tuple[str ) }, "ORE": { - "exact": ( - "SELECT value FROM {TABLE} WHERE value = $1 LIMIT 1", - "5000" - ), "range_gt_10": ( "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", "5000" @@ -216,13 +270,91 @@ def get_query_sql_and_param(self, query_type: str, query_name: str) -> Tuple[str "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 LIMIT 100", "5000" ), - "range_lt_ordered_10": ( - "SELECT id,value::jsonb FROM {TABLE} WHERE value < $1 ORDER BY value LIMIT 10", + "range_selective_gt_100": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 100", + "2140000000" + ), + "range_highly_selective_gt_10": ( + "SELECT id,value::jsonb FROM {TABLE} WHERE value > $1 LIMIT 10", + "2147000000" + ), + "range_selective_gt_count": ( + "SELECT count(*) FROM {TABLE} WHERE value > $1", + "2140000000" + ), + "range_highly_selective_gt_count": ( + "SELECT count(*) FROM {TABLE} WHERE value > $1", + "2147000000" + ), + "range_lt_hybrid_ordered_10": ( + "SELECT id,value::jsonb FROM {TABLE} " + "WHERE value < $1 " + "ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", "5000" ) + }, + "GROUP_BY": { + "low_cardinality_groups_encrypted": ( + "SELECT count(*) FROM " + "(SELECT 1 FROM {TABLE} GROUP BY eql_v2.hmac_256(value)) g", + "" + ), + "low_cardinality_groups_plaintext": ( + "SELECT count(*) FROM " + "(SELECT 1 FROM {TABLE} GROUP BY value) g", + "" + ), + "top_n_groups_encrypted": ( + "SELECT eql_v2.hmac_256(value), count(*) FROM {TABLE} " + "GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "" + ), + "top_n_groups_plaintext": ( + "SELECT value, count(*) FROM {TABLE} " + "GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "" + ) + }, + "COMBO": { + "bloom_ore_order_limit": ( + "SELECT id FROM {TABLE} " + "WHERE name LIKE $1 " + "ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "Bob" + ), + "filtered_group_by": ( + "SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} " + "WHERE name LIKE $1 " + "GROUP BY 1", + "Bob" + ), + "top_n_filtered_group_by": ( + "SELECT eql_v2.hmac_256(category), count(*) FROM {TABLE} " + "WHERE name LIKE $1 " + "GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "Bob" + ) + }, + "JSON": { + "field_eq": ( + "SELECT id FROM {TABLE} " + "WHERE eql_v2.hmac_256_terms(value) @> $1::jsonb " + "LIMIT 10", + "[{\"s\":\"\",\"hm\":\"\"}]" + ), + "field_extract": ( + "SELECT eql_v2.jsonb_path_query(value, '') " + "FROM {TABLE} LIMIT 1000", + "" + ), + "field_group_by": ( + "SELECT eql_v2.hmac_256(value, ''), count(*) " + "FROM {TABLE} GROUP BY 1", + "" + ) } } - + return sql_map.get(query_type, {}).get(query_name, ("", "")) def get_query_description(self, query_type: str, query_name: str) -> Tuple[str, str]: @@ -261,47 +393,245 @@ def get_query_description(self, query_type: str, query_name: str) -> Tuple[str, ) }, "ORE": { - "exact": ( - "Exact match query on encrypted integer", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " - "Query returns LIMIT 1 result." - ), "range_gt_10": ( "Range query (greater than) returning 10 results", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "The bare-form `<` / `>` operators inline to " + "`eql_v2.ore_block_u64_8_256(a) op eql_v2.ore_block_u64_8_256(b)` " + "post-2.3, so the index engages without query rewriting. " "Query: WHERE value > 5000 LIMIT 10." ), "range_gt_100": ( "Range query (greater than) returning 100 results", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " "Query: WHERE value > 5000 LIMIT 100." ), "range_lt_10": ( "Range query (less than) returning 10 results", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " "Query: WHERE value < 5000 LIMIT 10." ), "range_lt_100": ( "Range query (less than) returning 100 results", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " "Query: WHERE value < 5000 LIMIT 100." ), - "range_lt_ordered_10": ( - "Ordered range query (less than) with ORDER BY", - "Table: `integer_encrypted_{rows}` with ORE-encrypted integer values. " - "Index: ORE index supporting equality and range queries. " - "Query: WHERE value < 5000 ORDER BY value LIMIT 10." + "range_selective_gt_100": ( + "Selective range query (~0.17% selectivity) with LIMIT 100", + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "Query: WHERE value > 2_140_000_000 LIMIT 100. The threshold sits 7.5M " + "values below `i32::MAX`, so ~0.17% of rows match on `Faker.fake::()` " + "uniform random data. Engages the ORE btree at every tier (10k → 10M) — " + "walking the b-tree from the top and returning the first 100 matches is " + "cheaper than scanning the table once the planner knows the predicate is " + "selective. **Note on stats**: this requires up-to-date planner stats on " + "the functional index expression (`ANALYZE
` after re-ingest). " + "Without current stats the planner falls back to default `>` selectivity " + "(~14%) and picks Seq Scan, which is silent but produces misleading " + "timing. The bench's `prepare:_table` now ANALYZE's automatically." + ), + "range_highly_selective_gt_10": ( + "Highly selective range query (~0.011% selectivity) with LIMIT 10", + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "Query: WHERE value > 2_147_000_000 LIMIT 10. Threshold sits 483k values " + "below `i32::MAX` (~0.011% selectivity). Engages the ORE btree at every " + "tier (with current stats — see the note on `range_selective_gt_100`). " + "Useful as the upper-bound demonstration of how cheap a selective range " + "lookup becomes when the functional index engages." + ), + "range_selective_gt_count": ( + "Selective range count (~0.17% selectivity), no LIMIT", + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "Query: `SELECT count(*) FROM tbl WHERE value > 2_140_000_000`. With no " + "LIMIT the planner must process every matching row, which at low " + "selectivity strongly favours Index Scan over Seq Scan. The companion " + "to `range_selective_gt_100` — removes any LIMIT-related cost-model " + "edge cases and demonstrates the index path in pure form." + ), + "range_highly_selective_gt_count": ( + "Highly selective range count (~0.011% selectivity), no LIMIT", + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "Query: `SELECT count(*) FROM tbl WHERE value > 2_147_000_000`. Tighter " + "selectivity than `range_selective_gt_count`; near-floor cost for an " + "indexed lookup." + ), + "range_lt_hybrid_ordered_10": ( + "Ordered range query (hybrid form: natural WHERE, extractor ORDER BY)", + "Table: `integer_encrypted_{rows}` with Block-ORE-encrypted integer values. " + "Index: functional btree on `eql_v2.ore_block_u64_8_256(value)`. " + "Query: WHERE value < 5000 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10. " + "The sort key matches the index expression syntactically, so rows stream " + "out of the index already ordered — no Sort node. See §4 of the EQL " + "query-performance guide for the natural-form sort-key trap that this " + "shape avoids." + ) + }, + "GROUP_BY": { + "low_cardinality_groups_encrypted": ( + "Low-cardinality GROUP BY (~250 buckets) on `eql_v2.hmac_256(value)`, " + "wrapped in `count(*)` to isolate aggregation cost from emit cost", + "Table: `category_encrypted_{rows}` with encrypted categorical values " + "(`CAT_001`..`CAT_250`, uniform random — ~250 distinct buckets). The " + "encrypted value carries an `hm` HMAC term via the `unique` search " + "index. **Index: hash index on `eql_v2.hmac_256(value)`, but `GROUP BY` " + "doesn't engage it directly** — the planner picks `HashAggregate`, " + "building an in-memory hash table keyed on the 32-byte HMAC. With " + "only 250 distinct keys the hash table fits comfortably in default " + "`work_mem`. The outer `count(*)` keeps the result-set emission at " + "exactly one row, so wall-clock time tracks aggregation cost. The " + "companion `low_cardinality_groups_plaintext` scenario runs the same " + "query shape against an unindexed TEXT column for a baseline." + ), + "low_cardinality_groups_plaintext": ( + "Plaintext baseline: low-cardinality GROUP BY on a plain TEXT column, " + "same query shape as the encrypted scenario", + "Table: `category_plaintext_{rows}` with the same `CAT_001`..`CAT_250` " + "distribution (uniform random, populated by SQL via " + "`mise run prepare:category_plaintext` — no encryption-client " + "dependency). Index: none. The wall-clock delta between this and " + "`low_cardinality_groups_encrypted` is the EQL recipe's overhead " + "relative to a bare-PG aggregate at the same row count and cardinality." + ), + "top_n_groups_encrypted": ( + "Dashboard analytic: top 10 categories by frequency, EQL recipe form", + "Table: `category_encrypted_{rows}` (same data as the " + "`low_cardinality_*` scenarios above). Query: " + "`SELECT eql_v2.hmac_256(value), count(*) FROM tbl GROUP BY 1 " + "ORDER BY count(*) DESC LIMIT 10`. The bench always emits 10 rows " + "regardless of input size, so the cost is dominated by the inner " + "HashAggregate (per-row HMAC + hash-table insert) plus a tiny " + "sort over the 250 group entries. Realistic shape for analytics " + "queries that surface the most common categories in an encrypted " + "dataset." + ), + "top_n_groups_plaintext": ( + "Plaintext baseline: top 10 categories by frequency on a plain TEXT " + "column", + "Table: `category_plaintext_{rows}`. Same query shape as the " + "encrypted top-N scenario; the delta is the EQL recipe's overhead " + "for the same shape on the same cardinality data." + ) + }, + "COMBO": { + "bloom_ore_order_limit": ( + "Composite predicate: filter by name pattern (bloom), order by age " + "(ORE), limit 10", + "Table: `combo_encrypted_{rows}` with three encrypted columns — " + "`name` (match + hmac), `age` (ORE), `category` (hmac). Indexes: " + "functional GIN on `eql_v2.bloom_filter(name)`, functional btree on " + "`eql_v2.ore_block_u64_8_256(age)`, functional hash on " + "`eql_v2.hmac_256(category)`. **The bloom GIN index engages for the " + "LIKE predicate**, narrowing the input to ~0.01–0.1% of rows; the " + "planner then sorts the small filtered set by `eql_v2.ore_block_u64_8_256(age)` " + "and returns the top 10. The ORE btree doesn't engage here — PostgreSQL " + "can't merge two unrelated indexes on different columns (bloom on `name`, " + "btree on `age`), so the ORDER BY is satisfied by a Sort node above the " + "Bitmap Heap Scan. With the bloom narrowing so aggressively, that Sort " + "is cheap; the cost is dominated by the bloom + heap fetch." + ), + "filtered_group_by": ( + "Composite predicate: filter by name pattern, GROUP BY category", + "Table: `combo_encrypted_{rows}`. Query: `SELECT eql_v2.hmac_256(category), " + "count(*) FROM tbl WHERE name LIKE $1 GROUP BY 1`. Bloom filter on " + "`name` filters the input set; HashAggregate then groups the small " + "post-filter set by the 32-byte category HMAC. With ~0.01-0.1% of " + "names matching a typical bloom pattern and 250 category buckets, the " + "aggregate stage is essentially free — the cost is bloom filter scan " + "plus per-matching-row HMAC." + ), + "top_n_filtered_group_by": ( + "Dashboard analytic: top 10 categories for customers matching a name " + "pattern", + "Table: `combo_encrypted_{rows}`. Query: `SELECT eql_v2.hmac_256(category), " + "count(*) FROM tbl WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) " + "DESC LIMIT 10`. Same shape as `filtered_group_by` with an outer " + "Top-N sort + LIMIT 10. Realistic analytics shape for surfacing the " + "categories that contain the most customers matching a filter, " + "without revealing the underlying names or category labels." + ) + }, + "JSON": { + "field_eq": ( + "Field-level equality on an ste_vec document via `hmac_256_terms`", + "Table: `json_ste_vec_small_encrypted_{rows}` with encrypted JSON " + "documents (small four-field shape — first_name / last_name / age / email). " + "Index: functional GIN on `eql_v2.hmac_256_terms(value)`. One index covers " + "field-level equality across every selector that carries `hm`, vs the " + "per-selector `hash (eql_v2.hmac_256(col, ''))` recipe which " + "needs one index per hot path. The bench picks a (selector, hmac) pair " + "from `sv[0]` of a sample row at startup; the query body matches the " + "documented EQL recipe." + ), + "field_extract": ( + "Sequential field extraction via `eql_v2.jsonb_path_query`", + "Table: `json_ste_vec_small_encrypted_{rows}`. No index — measures the " + "per-row cost of the inlinable `jsonb_path_query` body " + "(`jsonb_array_elements((val).data -> 'sv') WHERE elem ->> 's' = selector`). " + "Inlining means the body folds into the calling query, so each row pays " + "an array walk rather than a plpgsql function call. Query: " + "`SELECT eql_v2.jsonb_path_query(value, '') FROM tbl LIMIT 1000`." + ), + "field_group_by": ( + "Field-level `GROUP BY` on an ste_vec document", + "Table: `json_ste_vec_small_encrypted_{rows}`. No index — HashAggregate " + "is in-memory. Query: " + "`GROUP BY eql_v2.hmac_256(value, '')`. Same extractor-form " + "recipe as the top-level GROUP_BY bench, scaled to a single field " + "inside an ste_vec doc." ) } } - + return descriptions.get(query_type, {}).get(query_name, ("Unknown query", "")) + def planner_estimated_rows(self, explain: list) -> Optional[int]: + """Pull the top-level Plan's `Plan Rows` from an EXPLAIN (FORMAT JSON) + result. That's the planner's row-count estimate for the final output; + for LIMIT-bounded queries it matches the LIMIT, for aggregates it's + the estimated group count. Returns None on malformed input.""" + if not explain: + return None + try: + return int(explain[0]["Plan"]["Plan Rows"]) + except (KeyError, TypeError, IndexError, ValueError): + return None + + def format_plan_tree(self, plan_node: dict, depth: int = 0) -> str: + """Render an EXPLAIN plan node as an indented text tree. One line per + node with the bits a human reader cares about: node type, scan + strategy, target relation, picked index. Children indented two + spaces.""" + indent = " " * depth + node_type = plan_node.get("Node Type", "?") + parts = [node_type] + strategy = plan_node.get("Strategy") + # "Plain" is the default for Aggregate; only show the strategy when + # it's something interesting (Hashed, Sorted, Mixed). + if strategy and strategy != "Plain": + parts.append(f"({strategy})") + relation = plan_node.get("Relation Name") + index = plan_node.get("Index Name") + if index: + parts.append(f"using {index}") + if relation: + parts.append(f"on {relation}") + elif relation: + parts.append(f"on {relation}") + line = f"{indent}{' '.join(parts)}" + child_lines = [ + self.format_plan_tree(child, depth + 1) + for child in plan_node.get("Plans", []) + ] + return "\n".join([line] + child_lines) + def get_table_indexes(self, table_name: str) -> Optional[str]: """Get index SQL for a table by reading from sql/indexes directory""" # Check cache first @@ -330,35 +660,61 @@ def get_table_indexes(self, table_name: str) -> Optional[str]: return None def generate_report(self): - """Generate the full benchmark report""" + """Generate the report as an index page plus one per-query-type page. + + Each per-type page lives at `report/.md` (e.g. `exact.md`); the + top-level `BENCHMARK_REPORT.md` is the index and links into them. + """ + query_types = sorted(set(r.query_type for r in self.query_results)) + + # Per-query-type pages first so the index can link to them. + scenario_pages: Dict[str, str] = {} + for query_type in query_types: + page_name = f"{query_type.lower()}.md" + page_path = self.output_file.parent / page_name + with open(page_path, 'w') as pf: + self._write_query_type_page_content(pf, query_type) + scenario_pages[query_type] = page_name + with open(self.output_file, 'w') as f: - self._write_header(f) + self._write_header(f, scenario_pages) self._write_ingest_section(f) - self._write_query_sections(f) + self._write_query_overview(f, scenario_pages) self._write_footer(f) - def _write_header(self, f): + def _write_header(self, f, scenario_pages: Dict[str, str]): f.write("# Benchmark Report\n\n") - f.write("This report summarizes the performance benchmarks for encrypted database operations.\n\n") + f.write("This report summarises the performance benchmarks for encrypted database operations. " + "Per-query-type detail lives on its own page — click through from the " + "Query Performance section below.\n\n") f.write("## Table of Contents\n\n") f.write("1. [Ingest Throughput](#ingest-throughput)\n") + + # Add subsections for each ingest type + ingest_types = sorted(set(r.bench_type for r in self.ingest_results)) + for it in ingest_types: + title = it.replace('_', ' ').title() + anchor = it.replace('_', '-') + f.write(f" - [{title}](#{anchor})\n") + f.write("2. [Query Performance](#query-performance)\n") - - # Add subsections for each query type - query_types = set(r.query_type for r in self.query_results) - for qt in sorted(query_types): - f.write(f" - [{qt} Queries](#{qt.lower()}-queries)\n") - + for qt in sorted(scenario_pages.keys()): + f.write(f" - [{qt} Queries]({scenario_pages[qt]})\n") + f.write("\n---\n\n") def _write_ingest_section(self, f): f.write("## Ingest Throughput\n\n") f.write("This section measures the throughput of inserting encrypted records into the database.\n\n") - # Group by bench_type - types = ["int", "json_small", "string"] + # Add comparison charts at the top if matplotlib is available + if HAS_MATPLOTLIB: + self._write_comparison_charts(f) + + # Group by bench_type - use all types found in results + ingest_types = sorted(set(r.bench_type for r in self.ingest_results)) - for bench_type in types: + for bench_type in ingest_types: results = [r for r in self.ingest_results if r.bench_type == bench_type] if not results: continue @@ -368,12 +724,18 @@ def _write_ingest_section(self, f): f.write(f"### {bench_type.replace('_', ' ').title()}\n\n") - if bench_type == "int": - f.write("Tests insertion of encrypted integer values.\n\n") - elif bench_type == "json_small": - f.write("Tests insertion of small encrypted JSON objects.\n\n") - elif bench_type == "string": - f.write("Tests insertion of encrypted string values.\n\n") + # Add descriptions for each type + descriptions = { + "int": "Tests insertion of encrypted integer values.", + "json_small": "Tests insertion of small encrypted JSON objects (first_name, last_name, age, email).", + "json_large": "Tests insertion of large encrypted JSON objects with complex nested structures (user info, company, addresses, orders).", + "string": "Tests insertion of encrypted string values.", + "ste_vec_small": "Tests insertion of small JSON objects with SteVec (searchable encrypted vector) indexing.", + "ste_vec_large": "Tests insertion of large JSON objects with SteVec (searchable encrypted vector) indexing.", + } + + if bench_type in descriptions: + f.write(f"{descriptions[bench_type]}\n\n") # Table f.write("| Records | Throughput (records/sec) | Total Time | Avg Memory |\n") @@ -385,13 +747,19 @@ def _write_ingest_section(self, f): f.write("\n") - # Generate chart if matplotlib is available + # Generate charts if matplotlib is available if HAS_MATPLOTLIB: - chart_path = self.output_file.parent / f"ingest_{bench_type}_chart.png" - self._create_ingest_chart(results, bench_type, chart_path) - f.write(f"![Ingest Throughput - {bench_type}]({chart_path.name})\n\n") + # Throughput chart + throughput_chart_path = self.output_file.parent / f"ingest_{bench_type}_throughput_chart.png" + self._create_ingest_throughput_chart(results, bench_type, throughput_chart_path) + f.write(f"![Ingest Throughput - {bench_type}]({throughput_chart_path.name})\n\n") + + # Total time chart + time_chart_path = self.output_file.parent / f"ingest_{bench_type}_time_chart.png" + self._create_ingest_time_chart(results, bench_type, time_chart_path) + f.write(f"![Ingest Total Time - {bench_type}]({time_chart_path.name})\n\n") - def _create_ingest_chart(self, results: List[IngestResult], bench_type: str, output_path: Path): + def _create_ingest_throughput_chart(self, results: List[IngestResult], bench_type: str, output_path: Path): """Create a bar chart for ingest throughput""" fig, ax = plt.subplots(figsize=(10, 6)) @@ -405,96 +773,346 @@ def _create_ingest_chart(self, results: List[IngestResult], bench_type: str, out ax.set_xticks(range(len(records))) ax.set_xticklabels([f"{r:,}" for r in records]) ax.grid(axis='y', alpha=0.3) + ax.set_ylim(bottom=0) + + # Add "larger is better" annotation + ax.text(0.98, 0.98, 'larger is better ↑', transform=ax.transAxes, + fontsize=11, verticalalignment='top', horizontalalignment='right', + bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) + + plt.tight_layout() + plt.savefig(output_path, dpi=100, bbox_inches='tight') + plt.close() + + def _create_ingest_time_chart(self, results: List[IngestResult], bench_type: str, output_path: Path): + """Create a bar chart for total ingest time""" + fig, ax = plt.subplots(figsize=(10, 6)) + + records = [r.num_records for r in results] + times = [r.total_time for r in results] + + ax.bar(range(len(records)), times, color='coral') + ax.set_xlabel('Number of Records') + ax.set_ylabel('Total Time (seconds)') + ax.set_title(f'Ingest Total Time - {bench_type.replace("_", " ").title()}') + ax.set_xticks(range(len(records))) + ax.set_xticklabels([f"{r:,}" for r in records]) + ax.grid(axis='y', alpha=0.3) + ax.set_ylim(bottom=0) + + # Add "smaller is better" annotation + ax.text(0.98, 0.98, 'smaller is better ↓', transform=ax.transAxes, + fontsize=11, verticalalignment='top', horizontalalignment='right', + bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.5)) plt.tight_layout() plt.savefig(output_path, dpi=100, bbox_inches='tight') plt.close() + + def _write_comparison_charts(self, f): + """Write comparison charts for all benchmark types at 10000 rows""" + target_row_count = 10000 + + # Get results for each bench type at target row count + comparison_data = {} + for result in self.ingest_results: + if result.num_records == target_row_count: + comparison_data[result.bench_type] = result + + if len(comparison_data) < 2: + # Not enough data for comparison + return + + f.write(f"### Comparison at {target_row_count:,} Records\n\n") + f.write(f"Comparing all benchmark types at {target_row_count:,} records.\n\n") + + # Create throughput comparison chart + throughput_chart_path = self.output_file.parent / f"ingest_comparison_throughput_{target_row_count}.png" + self._create_comparison_throughput_chart(comparison_data, target_row_count, throughput_chart_path) + f.write(f"![Throughput Comparison at {target_row_count:,} records]({throughput_chart_path.name})\n\n") + + # Create time comparison chart + time_chart_path = self.output_file.parent / f"ingest_comparison_time_{target_row_count}.png" + self._create_comparison_time_chart(comparison_data, target_row_count, time_chart_path) + f.write(f"![Total Time Comparison at {target_row_count:,} records]({time_chart_path.name})\n\n") + + # Create time comparison chart without ste_vec_large + filtered_data = {k: v for k, v in comparison_data.items() if k != 'ste_vec_large'} + if len(filtered_data) >= 2: + time_chart_path_filtered = self.output_file.parent / f"ingest_comparison_time_{target_row_count}_filtered.png" + self._create_comparison_time_chart(filtered_data, target_row_count, time_chart_path_filtered, exclude_label='ste_vec_large') + f.write(f"![Total Time Comparison at {target_row_count:,} records (excluding ste_vec_large)]({time_chart_path_filtered.name})\n\n") + + def _create_comparison_throughput_chart(self, comparison_data: Dict[str, IngestResult], + row_count: int, output_path: Path): + """Create a bar chart comparing throughput across all benchmark types""" + fig, ax = plt.subplots(figsize=(12, 6)) + + # Sort by throughput descending (highest on left) + sorted_items = sorted(comparison_data.items(), key=lambda x: x[1].throughput, reverse=True) + bench_types = [item[0] for item in sorted_items] + labels = [bt.replace('_', ' ').title() for bt in bench_types] + throughputs = [comparison_data[bt].throughput for bt in bench_types] + + # Use different colors for each bar + colors = plt.cm.Set3(range(len(bench_types))) + + ax.bar(range(len(bench_types)), throughputs, color=colors) + ax.set_xlabel('Benchmark Type', fontsize=12) + ax.set_ylabel('Throughput (records/sec)', fontsize=12) + ax.set_title(f'Ingest Throughput Comparison at {row_count:,} Records', fontsize=14, fontweight='bold') + ax.set_xticks(range(len(bench_types))) + ax.set_xticklabels(labels, rotation=45, ha='right') + ax.grid(axis='y', alpha=0.3) + ax.set_ylim(bottom=0) - def _write_query_sections(self, f): - f.write("## Query Performance\n\n") - f.write("This section measures query performance across different data set sizes. " - "Each query is tested with and without decryption of results.\n\n") + # Add "larger is better" annotation + ax.text(0.98, 0.98, 'larger is better ↑', transform=ax.transAxes, + fontsize=11, verticalalignment='top', horizontalalignment='right', + bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5)) - # Group by query type (EXACT, MATCH, ORE) - query_types = sorted(set(r.query_type for r in self.query_results)) + plt.tight_layout() + plt.savefig(output_path, dpi=100, bbox_inches='tight') + plt.close() + + def _create_comparison_time_chart(self, comparison_data: Dict[str, IngestResult], + row_count: int, output_path: Path, exclude_label: str = None): + """Create a bar chart comparing total time across all benchmark types""" + fig, ax = plt.subplots(figsize=(12, 6)) - for query_type in query_types: - self._write_query_type_section(f, query_type) + # Sort by throughput descending (highest on left) to match throughput chart order + sorted_items = sorted(comparison_data.items(), key=lambda x: x[1].throughput, reverse=True) + bench_types = [item[0] for item in sorted_items] + labels = [bt.replace('_', ' ').title() for bt in bench_types] + times = [comparison_data[bt].total_time for bt in bench_types] + + # Use different colors for each bar + colors = plt.cm.Set2(range(len(bench_types))) + + ax.bar(range(len(bench_types)), times, color=colors) + ax.set_xlabel('Benchmark Type', fontsize=12) + ax.set_ylabel('Total Time (seconds)', fontsize=12) + title = f'Total Ingest Time Comparison at {row_count:,} Records' + if exclude_label: + title += f' (excluding {exclude_label.replace("_", " ").title()})' + ax.set_title(title, fontsize=14, fontweight='bold') + ax.set_xticks(range(len(bench_types))) + ax.set_xticklabels(labels, rotation=45, ha='right') + ax.grid(axis='y', alpha=0.3) + ax.set_ylim(bottom=0) - def _write_query_type_section(self, f, query_type: str): - f.write(f"### {query_type} Queries\n\n") + # Add "smaller is better" annotation + ax.text(0.98, 0.98, 'smaller is better ↓', transform=ax.transAxes, + fontsize=11, verticalalignment='top', horizontalalignment='right', + bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.5)) - # Get all unique query names for this type + plt.tight_layout() + plt.savefig(output_path, dpi=100, bbox_inches='tight') + plt.close() + + def _write_query_overview(self, f, scenario_pages: Dict[str, str]): + """Brief overview of the per-query-type pages on the index file. + + Picks the bits most useful for orienting a reader before they click + through: which scenarios live under each type, which row-count tiers + ran, and what the median timing looks like at the largest tier so the + index gives an immediate sense of where the costs live. + """ + f.write("## Query Performance\n\n") + f.write("Per-query-type detail is broken out into separate pages — click into a " + "scenario family for the SQL, per-tier timings, the indexes the planner " + "picked, and the EXPLAIN plan tree.\n\n") + f.write("| Query Type | Scenarios | Tiers | Largest-tier median (no decrypt) | Detail |\n") + f.write("|-|-|-|-|-|\n") + for qt in sorted(scenario_pages.keys()): + type_results = [r for r in self.query_results if r.query_type == qt] + if not type_results: + continue + scenarios = sorted(set(r.query_name for r in type_results)) + tiers = sorted(set(r.row_count for r in type_results)) + tiers_str = ", ".join(f"{t:,}" for t in tiers) + scenarios_str = ", ".join(f"`{s}`" for s in scenarios) + # Median timing at the largest tier, averaged across scenarios for + # a single-number summary. Not a substitute for the detail page; + # just enough to flag "this family runs in seconds" vs "this one + # is sub-millisecond". + biggest = max(tiers) + biggest_results = [r for r in type_results + if r.row_count == biggest and not r.decrypt] + if biggest_results: + med_ns = sum(r.median_ns for r in biggest_results) / len(biggest_results) + med_str = self.format_time(med_ns, include_indicator=False) + else: + med_str = "—" + page = scenario_pages[qt] + f.write(f"| {qt} | {scenarios_str} | {tiers_str} | {med_str} | [open]({page}) |\n") + f.write("\n") + + def _write_query_type_page_content(self, f, query_type: str): + """Write a self-contained per-query-type page.""" + f.write(f"# {query_type} Queries\n\n") + f.write(f"[← Back to overview](./{self.output_file.name})\n\n") + f.write("Per-tier query performance. Each scenario lists its SQL, the indexes " + "available on the target table, the indexes the planner actually picked " + "per tier, the timing table, and the full EXPLAIN plan in a collapsed " + "block.\n\n") type_results = [r for r in self.query_results if r.query_type == query_type] query_names = sorted(set(r.query_name for r in type_results)) - for query_name in query_names: - self._write_query_subsection(f, query_type, query_name) + self._write_query_subsection(f, query_type, query_name, heading="##") - def _write_query_subsection(self, f, query_type: str, query_name: str): + def _write_query_subsection(self, f, query_type: str, query_name: str, + heading: str = "##"): # Get results for this specific query - results = [r for r in self.query_results + results = [r for r in self.query_results if r.query_type == query_type and r.query_name == query_name] - + if not results: return - + # Sort by row count results.sort(key=lambda x: (x.row_count, x.decrypt)) - + # Get description description, table_info = self.get_query_description(query_type, query_name) sql_query, param = self.get_query_sql_and_param(query_type, query_name) - - f.write(f"#### {query_name}\n\n") + + f.write(f"{heading} {query_name}\n\n") f.write(f"**Description:** {description}\n\n") # Add SQL query and parameter if sql_query: f.write(f"**SQL Query:**\n```sql\n{sql_query}\n```\n\n") - f.write(f"**Parameter:** `{param}`\n\n") - + if param: + f.write(f"**Parameter:** `{param}`\n\n") + f.write(f"**{table_info}**\n\n") - + # Add index information for one of the row counts (they all use same indexes) if results: - # Determine table name based on query type + # Determine table name based on query type / scenario. sample_row_count = results[0].row_count - if query_type in ["EXACT", "MATCH"]: + if query_type == "GROUP_BY" and query_name.endswith("_plaintext"): + # Plaintext baselines run against a plain TEXT column — no + # functional EQL indexes; lookup will return None and the + # Indexes block will be skipped. + table_name = f"category_plaintext_{sample_row_count}" + elif query_type == "GROUP_BY": + # Encrypted GROUP BY scenarios run against the categorical + # 250-bucket table family. + table_name = f"category_encrypted_{sample_row_count}" + elif query_type in ["EXACT", "MATCH"]: + # String-encrypted scenarios. table_name = f"string_encrypted_{sample_row_count}" elif query_type == "ORE": table_name = f"integer_encrypted_{sample_row_count}" + elif query_type == "JSON": + table_name = f"json_ste_vec_small_encrypted_{sample_row_count}" + elif query_type == "COMBO": + table_name = f"combo_encrypted_{sample_row_count}" else: table_name = "" - + if table_name: indexes_sql = self.get_table_indexes(table_name) if indexes_sql: - f.write(f"**Indexes:**\n```sql\n{indexes_sql}\n```\n\n") - + f.write(f"**Indexes available on the table:**\n```sql\n{indexes_sql}\n```\n\n") + + # Group by row_count for the various per-tier renderings below. + row_counts = sorted(set(r.row_count for r in results)) + + # Indexes used per data set size, sourced from the EXPLAIN metadata + # sidecars. The list can vary between tiers — small tables often + # take a Seq Scan even when a functional index exists. + used_by_size = [ + (rc, self.metadata.get((query_type, query_name, rc))) + for rc in row_counts + ] + if any(m is not None for _, m in used_by_size): + f.write("**Indexes used by the planner (per data set size):**\n\n") + for rc, meta in used_by_size: + if meta is None: + f.write(f"- {rc:,}: _(no metadata)_\n") + elif meta.indexes_used: + idx_list = ", ".join(f"`{i}`" for i in meta.indexes_used) + f.write(f"- {rc:,}: {idx_list}\n") + else: + f.write(f"- {rc:,}: _none — planner picked a sequential / hash-aggregate / sort plan_\n") + f.write("\n") + # Create table with legend if any results exceed 100ms has_slow_queries = any((r.mean_ns / 1_000_000) > 100 for r in results) - + if has_slow_queries: f.write("*⚠️ = Query time exceeds 100ms*\n\n") - - f.write("| Data Set Size | Query Time (no decrypt) | Query Time (with decrypt) |\n") - f.write("|---------------|-------------------------|---------------------------|\n") - - # Group by row_count - row_counts = sorted(set(r.row_count for r in results)) - + + # Decide column header based on whether any tier has actual rows + # data (preferred) or only planner estimates from EXPLAIN. + any_actual = any( + (m := self.metadata.get((query_type, query_name, rc))) is not None + and m.rows_returned is not None + for rc in row_counts + ) + rows_header = "Rows Returned" if any_actual else "Rows (est.)" + f.write(f"| Data Set Size | {rows_header} | Query Time (no decrypt) | Query Time (with decrypt) |\n") + f.write("|---------------|-") + f.write("-" * len(rows_header)) + f.write("-|-------------------------|---------------------------|\n") + for row_count in row_counts: no_decrypt = next((r for r in results if r.row_count == row_count and not r.decrypt), None) with_decrypt = next((r for r in results if r.row_count == row_count and r.decrypt), None) - + no_decrypt_str = self.format_time(no_decrypt.mean_ns) if no_decrypt else "N/A" with_decrypt_str = self.format_time(with_decrypt.mean_ns) if with_decrypt else "N/A" - - f.write(f"| {row_count:,} | {no_decrypt_str} | {with_decrypt_str} |\n") - + + meta = self.metadata.get((query_type, query_name, row_count)) + # Prefer the actual row count from a pre-bench execute; fall + # back to the planner's estimate when the sidecar predates + # actual-rows capture, with an explicit (est.) suffix so the + # number isn't misread as authoritative. + if meta is not None and meta.rows_returned is not None: + rows_str = f"{meta.rows_returned:,}" + elif meta is not None: + planner = self.planner_estimated_rows(meta.explain) + rows_str = f"{planner:,} (est.)" if planner is not None else "—" + else: + rows_str = "—" + + f.write(f"| {row_count:,} | {rows_str} | {no_decrypt_str} | {with_decrypt_str} |\n") + f.write("\n") - + if not any_actual: + f.write("_Rows are the planner's estimate from `EXPLAIN` " + "captured before the bench loop; re-run the bench with the " + "current source to capture actual row counts._\n\n") + else: + f.write("_Rows Returned is the actual count from a one-shot pre-bench " + "execution. For LIMIT-bounded queries it matches the LIMIT (or " + "is lower when the table doesn't have enough matching rows); " + "for aggregates wrapped in `count(*)` it's 1._\n\n") + + # Per-tier EXPLAIN plans (collapsed). Useful when the plan shape + # changes across data sizes — e.g. the ORE bench, where the planner + # picks Seq Scan at every tier for bare-range queries but switches to + # Index Scan for the hybrid ordered scenario. + explain_blocks = [ + (rc, meta) + for rc, meta in used_by_size + if meta is not None and meta.explain + ] + if explain_blocks: + f.write("
\nEXPLAIN plans (per data set size)\n\n") + for rc, meta in explain_blocks: + f.write(f"**{rc:,} rows**\n\n") + plan = meta.explain[0].get("Plan", {}) + tree = self.format_plan_tree(plan) + f.write(f"```\n{tree}\n```\n\n") + f.write("Full `EXPLAIN (FORMAT JSON)`:\n\n") + pretty = json.dumps(meta.explain, indent=2) + f.write(f"```json\n{pretty}\n```\n\n") + f.write("
\n\n") + # Generate chart if matplotlib is available if HAS_MATPLOTLIB and len(row_counts) > 1: chart_path = self.output_file.parent / f"query_{query_type.lower()}_{query_name}_chart.png" @@ -531,13 +1149,19 @@ def _create_query_chart(self, results: List[QueryResult], query_type: str, ax.set_ylabel('Query Time (ms)', fontsize=12) ax.set_title(f'{query_type} - {query_name}', fontsize=14, fontweight='bold') ax.set_xscale('log') + ax.set_ylim(bottom=0) ax.grid(True, alpha=0.3) ax.legend(fontsize=10) - + # Format x-axis labels ax.set_xticks(row_counts) ax.set_xticklabels([f"{r:,}" for r in row_counts]) + # Add "smaller is better" annotation + ax.text(0.98, 0.98, 'smaller is better ↓', transform=ax.transAxes, + fontsize=11, verticalalignment='top', horizontalalignment='right', + bbox=dict(boxstyle='round', facecolor='lightblue', alpha=0.5)) + plt.tight_layout() plt.savefig(output_path, dpi=100, bbox_inches='tight') plt.close() @@ -574,6 +1198,10 @@ def main(): print("Loading query results...") reporter.load_query_results() print(f" Found {len(reporter.query_results)} query results") + + print("Loading query metadata sidecars...") + reporter.load_query_metadata() + print(f" Found {len(reporter.metadata)} per-scenario metadata records") print(f"Generating report: {args.output}") reporter.generate_report() diff --git a/results/ingest/encrypt_ste_vec_small_combined.json b/results/ingest/encrypt_ste_vec_small_combined.json new file mode 100644 index 0000000..79090a6 --- /dev/null +++ b/results/ingest/encrypt_ste_vec_small_combined.json @@ -0,0 +1,24 @@ +{ + "metadata": { + "timestamp": "2026-05-13T13:11:12.461702+00:00", + "rust_version": "rustc 1.92.0 (ded5c06cf 2025-12-08)", + "postgres_version": "psql (PostgreSQL) 17.7 (Debian 17.7-3.pgdg13+1)", + "host_info": { + "os": "macOS", + "cpu_model": "Apple M1 Max", + "cpu_cores": 10, + "total_memory_gb": 64.0 + } + }, + "results": [ + { + "num_records": 10000, + "total_time_seconds": 2.47986869314, + "total_records": 10000, + "throughput_records_per_second": 4032.4715690241, + "average_memory_usage_bytes": 33447936, + "average_memory_usage_mb": 31.8984375, + "num_runs": 2 + } + ] +} \ No newline at end of file diff --git a/results/query/combo_metadata_10000.json b/results/query/combo_metadata_10000.json new file mode 100644 index 0000000..5d13fe6 --- /dev/null +++ b/results/query/combo_metadata_10000.json @@ -0,0 +1,288 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1603,1789,1164,10,1555}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1603,1789,1164,10,1555}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 60.74, + "Total Cost": 60.75 + } + ], + "Startup Cost": 60.74, + "Total Cost": 60.75 + } + } + ], + "id": "COMBO/combo/bloom_ore_order_limit/10000", + "indexes_used": [ + "combo_encrypted_10000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 1603, + 1789, + 1164, + 10, + 1555 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id FROM combo_encrypted_10000 WHERE name LIKE $1 ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "rows_returned": 9 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,10,1555,1789,1603,36}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,10,1555,1789,1603,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.49 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 60.5, + "Total Cost": 60.5 + } + ], + "Startup Cost": 60.5, + "Strategy": "Sorted", + "Total Cost": 60.52 + } + } + ], + "id": "COMBO/combo/filtered_group_by/10000", + "indexes_used": [ + "combo_encrypted_10000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1164, + 10, + 1555, + 1789, + 1603, + 36 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_10000 WHERE name LIKE $1 GROUP BY 1", + "rows_returned": 9 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1164,10,1555}'::smallint[])", + "Index Name": "combo_encrypted_10000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1164,10,1555}'::smallint[])", + "Relation Name": "combo_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.49 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 60.5, + "Total Cost": 60.5 + } + ], + "Startup Cost": 60.5, + "Strategy": "Sorted", + "Total Cost": 60.52 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 60.53, + "Total Cost": 60.53 + } + ], + "Startup Cost": 60.53, + "Total Cost": 60.53 + } + } + ], + "id": "COMBO/combo/top_n_filtered_group_by/10000", + "indexes_used": [ + "combo_encrypted_10000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 1789, + 1603, + 1164, + 10, + 1555 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_10000 WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 9 + } + ], + "target_rows": "10000" +} \ No newline at end of file diff --git a/results/query/combo_metadata_100000.json b/results/query/combo_metadata_100000.json new file mode 100644 index 0000000..d5c4dbe --- /dev/null +++ b/results/query/combo_metadata_100000.json @@ -0,0 +1,288 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{10,1789,1555,36,1603,1164}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{10,1789,1555,36,1603,1164}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 97.87, + "Total Cost": 97.87 + } + ], + "Startup Cost": 97.87, + "Total Cost": 97.87 + } + } + ], + "id": "COMBO/combo/bloom_ore_order_limit/100000", + "indexes_used": [ + "combo_encrypted_100000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 10, + 1789, + 1555, + 36, + 1603, + 1164 + ], + "i": { + "c": "name", + "t": "combo_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id FROM combo_encrypted_100000 WHERE name LIKE $1 ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,10,1164,36,1555,1789}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,10,1164,36,1555,1789}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.61 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 97.62, + "Total Cost": 97.63 + } + ], + "Startup Cost": 97.62, + "Strategy": "Sorted", + "Total Cost": 97.64 + } + } + ], + "id": "COMBO/combo/filtered_group_by/100000", + "indexes_used": [ + "combo_encrypted_100000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1603, + 10, + 1164, + 36, + 1555, + 1789 + ], + "i": { + "c": "name", + "t": "combo_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_100000 WHERE name LIKE $1 GROUP BY 1", + "rows_returned": 42 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Index Name": "combo_encrypted_100000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Relation Name": "combo_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.61 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 97.62, + "Total Cost": 97.63 + } + ], + "Startup Cost": 97.62, + "Strategy": "Sorted", + "Total Cost": 97.64 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 97.65, + "Total Cost": 97.66 + } + ], + "Startup Cost": 97.65, + "Total Cost": 97.66 + } + } + ], + "id": "COMBO/combo/top_n_filtered_group_by/100000", + "indexes_used": [ + "combo_encrypted_100000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 1789, + 1603, + 1555, + 10, + 1164 + ], + "i": { + "c": "name", + "t": "combo_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_100000 WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "100000" +} \ No newline at end of file diff --git a/results/query/combo_metadata_1000000.json b/results/query/combo_metadata_1000000.json new file mode 100644 index 0000000..2a28c27 --- /dev/null +++ b/results/query/combo_metadata_1000000.json @@ -0,0 +1,288 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1789,1164,10,1555,36}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1789,1164,10,1555,36}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.48 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 316.49, + "Total Cost": 316.5 + } + ], + "Startup Cost": 316.49, + "Total Cost": 316.5 + } + } + ], + "id": "COMBO/combo/bloom_ore_order_limit/1000000", + "indexes_used": [ + "combo_encrypted_1000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1603, + 1789, + 1164, + 10, + 1555, + 36 + ], + "i": { + "c": "name", + "t": "combo_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id FROM combo_encrypted_1000000 WHERE name LIKE $1 ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,36,1789,1603,1164,10}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,36,1789,1603,1164,10}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.24 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 316.25, + "Total Cost": 316.25 + } + ], + "Startup Cost": 316.25, + "Strategy": "Sorted", + "Total Cost": 316.27 + } + } + ], + "id": "COMBO/combo/filtered_group_by/1000000", + "indexes_used": [ + "combo_encrypted_1000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1555, + 36, + 1789, + 1603, + 1164, + 10 + ], + "i": { + "c": "name", + "t": "combo_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_1000000 WHERE name LIKE $1 GROUP BY 1", + "rows_returned": 235 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,1164,1603,36,10,1789}'::smallint[])", + "Index Name": "combo_encrypted_1000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 311.97 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1555,1164,1603,36,10,1789}'::smallint[])", + "Relation Name": "combo_encrypted_1000000", + "Startup Cost": 311.97, + "Total Cost": 316.24 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 316.25, + "Total Cost": 316.25 + } + ], + "Startup Cost": 316.25, + "Strategy": "Sorted", + "Total Cost": 316.27 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 316.28, + "Total Cost": 316.28 + } + ], + "Startup Cost": 316.28, + "Total Cost": 316.28 + } + } + ], + "id": "COMBO/combo/top_n_filtered_group_by/1000000", + "indexes_used": [ + "combo_encrypted_1000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1555, + 1164, + 1603, + 36, + 10, + 1789 + ], + "i": { + "c": "name", + "t": "combo_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_1000000 WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "1000000" +} \ No newline at end of file diff --git a/results/query/combo_metadata_10000000.json b/results/query/combo_metadata_10000000.json new file mode 100644 index 0000000..0b818a4 --- /dev/null +++ b/results/query/combo_metadata_10000000.json @@ -0,0 +1,288 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,10,1603,1555,36}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,10,1603,1555,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.61 + } + ], + "Sort Key": [ + "(eql_v2.ore_block_u64_8_256(age))" + ], + "Startup Cost": 2300.62, + "Total Cost": 2300.62 + } + ], + "Startup Cost": 2300.62, + "Total Cost": 2300.62 + } + } + ], + "id": "COMBO/combo/bloom_ore_order_limit/10000000", + "indexes_used": [ + "combo_encrypted_10000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1164, + 1789, + 10, + 1603, + 1555, + 36 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id FROM combo_encrypted_10000000 WHERE name LIKE $1 ORDER BY eql_v2.ore_block_u64_8_256(age) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,1555,10,36,1603}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1164,1789,1555,10,36,1603}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.36 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 2300.37, + "Total Cost": 2300.38 + } + ], + "Startup Cost": 2300.37, + "Strategy": "Sorted", + "Total Cost": 2300.39 + } + } + ], + "id": "COMBO/combo/filtered_group_by/10000000", + "indexes_used": [ + "combo_encrypted_10000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1164, + 1789, + 1555, + 10, + 36, + 1603 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_10000000 WHERE name LIKE $1 GROUP BY 1", + "rows_returned": 250 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Alias": "combo_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1555,10,1164,1789,36}'::smallint[])", + "Index Name": "combo_encrypted_10000000_name_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2296.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(name))::smallint[] @> '{1603,1555,10,1164,1789,36}'::smallint[])", + "Relation Name": "combo_encrypted_10000000", + "Startup Cost": 2296.1, + "Total Cost": 2300.36 + } + ], + "Sort Key": [ + "((((category).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 2300.37, + "Total Cost": 2300.38 + } + ], + "Startup Cost": 2300.37, + "Strategy": "Sorted", + "Total Cost": 2300.39 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 2300.4, + "Total Cost": 2300.41 + } + ], + "Startup Cost": 2300.4, + "Total Cost": 2300.41 + } + } + ], + "id": "COMBO/combo/top_n_filtered_group_by/10000000", + "indexes_used": [ + "combo_encrypted_10000000_name_gin_index" + ], + "parameters": [ + { + "bf": [ + 1603, + 1555, + 10, + 1164, + 1789, + 36 + ], + "i": { + "c": "name", + "t": "combo_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT eql_v2.hmac_256(category), count(*) FROM combo_encrypted_10000000 WHERE name LIKE $1 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "10000000" +} \ No newline at end of file diff --git a/results/query/combo_rows_10000.json b/results/query/combo_rows_10000.json new file mode 100644 index 0000000..77c8f88 --- /dev/null +++ b/results/query/combo_rows_10000.json @@ -0,0 +1,4 @@ +{"reason":"benchmark-complete","id":"COMBO/combo/bloom_ore_order_limit/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_bloom_ore_order_limit_10000","iteration_count":[84,168,252,336,420,504,588,672,756,840],"measured_values":[94558375.0,180183292.0,288286292.0,361396542.0,433502458.0,510542000.0,705482209.0,853377042.0,856637750.0,2694443041.0],"unit":"ns","throughput":[],"typical":{"estimate":1682612.7474335188,"lower_bound":1089849.8882459,"upper_bound":2473305.4242325015,"unit":"ns"},"mean":{"estimate":1327341.6564125093,"lower_bound":1083009.4327683295,"upper_bound":1759939.7461394556,"unit":"ns"},"median":{"estimate":1129406.8287037038,"lower_bound":1053866.8279761905,"upper_bound":1206949.767361111,"unit":"ns"},"median_abs_dev":{"estimate":94352.72157847577,"lower_bound":13564.516017515012,"upper_bound":186433.0983597937,"unit":"ns"},"slope":{"estimate":1682612.7474335188,"lower_bound":1089849.8882459,"upper_bound":2473305.4242325015,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/filtered_group_by/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_filtered_group_by_10000","iteration_count":[80,160,240,320,400,480,560,640,720,800],"measured_values":[68843917.0,241441041.0,260454666.0,394839792.0,370265375.0,451311209.0,397054500.0,476663625.0,549455667.0,619173667.0],"unit":"ns","throughput":[],"typical":{"estimate":818219.8528246753,"lower_bound":768517.2702997143,"upper_bound":933151.7095553013,"unit":"ns"},"mean":{"estimate":954546.5478169642,"lower_bound":818768.5416244791,"upper_bound":1114628.8907291666,"unit":"ns"},"median":{"estimate":893106.2,"lower_bound":759376.99890625,"upper_bound":1087053.0177083334,"unit":"ns"},"median_abs_dev":{"estimate":206298.3119141915,"lower_bound":27199.71502554605,"upper_bound":397252.0121651795,"unit":"ns"},"slope":{"estimate":818219.8528246753,"lower_bound":768517.2702997143,"upper_bound":933151.7095553013,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/top_n_filtered_group_by/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_top_n_filtered_group_by_10000","iteration_count":[105,210,315,420,525,630,735,840,945,1050],"measured_values":[115803417.0,360273125.0,269562708.0,283642958.0,318347666.0,391719334.0,501856375.0,588216292.0,681796125.0,729282834.0],"unit":"ns","throughput":[],"typical":{"estimate":701778.1665553494,"lower_bound":670580.8208674552,"upper_bound":746786.7524171646,"unit":"ns"},"mean":{"estimate":837681.1967845804,"lower_bound":677646.3528478459,"upper_bound":1065693.702502947,"unit":"ns"},"median":{"estimate":697406.2852380952,"lower_bound":652287.2548752835,"upper_bound":912183.5333333334,"unit":"ns"},"median_abs_dev":{"estimate":73908.0981812023,"lower_bound":12942.876388789418,"upper_bound":345615.47844267025,"unit":"ns"},"slope":{"estimate":701778.1665553494,"lower_bound":670580.8208674552,"upper_bound":746786.7524171646,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"COMBO","benchmarks":["COMBO/combo/bloom_ore_order_limit/10000","COMBO/combo/filtered_group_by/10000","COMBO/combo/top_n_filtered_group_by/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO"} diff --git a/results/query/combo_rows_100000.json b/results/query/combo_rows_100000.json new file mode 100644 index 0000000..ce3f11b --- /dev/null +++ b/results/query/combo_rows_100000.json @@ -0,0 +1,4 @@ +{"reason":"benchmark-complete","id":"COMBO/combo/bloom_ore_order_limit/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_bloom_ore_order_limit_100000","iteration_count":[29,58,87,116,145,174,203,232,261,290],"measured_values":[88275542.0,195222792.0,262384917.0,347524416.0,429947083.0,518904875.0,594623792.0,703940083.0,788381958.0,880631416.0],"unit":"ns","throughput":[],"typical":{"estimate":3010727.917241379,"lower_bound":2974855.0862118113,"upper_bound":3034521.013935459,"unit":"ns"},"mean":{"estimate":3038976.3680747123,"lower_bound":2985287.7508232757,"upper_bound":3119738.8151436783,"unit":"ns"},"median":{"estimate":3018269.557471264,"lower_bound":2980526.2172413794,"upper_bound":3039104.351293104,"unit":"ns"},"median_abs_dev":{"estimate":35644.71969131781,"lower_bound":9040.354001742955,"upper_bound":88836.2701651689,"unit":"ns"},"slope":{"estimate":3010727.917241379,"lower_bound":2974855.0862118113,"upper_bound":3034521.013935459,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/filtered_group_by/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_filtered_group_by_100000","iteration_count":[84,168,252,336,420,504,588,672,756,840],"measured_values":[87863208.0,176645458.0,247898791.0,345002750.0,438618458.0,536872834.0,599180750.0,671862291.0,789477000.0,824211584.0],"unit":"ns","throughput":[],"typical":{"estimate":1017185.009554731,"lower_bound":995832.5986622074,"upper_bound":1043204.7887466308,"unit":"ns"},"mean":{"estimate":1026182.0399305556,"lower_bound":1008370.8763988096,"upper_bound":1042624.0969474206,"unit":"ns"},"median":{"estimate":1035537.8224206349,"lower_bound":999795.0758928572,"upper_bound":1047895.3607142856,"unit":"ns"},"median_abs_dev":{"estimate":24052.35174798536,"lower_bound":1302.2722802134192,"upper_bound":48104.70349597072,"unit":"ns"},"slope":{"estimate":1017185.009554731,"lower_bound":995832.5986622074,"upper_bound":1043204.7887466308,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/top_n_filtered_group_by/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_top_n_filtered_group_by_100000","iteration_count":[90,180,270,360,450,540,630,720,810,900],"measured_values":[79279125.0,166239625.0,247244250.0,326025500.0,427356708.0,499861250.0,567216000.0,657583291.0,741717750.0,838660083.0],"unit":"ns","throughput":[],"typical":{"estimate":920253.4797402597,"lower_bound":910437.8058782124,"upper_bound":929482.5186850519,"unit":"ns"},"mean":{"estimate":916232.7473161377,"lower_bound":905177.4503955358,"upper_bound":927199.2287962962,"unit":"ns"},"median":{"estimate":915710.1851851852,"lower_bound":905626.3888888889,"upper_bound":927699.0044444444,"unit":"ns"},"median_abs_dev":{"estimate":14857.573625114223,"lower_bound":1786.0274428751075,"upper_bound":32658.107648869387,"unit":"ns"},"slope":{"estimate":920253.4797402597,"lower_bound":910437.8058782124,"upper_bound":929482.5186850519,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"COMBO","benchmarks":["COMBO/combo/bloom_ore_order_limit/100000","COMBO/combo/filtered_group_by/100000","COMBO/combo/top_n_filtered_group_by/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO"} diff --git a/results/query/combo_rows_1000000.json b/results/query/combo_rows_1000000.json new file mode 100644 index 0000000..dd7c652 --- /dev/null +++ b/results/query/combo_rows_1000000.json @@ -0,0 +1,4 @@ +{"reason":"benchmark-complete","id":"COMBO/combo/bloom_ore_order_limit/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_bloom_ore_order_limit_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[89227459.0,185395542.0,307156667.0,371222875.0,477400542.0,572873333.0,744229333.0,769211292.0,923407875.0,2539248750.0],"unit":"ns","throughput":[],"typical":{"estimate":34907192.723376624,"lower_bound":24079574.137381002,"upper_bound":49771263.919181034,"unit":"ns"},"mean":{"estimate":28176778.48232143,"lower_bound":23649267.018750004,"upper_bound":36311561.950476184,"unit":"ns"},"median":{"estimate":23953939.9875,"lower_bound":23201429.6875,"upper_bound":26088003.976190478,"unit":"ns"},"median_abs_dev":{"estimate":1795388.6614754805,"lower_bound":124635.26098728272,"upper_bound":3204093.2843909725,"unit":"ns"},"slope":{"estimate":34907192.723376624,"lower_bound":24079574.137381002,"upper_bound":49771263.919181034,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/filtered_group_by/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_filtered_group_by_1000000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[65915458.0,167379541.0,215495042.0,289673167.0,369709459.0,418530875.0,504520875.0,580379042.0,709293791.0,721680500.0],"unit":"ns","throughput":[],"typical":{"estimate":6134353.346103896,"lower_bound":5973174.103603603,"upper_bound":6354742.7256711405,"unit":"ns"},"mean":{"estimate":6109604.172804233,"lower_bound":5888889.899063657,"upper_bound":6360782.48920056,"unit":"ns"},"median":{"estimate":6024430.90625,"lower_bound":5909564.856150793,"upper_bound":6306575.061342592,"unit":"ns"},"median_abs_dev":{"estimate":130358.29044734412,"lower_bound":20779.21519776201,"upper_bound":711754.2712513357,"unit":"ns"},"slope":{"estimate":6134353.346103896,"lower_bound":5973174.103603603,"upper_bound":6354742.7256711405,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/top_n_filtered_group_by/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_top_n_filtered_group_by_1000000","iteration_count":[17,34,51,68,85,102,119,136,153,170],"measured_values":[82365125.0,182798541.0,255316666.0,334692125.0,428338500.0,502938709.0,617395666.0,666919708.0,779334291.0,856690500.0],"unit":"ns","throughput":[],"typical":{"estimate":5034384.477310925,"lower_bound":4959462.670666887,"upper_bound":5101944.278840731,"unit":"ns"},"mean":{"estimate":5034469.962394957,"lower_bound":4950309.54964986,"upper_bound":5133224.451943277,"unit":"ns"},"median":{"estimate":5022742.803921569,"lower_bound":4917296.519607843,"upper_bound":5113777.37815126,"unit":"ns"},"median_abs_dev":{"estimate":142901.09252329334,"lower_bound":24512.813764811024,"upper_bound":245246.29712836107,"unit":"ns"},"slope":{"estimate":5034384.477310925,"lower_bound":4959462.670666887,"upper_bound":5101944.278840731,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"COMBO","benchmarks":["COMBO/combo/bloom_ore_order_limit/1000000","COMBO/combo/filtered_group_by/1000000","COMBO/combo/top_n_filtered_group_by/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO"} diff --git a/results/query/combo_rows_10000000.json b/results/query/combo_rows_10000000.json new file mode 100644 index 0000000..b907598 --- /dev/null +++ b/results/query/combo_rows_10000000.json @@ -0,0 +1,4 @@ +{"reason":"benchmark-complete","id":"COMBO/combo/bloom_ore_order_limit/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_bloom_ore_order_limit_10000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[618442584.0,634203000.0,632617959.0,623987500.0,638118125.0,617624458.0,626994083.0,620209750.0,623137541.0,619477750.0],"unit":"ns","throughput":[],"typical":{"estimate":208493758.3333333,"lower_bound":207159608.22666666,"upper_bound":209968911.49416667,"unit":"ns"},"mean":{"estimate":208493758.3333333,"lower_bound":207159608.22666666,"upper_bound":209968911.49416667,"unit":"ns"},"median":{"estimate":207854173.5,"lower_bound":206442055.6666667,"upper_bound":210872653.0,"unit":"ns"},"median_abs_dev":{"estimate":2274483.0593198463,"lower_bound":436666.7108476236,"upper_bound":3887541.946682319,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/filtered_group_by/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_filtered_group_by_10000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[124790417.0,247090292.0,380447750.0,540322333.0,668313000.0,774443709.0,891690416.0,1063415000.0,1220735709.0,1339746667.0],"unit":"ns","throughput":[],"typical":{"estimate":44193135.75757576,"lower_bound":43270939.158396944,"upper_bound":44760931.18505747,"unit":"ns"},"mean":{"estimate":43429726.74198413,"lower_bound":42537296.94476191,"upper_bound":44287222.871642865,"unit":"ns"},"median":{"estimate":43666804.41666667,"lower_bound":42029127.02380952,"upper_bound":44790530.54166667,"unit":"ns"},"median_abs_dev":{"estimate":1901740.4025123608,"lower_bound":258909.32447343954,"upper_bound":2314833.9061534847,"unit":"ns"},"slope":{"estimate":44193135.75757576,"lower_bound":43270939.158396944,"upper_bound":44760931.18505747,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"COMBO/combo/top_n_filtered_group_by/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO/combo_top_n_filtered_group_by_10000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[125427875.0,247546333.0,383149708.0,504254125.0,719146333.0,768212792.0,939495084.0,1047918416.0,1153029666.0,1275928791.0],"unit":"ns","throughput":[],"typical":{"estimate":43366547.53419913,"lower_bound":42608505.09330601,"upper_bound":44538606.52822581,"unit":"ns"},"mean":{"estimate":43191884.86261905,"lower_bound":42230489.852986105,"upper_bound":44453487.643728174,"unit":"ns"},"median":{"estimate":42625339.11111111,"lower_bound":42021177.083333336,"upper_bound":43721331.79365079,"unit":"ns"},"median_abs_dev":{"estimate":1052801.2630673759,"lower_bound":98305.76805472742,"upper_bound":2315922.1639508293,"unit":"ns"},"slope":{"estimate":43366547.53419913,"lower_bound":42608505.09330601,"upper_bound":44538606.52822581,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"COMBO","benchmarks":["COMBO/combo/bloom_ore_order_limit/10000000","COMBO/combo/filtered_group_by/10000000","COMBO/combo/top_n_filtered_group_by/10000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/COMBO"} diff --git a/results/query/exact_metadata_10000.json b/results/query/exact_metadata_10000.json new file mode 100644 index 0000000..c3e121d --- /dev/null +++ b/results/query/exact_metadata_10000.json @@ -0,0 +1,101 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405'::text)", + "Index Name": "string_encrypted_10000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } + ], + "id": "EXACT/exact/eql_cast/10000", + "indexes_used": [ + "string_encrypted_10000_hash_index" + ], + "parameters": [ + { + "hm": "5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405", + "i": { + "c": "value", + "t": "string_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_10000 WHERE value = $1 LIMIT 1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405'::text)", + "Index Name": "string_encrypted_10000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } + ], + "id": "EXACT/exact/eql_hash/10000", + "indexes_used": [ + "string_encrypted_10000_hash_index" + ], + "parameters": [ + { + "hm": "5488ee1b0cc520560b6cac5bcfc63439d219b24846747a3fed35772326388405", + "i": { + "c": "value", + "t": "string_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_10000 WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "rows_returned": 1 + } + ], + "target_rows": "10000" +} \ No newline at end of file diff --git a/results/query/exact_metadata_100000.json b/results/query/exact_metadata_100000.json new file mode 100644 index 0000000..56854ac --- /dev/null +++ b/results/query/exact_metadata_100000.json @@ -0,0 +1,101 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7'::text)", + "Index Name": "string_encrypted_100000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } + ], + "id": "EXACT/exact/eql_cast/100000", + "indexes_used": [ + "string_encrypted_100000_hash_index" + ], + "parameters": [ + { + "hm": "78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7", + "i": { + "c": "value", + "t": "string_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_100000 WHERE value = $1 LIMIT 1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7'::text)", + "Index Name": "string_encrypted_100000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Relation Name": "string_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + ], + "Startup Cost": 0.0, + "Total Cost": 8.27 + } + } + ], + "id": "EXACT/exact/eql_hash/100000", + "indexes_used": [ + "string_encrypted_100000_hash_index" + ], + "parameters": [ + { + "hm": "78ef439942d7046b495cad3df8afc1555af6aff90d1d287a5dd3f18dadfa6ef7", + "i": { + "c": "value", + "t": "string_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_100000 WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "rows_returned": 1 + } + ], + "target_rows": "100000" +} \ No newline at end of file diff --git a/results/query/exact_metadata_1000000.json b/results/query/exact_metadata_1000000.json new file mode 100644 index 0000000..3735ed4 --- /dev/null +++ b/results/query/exact_metadata_1000000.json @@ -0,0 +1,101 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f'::text)", + "Index Name": "string_encrypted_1000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "string_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 21105.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.22 + } + } + ], + "id": "EXACT/exact/eql_cast/1000000", + "indexes_used": [ + "string_encrypted_1000000_hash_index" + ], + "parameters": [ + { + "hm": "1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f", + "i": { + "c": "value", + "t": "string_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_1000000 WHERE value = $1 LIMIT 1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f'::text)", + "Index Name": "string_encrypted_1000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "string_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 21105.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.22 + } + } + ], + "id": "EXACT/exact/eql_hash/1000000", + "indexes_used": [ + "string_encrypted_1000000_hash_index" + ], + "parameters": [ + { + "hm": "1246c1084a30cdf8fad11d1b43ea7efa0966d7b8afed182d8041b6138a0cd67f", + "i": { + "c": "value", + "t": "string_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_1000000 WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "rows_returned": 1 + } + ], + "target_rows": "1000000" +} \ No newline at end of file diff --git a/results/query/exact_metadata_10000000.json b/results/query/exact_metadata_10000000.json new file mode 100644 index 0000000..0de26ef --- /dev/null +++ b/results/query/exact_metadata_10000000.json @@ -0,0 +1,101 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677'::text)", + "Index Name": "string_encrypted_10000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 8, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 38.14 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.77 + } + } + ], + "id": "EXACT/exact/eql_cast/10000000", + "indexes_used": [ + "string_encrypted_10000000_hash_index" + ], + "parameters": [ + { + "hm": "3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677", + "i": { + "c": "value", + "t": "string_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_10000000 WHERE value = $1 LIMIT 1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(((value).data ->> 'hm'::text) = '3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677'::text)", + "Index Name": "string_encrypted_10000000_hash_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 8, + "Plan Width": 36, + "Relation Name": "string_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.0, + "Total Cost": 38.14 + } + ], + "Startup Cost": 0.0, + "Total Cost": 4.77 + } + } + ], + "id": "EXACT/exact/eql_hash/10000000", + "indexes_used": [ + "string_encrypted_10000000_hash_index" + ], + "parameters": [ + { + "hm": "3ad65b2ad0d1cd146d576dffe73c17884b1c3d7004d17efc546d7d9d7a6e0677", + "i": { + "c": "value", + "t": "string_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id, value::jsonb FROM string_encrypted_10000000 WHERE eql_v2.hmac_256(value) = eql_v2.hmac_256($1::jsonb) LIMIT 1", + "rows_returned": 1 + } + ], + "target_rows": "10000000" +} \ No newline at end of file diff --git a/results/query/exact_rows_10000.json b/results/query/exact_rows_10000.json index 61a7c24..6da3388 100644 --- a/results/query/exact_rows_10000.json +++ b/results/query/exact_rows_10000.json @@ -1,5 +1,5 @@ -{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_10000","iteration_count":[208,416,624,832,1040,1248,1456,1664,1872,2080],"measured_values":[90136125.0,177061708.0,277471041.0,347643000.0,440986500.0,523136167.0,599694959.0,697944208.0,782574417.0,862956500.0],"unit":"ns","throughput":[],"typical":{"estimate":417896.44475524477,"lower_bound":415600.3899663456,"upper_bound":421721.40603252273,"unit":"ns"},"mean":{"estimate":422892.7089400183,"lower_bound":417792.3236950549,"upper_bound":429038.6276098901,"unit":"ns"},"median":{"estimate":419308.6229967949,"lower_bound":416462.4110576923,"upper_bound":428686.1177884615,"unit":"ns"},"median_abs_dev":{"estimate":6777.370769100684,"lower_bound":992.9541066504212,"upper_bound":14608.275450266608,"unit":"ns"},"slope":{"estimate":417896.44475524477,"lower_bound":415600.3899663456,"upper_bound":421721.40603252273,"unit":"ns"},"change":{"mean":{"estimate":-0.07175388180360132,"lower_bound":-0.09815735360157866,"upper_bound":-0.04219930201730728,"unit":"%"},"median":{"estimate":-0.09055110044831072,"lower_bound":-0.10480369121200861,"upper_bound":-0.04237911841429509,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_10000","iteration_count":[203,406,609,812,1015,1218,1421,1624,1827,2030],"measured_values":[94865791.0,176606584.0,258618416.0,334995709.0,419629459.0,517907875.0,603494042.0,699001333.0,782854416.0,835196125.0],"unit":"ns","throughput":[],"typical":{"estimate":422028.424796878,"lower_bound":415371.52842421154,"upper_bound":427960.9524024873,"unit":"ns"},"mean":{"estimate":427320.22540874965,"lower_bound":419085.9189514426,"upper_bound":437835.01490147784,"unit":"ns"},"median":{"estimate":424954.2210297912,"lower_bound":413428.0384236453,"upper_bound":431741.66502463055,"unit":"ns"},"median_abs_dev":{"estimate":11492.139572636332,"lower_bound":435.053277251628,"upper_bound":20900.81046672519,"unit":"ns"},"slope":{"estimate":422028.424796878,"lower_bound":415371.52842421154,"upper_bound":427960.9524024873,"unit":"ns"},"change":{"mean":{"estimate":-0.06496087032072162,"lower_bound":-0.12209036207440671,"upper_bound":-0.0002637463651535696,"unit":"%"},"median":{"estimate":-0.06552222647720707,"lower_bound":-0.15749868305123926,"upper_bound":0.03876544773814694,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_10000","iteration_count":[220,440,660,880,1100,1320,1540,1760,1980,2200],"measured_values":[88241833.0,188105542.0,273259291.0,401735875.0,463563625.0,546438709.0,611396375.0,738599541.0,790385250.0,886300625.0],"unit":"ns","throughput":[],"typical":{"estimate":409122.42174734356,"lower_bound":402560.0501243914,"upper_bound":420840.6348240469,"unit":"ns"},"mean":{"estimate":415326.7154518398,"lower_bound":405970.84054951294,"upper_bound":426802.02560213744,"unit":"ns"},"median":{"estimate":413998.9738636364,"lower_bound":401024.19507575757,"upper_bound":423585.7127840909,"unit":"ns"},"median_abs_dev":{"estimate":17816.9868150489,"lower_bound":2727.576798166732,"upper_bound":27514.93985815988,"unit":"ns"},"slope":{"estimate":409122.42174734356,"lower_bound":402560.0501243914,"upper_bound":420840.6348240469,"unit":"ns"},"change":{"mean":{"estimate":0.0016386131234420453,"lower_bound":-0.0447391621831066,"upper_bound":0.057122313778719534,"unit":"%"},"median":{"estimate":0.0007265270621481523,"lower_bound":-0.07397431236064733,"upper_bound":0.05272385660338408,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_10000","iteration_count":[224,448,672,896,1120,1344,1568,1792,2016,2240],"measured_values":[121678792.0,186398417.0,280387292.0,361523166.0,470885166.0,553291375.0,657253208.0,753239959.0,824946167.0,910833584.0],"unit":"ns","throughput":[],"typical":{"estimate":412980.6089633581,"lower_bound":408941.5526172377,"upper_bound":418886.1718322026,"unit":"ns"},"mean":{"estimate":426743.67810675316,"lower_bound":411016.9849541171,"upper_bound":453915.47152507177,"unit":"ns"},"median":{"estimate":416655.4445684524,"lower_bound":409148.6329613095,"upper_bound":420334.79854910716,"unit":"ns"},"median_abs_dev":{"estimate":6492.3451075503335,"lower_bound":1011.8615636541508,"upper_bound":15718.613403383028,"unit":"ns"},"slope":{"estimate":412980.6089633581,"lower_bound":408941.5526172377,"upper_bound":418886.1718322026,"unit":"ns"},"change":{"mean":{"estimate":0.06507270634468143,"lower_bound":0.0004891838434652832,"upper_bound":0.1487705487781515,"unit":"%"},"median":{"estimate":0.0503621893005759,"lower_bound":-0.007378055546500728,"upper_bound":0.09066126338326375,"unit":"%"},"change":"NoChange"}} -{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact_decrypt/eql_hash/1000000","EXACT/exact/eql_hash/1000000","EXACT/exact_decrypt/eql_hash/100000","EXACT/exact_decrypt/eql_cast/100000","EXACT/exact/eql_cast/100000","EXACT/exact_decrypt/eql_cast/1000000","EXACT/exact/eql_hash/100000","EXACT/exact/eql_cast/1000000","EXACT/exact/eql_cast/10000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact/eql_hash/10000","EXACT/exact_decrypt/eql_hash/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_10000","iteration_count":[181,362,543,724,905,1086,1267,1448,1629,1810],"measured_values":[84221917.0,167678167.0,241057417.0,335311166.0,407649583.0,734987666.0,621671917.0,737714000.0,884550667.0,845484166.0],"unit":"ns","throughput":[],"typical":{"estimate":510890.179507785,"lower_bound":472225.38172939647,"upper_bound":560943.6241640012,"unit":"ns"},"mean":{"estimate":497306.89125317906,"lower_bound":464330.17740239424,"upper_bound":543635.6151635535,"unit":"ns"},"median":{"estimate":466216.391160221,"lower_bound":456820.4422651933,"upper_bound":516833.3737612909,"unit":"ns"},"median_abs_dev":{"estimate":28210.128678175657,"lower_bound":1660.4198199691891,"upper_bound":70194.01106146834,"unit":"ns"},"slope":{"estimate":510890.179507785,"lower_bound":472225.38172939647,"upper_bound":560943.6241640012,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[107866209.0,204930500.0,308735541.0,440848584.0,498388958.0,596653667.0,704660750.0,782272459.0,922933541.0,1015660833.0],"unit":"ns","throughput":[],"typical":{"estimate":25281175.37727273,"lower_bound":24873395.86809363,"upper_bound":25706109.67699455,"unit":"ns"},"mean":{"estimate":25628491.368978176,"lower_bound":25107977.36141791,"upper_bound":26228814.33477902,"unit":"ns"},"median":{"estimate":25503916.6625,"lower_bound":24919447.9,"upper_bound":26301797.527777776,"unit":"ns"},"median_abs_dev":{"estimate":683426.7471692524,"lower_bound":87293.17606523597,"upper_bound":1561165.0157462815,"unit":"ns"},"slope":{"estimate":25281175.37727273,"lower_bound":24873395.86809363,"upper_bound":25706109.67699455,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_10000","iteration_count":[201,402,603,804,1005,1206,1407,1608,1809,2010],"measured_values":[90979875.0,170016000.0,226042084.0,297799209.0,393813000.0,581808917.0,621645584.0,732330417.0,829657208.0,905565583.0],"unit":"ns","throughput":[],"typical":{"estimate":445732.20379918587,"lower_bound":424597.83707463904,"upper_bound":457160.23966923374,"unit":"ns"},"mean":{"estimate":430151.39207158645,"lower_bound":406913.7116362632,"upper_bound":451769.7522120647,"unit":"ns"},"median":{"estimate":446176.79179104476,"lower_bound":391853.7313432836,"upper_bound":455631.8637368712,"unit":"ns"},"median_abs_dev":{"estimate":26466.010967613678,"lower_bound":4141.153436554465,"upper_bound":62095.0224922862,"unit":"ns"},"slope":{"estimate":445732.20379918587,"lower_bound":424597.83707463904,"upper_bound":457160.23966923374,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[111805750.0,203129333.0,297537583.0,410550875.0,506844791.0,592872875.0,702377917.0,792018916.0,902669917.0,1009260917.0],"unit":"ns","throughput":[],"typical":{"estimate":25073881.194805194,"lower_bound":24898909.046296295,"upper_bound":25239438.456043955,"unit":"ns"},"mean":{"estimate":25398331.242242064,"lower_bound":24973041.446724705,"upper_bound":26030453.675459825,"unit":"ns"},"median":{"estimate":25158224.26607143,"lower_bound":24794798.583333332,"upper_bound":25500834.61875,"unit":"ns"},"median_abs_dev":{"estimate":442087.6214388767,"lower_bound":70504.54754829592,"upper_bound":762332.7183958908,"unit":"ns"},"slope":{"estimate":25073881.194805194,"lower_bound":24898909.046296295,"upper_bound":25239438.456043955,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact/eql_cast/10000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact/eql_hash/10000","EXACT/exact_decrypt/eql_hash/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} diff --git a/results/query/exact_rows_100000.json b/results/query/exact_rows_100000.json index efdc988..9b31ca1 100644 --- a/results/query/exact_rows_100000.json +++ b/results/query/exact_rows_100000.json @@ -1,5 +1,5 @@ -{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_100000","iteration_count":[207,414,621,828,1035,1242,1449,1656,1863,2070],"measured_values":[91542500.0,183934750.0,265712959.0,345890166.0,455921125.0,511696375.0,657076625.0,711966167.0,787200416.0,858054791.0],"unit":"ns","throughput":[],"typical":{"estimate":426005.55594453856,"lower_bound":417845.4233434723,"upper_bound":438380.05830077,"unit":"ns"},"mean":{"estimate":430510.3425843494,"lower_bound":422434.3259928878,"upper_bound":438827.946226248,"unit":"ns"},"median":{"estimate":428905.21064814815,"lower_bound":417741.7463768116,"upper_bound":442395.16908212565,"unit":"ns"},"median_abs_dev":{"estimate":18478.66693745741,"lower_bound":3042.4422719519766,"upper_bound":22924.348979323884,"unit":"ns"},"slope":{"estimate":426005.55594453856,"lower_bound":417845.4233434723,"upper_bound":438380.05830077,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_100000","iteration_count":[210,420,630,840,1050,1260,1470,1680,1890,2100],"measured_values":[94938042.0,190256542.0,266570291.0,361908125.0,452238167.0,553183750.0,682493167.0,710323167.0,838613208.0,929865250.0],"unit":"ns","throughput":[],"typical":{"estimate":440436.57032776746,"lower_bound":430631.182728774,"upper_bound":449267.187456446,"unit":"ns"},"mean":{"estimate":440238.201451814,"lower_bound":432495.62688095245,"upper_bound":448409.9439149659,"unit":"ns"},"median":{"estimate":440913.84920634923,"lower_bound":426985.2259920635,"upper_bound":452085.9142857143,"unit":"ns"},"median_abs_dev":{"estimate":15851.142076585964,"lower_bound":1360.6055291777518,"upper_bound":24289.08371354447,"unit":"ns"},"slope":{"estimate":440436.57032776746,"lower_bound":430631.182728774,"upper_bound":449267.187456446,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_100000","iteration_count":[219,438,657,876,1095,1314,1533,1752,1971,2190],"measured_values":[85526083.0,170157291.0,256196625.0,339009625.0,458985667.0,524873417.0,618550875.0,688167709.0,826586916.0,898265208.0],"unit":"ns","throughput":[],"typical":{"estimate":406235.78245863726,"lower_bound":396694.73313514306,"upper_bound":413200.4980410325,"unit":"ns"},"mean":{"estimate":400039.69488095236,"lower_bound":393125.9105620787,"upper_bound":407584.60260112246,"unit":"ns"},"median":{"estimate":396118.41657153727,"lower_bound":389508.5125570776,"upper_bound":411327.7262883235,"unit":"ns"},"median_abs_dev":{"estimate":11122.090000488626,"lower_bound":1675.136989952156,"upper_bound":21227.075703144084,"unit":"ns"},"slope":{"estimate":406235.78245863726,"lower_bound":396694.73313514306,"upper_bound":413200.4980410325,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_100000","iteration_count":[219,438,657,876,1095,1314,1533,1752,1971,2190],"measured_values":[84802416.0,169951041.0,254047416.0,375829125.0,474532917.0,553088083.0,645717916.0,765987667.0,782828875.0,882309375.0],"unit":"ns","throughput":[],"typical":{"estimate":413898.3182351895,"lower_bound":403438.7811022991,"upper_bound":428497.2556960362,"unit":"ns"},"mean":{"estimate":410370.5109014641,"lower_bound":398683.6080792926,"upper_bound":422217.8294643717,"unit":"ns"},"median":{"estimate":411900.1933028919,"lower_bound":388016.0753424658,"upper_bound":429028.6815068493,"unit":"ns"},"median_abs_dev":{"estimate":28608.01886034816,"lower_bound":1397.9513005239087,"upper_bound":33615.967109909594,"unit":"ns"},"slope":{"estimate":413898.3182351895,"lower_bound":403438.7811022991,"upper_bound":428497.2556960362,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_100000","iteration_count":[191,382,573,764,955,1146,1337,1528,1719,1910],"measured_values":[87113125.0,172180208.0,280037542.0,354942500.0,582090625.0,506644000.0,603593792.0,707025667.0,999070708.0,917511041.0],"unit":"ns","throughput":[],"typical":{"estimate":498943.1148976678,"lower_bound":459768.81436530733,"upper_bound":545621.3566836768,"unit":"ns"},"mean":{"estimate":488747.82538789156,"lower_bound":458447.5566492147,"upper_bound":527048.7795173066,"unit":"ns"},"median":{"estimate":463648.7784685864,"lower_bound":451453.8459237098,"upper_bound":530782.6192262943,"unit":"ns"},"median_abs_dev":{"estimate":21971.200521608607,"lower_bound":4504.4708357364625,"upper_bound":74738.37832201159,"unit":"ns"},"slope":{"estimate":498943.1148976678,"lower_bound":459768.81436530733,"upper_bound":545621.3566836768,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[102038500.0,196967166.0,321210333.0,424483458.0,504357917.0,606321792.0,699482292.0,824788917.0,917215833.0,1002758125.0],"unit":"ns","throughput":[],"typical":{"estimate":25386018.913636364,"lower_bound":25153753.61452514,"upper_bound":25710407.29257642,"unit":"ns"},"mean":{"estimate":25521290.32681548,"lower_bound":25151285.864880953,"upper_bound":25941423.948214285,"unit":"ns"},"median":{"estimate":25370812.791666664,"lower_bound":25068953.125,"upper_bound":26019920.5625,"unit":"ns"},"median_abs_dev":{"estimate":512358.40356631594,"lower_bound":144149.39627833664,"upper_bound":1120196.8962812796,"unit":"ns"},"slope":{"estimate":25386018.913636364,"lower_bound":25153753.61452514,"upper_bound":25710407.29257642,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_100000","iteration_count":[207,414,621,828,1035,1242,1449,1656,1863,2070],"measured_values":[86892791.0,167035459.0,273098041.0,351665334.0,401137333.0,579410917.0,732051167.0,759322250.0,803093792.0,905393250.0],"unit":"ns","throughput":[],"typical":{"estimate":446825.8251082251,"lower_bound":427990.55209591513,"upper_bound":469515.6766505636,"unit":"ns"},"mean":{"estimate":437401.6787673491,"lower_bound":418724.4196622383,"upper_bound":457852.2273149203,"unit":"ns"},"median":{"estimate":434231.80810520664,"lower_bound":414091.93961352657,"upper_bound":458527.9287439613,"unit":"ns"},"median_abs_dev":{"estimate":28729.81602291482,"lower_bound":6446.218549163859,"upper_bound":55642.05251493388,"unit":"ns"},"slope":{"estimate":446825.8251082251,"lower_bound":427990.55209591513,"upper_bound":469515.6766505636,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[99406958.0,199434791.0,328383166.0,404310000.0,516886834.0,651317458.0,711320417.0,796263916.0,934359792.0,1008086833.0],"unit":"ns","throughput":[],"typical":{"estimate":25605497.18246753,"lower_bound":25210209.80862069,"upper_bound":26190605.70658468,"unit":"ns"},"mean":{"estimate":25684245.37988095,"lower_bound":25192009.923455358,"upper_bound":26256774.059446424,"unit":"ns"},"median":{"estimate":25336837.80357143,"lower_bound":24929348.875,"upper_bound":26491284.558333334,"unit":"ns"},"median_abs_dev":{"estimate":695849.9447836948,"lower_bound":80888.61598894,"upper_bound":1472358.259545416,"unit":"ns"},"slope":{"estimate":25605497.18246753,"lower_bound":25210209.80862069,"upper_bound":26190605.70658468,"unit":"ns"},"change":null} {"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact/eql_cast/100000","EXACT/exact_decrypt/eql_cast/100000","EXACT/exact/eql_hash/100000","EXACT/exact_decrypt/eql_hash/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} diff --git a/results/query/exact_rows_1000000.json b/results/query/exact_rows_1000000.json index 0532416..9ea6413 100644 --- a/results/query/exact_rows_1000000.json +++ b/results/query/exact_rows_1000000.json @@ -1,5 +1,5 @@ -{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_1000000","iteration_count":[114,228,342,456,570,684,798,912,1026,1140],"measured_values":[111220417.0,207633875.0,154657333.0,217299042.0,255996375.0,293648708.0,715914417.0,649318125.0,898715584.0,882423125.0],"unit":"ns","throughput":[],"typical":{"estimate":729554.5199817726,"lower_bound":579266.9333773884,"upper_bound":816916.6739211186,"unit":"ns"},"mean":{"estimate":695257.1395137148,"lower_bound":564730.4524562274,"upper_bound":825486.262810803,"unit":"ns"},"median":{"estimate":743013.5005482456,"lower_bound":452214.4239766082,"upper_bound":897135.8609022556,"unit":"ns"},"median_abs_dev":{"estimate":296716.8708443936,"lower_bound":19274.855251662575,"upper_bound":344858.96958049,"unit":"ns"},"slope":{"estimate":729554.5199817726,"lower_bound":579266.9333773884,"upper_bound":816916.6739211186,"unit":"ns"},"change":{"mean":{"estimate":-0.9999132211769995,"lower_bound":-0.999929754403837,"upper_bound":-0.9998948765867203,"unit":"%"},"median":{"estimate":-0.9999072405302023,"lower_bound":-0.9999435681534321,"upper_bound":-0.9998879986042203,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_1000000","iteration_count":[171,342,513,684,855,1026,1197,1368,1539,1710],"measured_values":[70718208.0,143040250.0,276062417.0,304802917.0,472662666.0,521332667.0,718801000.0,620982375.0,664433083.0,943154458.0],"unit":"ns","throughput":[],"typical":{"estimate":505907.42440950865,"lower_bound":456378.8420825437,"upper_bound":554045.3905741365,"unit":"ns"},"mean":{"estimate":491421.7408648937,"lower_bound":453044.06153537205,"upper_bound":531229.7601738896,"unit":"ns"},"median":{"estimate":481027.99622319685,"lower_bound":431730.3983105913,"upper_bound":551552.3146198831,"unit":"ns"},"median_abs_dev":{"estimate":88872.24741752387,"lower_bound":10888.558990666006,"upper_bound":108650.56284628624,"unit":"ns"},"slope":{"estimate":505907.42440950865,"lower_bound":456378.8420825437,"upper_bound":554045.3905741365,"unit":"ns"},"change":{"mean":{"estimate":-0.9999386627314146,"lower_bound":-0.9999432154424407,"upper_bound":-0.999933768635663,"unit":"%"},"median":{"estimate":-0.999939996075808,"lower_bound":-0.9999461455085877,"upper_bound":-0.9999311298078122,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_1000000","iteration_count":[228,456,684,912,1140,1368,1596,1824,2052,2280],"measured_values":[91025042.0,181228000.0,285367834.0,370343709.0,478358458.0,555475708.0,754519250.0,765128375.0,838837458.0,966803209.0],"unit":"ns","throughput":[],"typical":{"estimate":423055.78582820686,"lower_bound":410439.87234250567,"upper_bound":440559.9737923063,"unit":"ns"},"mean":{"estimate":417066.9082941729,"lower_bound":406657.7325767544,"upper_bound":431331.22623951803,"unit":"ns"},"median":{"estimate":412997.30994152045,"lower_bound":402655.63432017545,"upper_bound":421757.38547149126,"unit":"ns"},"median_abs_dev":{"estimate":10279.234370906175,"lower_bound":1785.2333090075356,"upper_bound":23366.55779755094,"unit":"ns"},"slope":{"estimate":423055.78582820686,"lower_bound":410439.87234250567,"upper_bound":440559.9737923063,"unit":"ns"},"change":{"mean":{"estimate":0.039912836206747127,"lower_bound":0.010669592681075332,"upper_bound":0.07599697044991253,"unit":"%"},"median":{"estimate":0.03764357790878403,"lower_bound":0.002651457789572431,"upper_bound":0.06061441074249396,"unit":"%"},"change":"Regressed"}} -{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_1000000","iteration_count":[228,456,684,912,1140,1368,1596,1824,2052,2280],"measured_values":[91911416.0,178735167.0,268568042.0,351820625.0,456181459.0,557669959.0,663052625.0,733402208.0,829428000.0,916695541.0],"unit":"ns","throughput":[],"typical":{"estimate":403619.1487126908,"lower_bound":399618.9344030809,"upper_bound":407751.88488100877,"unit":"ns"},"mean":{"estimate":400510.2726848371,"lower_bound":395485.11774853803,"upper_bound":405478.14408317674,"unit":"ns"},"median":{"estimate":402071.99583333335,"lower_bound":392643.33625730994,"upper_bound":405386.86220760236,"unit":"ns"},"median_abs_dev":{"estimate":5718.510781458577,"lower_bound":803.8899822193017,"upper_bound":15682.194641541606,"unit":"ns"},"slope":{"estimate":403619.1487126908,"lower_bound":399618.9344030809,"upper_bound":407751.88488100877,"unit":"ns"},"change":{"mean":{"estimate":-0.020692905391870742,"lower_bound":-0.047168489790024665,"upper_bound":0.002637677202577882,"unit":"%"},"median":{"estimate":-0.001774227767842751,"lower_bound":-0.04121604849202143,"upper_bound":0.013739706487771971,"unit":"%"},"change":"NoChange"}} -{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact_decrypt/eql_hash/10000","EXACT/exact_decrypt/eql_hash/100000","EXACT/exact_decrypt/eql_cast/10000","EXACT/exact_decrypt/eql_cast/100000","EXACT/exact/eql_cast/100000","EXACT/exact/eql_cast/10000","EXACT/exact/eql_hash/100000","EXACT/exact/eql_hash/10000","EXACT/exact/eql_cast/1000000","EXACT/exact_decrypt/eql_cast/1000000","EXACT/exact/eql_hash/1000000","EXACT/exact_decrypt/eql_hash/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_1000000","iteration_count":[199,398,597,796,995,1194,1393,1592,1791,1990],"measured_values":[89321083.0,182293041.0,271971042.0,353156416.0,458482375.0,538532458.0,640962917.0,689351791.0,830115250.0,901595917.0],"unit":"ns","throughput":[],"typical":{"estimate":452843.48684983357,"lower_bound":443606.210711452,"upper_bound":459988.2337694218,"unit":"ns"},"mean":{"estimate":452761.47262283636,"lower_bound":447006.8483598548,"upper_bound":457710.2243160245,"unit":"ns"},"median":{"estimate":454313.0796482412,"lower_bound":447348.0242881072,"upper_bound":460131.3115577889,"unit":"ns"},"median_abs_dev":{"estimate":8363.085692731567,"lower_bound":2048.6495658904787,"upper_bound":14699.061530329289,"unit":"ns"},"slope":{"estimate":452843.48684983357,"lower_bound":443606.210711452,"upper_bound":459988.2337694218,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[106246125.0,206738958.0,302856542.0,393445083.0,511486750.0,626236292.0,719969708.0,800036750.0,940479583.0,991864958.0],"unit":"ns","throughput":[],"typical":{"estimate":25415567.06753247,"lower_bound":24984630.432091348,"upper_bound":25909403.70018797,"unit":"ns"},"mean":{"estimate":25553518.929325394,"lower_bound":25176889.93203274,"upper_bound":25922428.54613095,"unit":"ns"},"median":{"estimate":25643770.67857143,"lower_bound":25001148.4375,"upper_bound":26093178.833333332,"unit":"ns"},"median_abs_dev":{"estimate":689461.1288012837,"lower_bound":198692.30339750648,"upper_bound":1066228.8209706545,"unit":"ns"},"slope":{"estimate":25415567.06753247,"lower_bound":24984630.432091348,"upper_bound":25909403.70018797,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_1000000","iteration_count":[202,404,606,808,1010,1212,1414,1616,1818,2020],"measured_values":[86514416.0,179933625.0,269747584.0,362459208.0,465019375.0,552870041.0,654404875.0,722466750.0,855492750.0,926324750.0],"unit":"ns","throughput":[],"typical":{"estimate":458673.37978655007,"lower_bound":451532.95370012266,"upper_bound":464723.9372226851,"unit":"ns"},"mean":{"estimate":452298.39263908536,"lower_bound":445029.3945833333,"upper_bound":459070.2850483263,"unit":"ns"},"median":{"estimate":452375.76443894394,"lower_bound":445380.2599009901,"upper_bound":460690.31117397454,"unit":"ns"},"median_abs_dev":{"estimate":10558.515532845951,"lower_bound":1627.31341331241,"upper_bound":20927.871125980775,"unit":"ns"},"slope":{"estimate":458673.37978655007,"lower_bound":451532.95370012266,"upper_bound":464723.9372226851,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[98064041.0,203157083.0,314924875.0,415932083.0,494401083.0,616274792.0,730634875.0,805127125.0,936487125.0,1007513667.0],"unit":"ns","throughput":[],"typical":{"estimate":25546439.773376625,"lower_bound":25224505.440615837,"upper_bound":25923619.53918639,"unit":"ns"},"mean":{"estimate":25500400.91389881,"lower_bound":25143614.88240476,"upper_bound":25842179.129061755,"unit":"ns"},"median":{"estimate":25536375.854166664,"lower_bound":24953947.9125,"upper_bound":26044928.933035716,"unit":"ns"},"median_abs_dev":{"estimate":694253.1824057959,"lower_bound":86082.3887342325,"upper_bound":1018582.1561465533,"unit":"ns"},"slope":{"estimate":25546439.773376625,"lower_bound":25224505.440615837,"upper_bound":25923619.53918639,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact/eql_cast/1000000","EXACT/exact_decrypt/eql_cast/1000000","EXACT/exact/eql_hash/1000000","EXACT/exact_decrypt/eql_hash/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} diff --git a/results/query/exact_rows_10000000.json b/results/query/exact_rows_10000000.json new file mode 100644 index 0000000..5bc97fa --- /dev/null +++ b/results/query/exact_rows_10000000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"EXACT/exact/eql_cast/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_cast_10000000","iteration_count":[181,362,543,724,905,1086,1267,1448,1629,1810],"measured_values":[82866000.0,191552125.0,254501083.0,352039333.0,414966875.0,503185334.0,572650875.0,683553292.0,741485750.0,818798583.0],"unit":"ns","throughput":[],"typical":{"estimate":460212.6318576451,"lower_bound":454969.0425511292,"upper_bound":469564.0473257318,"unit":"ns"},"mean":{"estimate":469536.8953753399,"lower_bound":458174.8203534596,"upper_bound":484885.0370450759,"unit":"ns"},"median":{"estimate":460932.58931860037,"lower_bound":455099.05607734807,"upper_bound":477468.3082412523,"unit":"ns"},"median_abs_dev":{"estimate":12097.671893013432,"lower_bound":2482.205918178794,"upper_bound":25105.803037349167,"unit":"ns"},"slope":{"estimate":460212.6318576451,"lower_bound":454969.0425511292,"upper_bound":469564.0473257318,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_cast/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_cast_10000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[101999167.0,193049250.0,301860833.0,414573209.0,523072000.0,609719625.0,742071042.0,826884458.0,938018625.0,1026742708.0],"unit":"ns","throughput":[],"typical":{"estimate":25873258.711038962,"lower_bound":25637296.973765418,"upper_bound":26123515.57210203,"unit":"ns"},"mean":{"estimate":25632274.449761905,"lower_bound":25211082.237014882,"upper_bound":25983738.682440475,"unit":"ns"},"median":{"estimate":25754353.50625,"lower_bound":25327430.583333336,"upper_bound":26056072.916666668,"unit":"ns"},"median_abs_dev":{"estimate":482651.92736871634,"lower_bound":144593.6511829477,"upper_bound":967319.9744891385,"unit":"ns"},"slope":{"estimate":25873258.711038962,"lower_bound":25637296.973765418,"upper_bound":26123515.57210203,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact/eql_hash/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_eql_hash_10000000","iteration_count":[209,418,627,836,1045,1254,1463,1672,1881,2090],"measured_values":[91735208.0,198276709.0,321772375.0,373703833.0,451170000.0,553675459.0,684482875.0,750817709.0,827705458.0,936223833.0],"unit":"ns","throughput":[],"typical":{"estimate":449087.59194680915,"lower_bound":442614.8440619411,"upper_bound":458711.5213431822,"unit":"ns"},"mean":{"estimate":455165.24408768135,"lower_bound":442887.88466440246,"upper_bound":470920.307136449,"unit":"ns"},"median":{"estimate":447484.0706937799,"lower_bound":440034.7995746943,"upper_bound":467862.52563226246,"unit":"ns"},"median_abs_dev":{"estimate":11867.398561313177,"lower_bound":1511.880879797478,"upper_bound":33465.186034283244,"unit":"ns"},"slope":{"estimate":449087.59194680915,"lower_bound":442614.8440619411,"upper_bound":458711.5213431822,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"EXACT/exact_decrypt/eql_hash/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT/exact_decrypt_eql_hash_10000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[115502583.0,195440750.0,303108083.0,404110500.0,524869625.0,600707584.0,711481375.0,834392292.0,906680250.0,1015706792.0],"unit":"ns","throughput":[],"typical":{"estimate":25476261.0987013,"lower_bound":25232946.600550964,"upper_bound":25801007.389657825,"unit":"ns"},"mean":{"estimate":25715765.71154762,"lower_bound":25131077.069285713,"upper_bound":26524888.454166666,"unit":"ns"},"median":{"estimate":25325838.358333334,"lower_bound":25143194.458333336,"upper_bound":26074759.125,"unit":"ns"},"median_abs_dev":{"estimate":323674.96226862125,"lower_bound":54444.34510842334,"upper_bound":1326473.708565382,"unit":"ns"},"slope":{"estimate":25476261.0987013,"lower_bound":25232946.600550964,"upper_bound":25801007.389657825,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"EXACT","benchmarks":["EXACT/exact/eql_cast/10000000","EXACT/exact_decrypt/eql_cast/10000000","EXACT/exact/eql_hash/10000000","EXACT/exact_decrypt/eql_hash/10000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/EXACT"} diff --git a/results/query/group_by_metadata_10000.json b/results/query/group_by_metadata_10000.json new file mode 100644 index 0000000..0ab3c7f --- /dev/null +++ b/results/query/group_by_metadata_10000.json @@ -0,0 +1,247 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_10000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 36, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 580.0 + } + ], + "Startup Cost": 605.0, + "Strategy": "Hashed", + "Total Cost": 608.12 + } + ], + "Startup Cost": 611.25, + "Strategy": "Plain", + "Total Cost": 611.26 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_encrypted/10000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_encrypted_10000 GROUP BY eql_v2.hmac_256(value)) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 12, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000", + "Startup Cost": 0.0, + "Total Cost": 155.0 + } + ], + "Startup Cost": 180.0, + "Strategy": "Hashed", + "Total Cost": 182.5 + } + ], + "Startup Cost": 185.62, + "Strategy": "Plain", + "Total Cost": 185.63 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_plaintext/10000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_plaintext_10000 GROUP BY value) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 580.0 + } + ], + "Startup Cost": 630.0, + "Strategy": "Hashed", + "Total Cost": 633.12 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 638.53, + "Total Cost": 639.15 + } + ], + "Startup Cost": 638.53, + "Total Cost": 638.55 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_encrypted/10000", + "indexes_used": [], + "parameters": [], + "query": "SELECT eql_v2.hmac_256(value), count(*) FROM category_encrypted_10000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 10000, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000", + "Startup Cost": 0.0, + "Total Cost": 155.0 + } + ], + "Startup Cost": 205.0, + "Strategy": "Hashed", + "Total Cost": 207.5 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 212.9, + "Total Cost": 213.53 + } + ], + "Startup Cost": 212.9, + "Total Cost": 212.93 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_plaintext/10000", + "indexes_used": [], + "parameters": [], + "query": "SELECT value, count(*) FROM category_plaintext_10000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "10000" +} \ No newline at end of file diff --git a/results/query/group_by_metadata_100000.json b/results/query/group_by_metadata_100000.json new file mode 100644 index 0000000..1d322e2 --- /dev/null +++ b/results/query/group_by_metadata_100000.json @@ -0,0 +1,247 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_100000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 36, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 32, + "Relation Name": "category_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 5796.0 + } + ], + "Startup Cost": 6046.0, + "Strategy": "Hashed", + "Total Cost": 6049.12 + } + ], + "Startup Cost": 6052.25, + "Strategy": "Plain", + "Total Cost": 6052.26 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_encrypted/100000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_encrypted_100000 GROUP BY eql_v2.hmac_256(value)) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_100000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 12, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 8, + "Relation Name": "category_plaintext_100000", + "Startup Cost": 0.0, + "Total Cost": 1541.0 + } + ], + "Startup Cost": 1791.0, + "Strategy": "Hashed", + "Total Cost": 1793.5 + } + ], + "Startup Cost": 1796.62, + "Strategy": "Plain", + "Total Cost": 1796.63 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_plaintext/100000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_plaintext_100000 GROUP BY value) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 32, + "Relation Name": "category_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 5796.0 + } + ], + "Startup Cost": 6296.0, + "Strategy": "Hashed", + "Total Cost": 6299.12 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 6304.53, + "Total Cost": 6305.15 + } + ], + "Startup Cost": 6304.53, + "Total Cost": 6304.55 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_encrypted/100000", + "indexes_used": [], + "parameters": [], + "query": "SELECT eql_v2.hmac_256(value), count(*) FROM category_encrypted_100000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Simple", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_100000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 100000, + "Plan Width": 8, + "Relation Name": "category_plaintext_100000", + "Startup Cost": 0.0, + "Total Cost": 1541.0 + } + ], + "Startup Cost": 2041.0, + "Strategy": "Hashed", + "Total Cost": 2043.5 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 2048.9, + "Total Cost": 2049.53 + } + ], + "Startup Cost": 2048.9, + "Total Cost": 2048.93 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_plaintext/100000", + "indexes_used": [], + "parameters": [], + "query": "SELECT value, count(*) FROM category_plaintext_100000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "100000" +} \ No newline at end of file diff --git a/results/query/group_by_metadata_1000000.json b/results/query/group_by_metadata_1000000.json new file mode 100644 index 0000000..3f11bb0 --- /dev/null +++ b/results/query/group_by_metadata_1000000.json @@ -0,0 +1,423 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 32, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416665, + "Plan Width": 32, + "Relation Name": "category_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 50663.31 + } + ], + "Startup Cost": 51704.97, + "Strategy": "Hashed", + "Total Cost": 51708.1 + } + ], + "Sort Key": [ + "((((category_encrypted_1000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 51718.05, + "Total Cost": 51718.68 + } + ], + "Startup Cost": 52718.08, + "Total Cost": 52776.41, + "Workers Planned": 2 + } + ], + "Startup Cost": 52718.08, + "Total Cost": 52778.29 + } + ], + "Startup Cost": 52781.41, + "Strategy": "Plain", + "Total Cost": 52781.42 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_encrypted/1000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_encrypted_1000000 GROUP BY eql_v2.hmac_256(value)) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_1000000.value" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 12, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_1000000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 8, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416667, + "Plan Width": 8, + "Relation Name": "category_plaintext_1000000", + "Startup Cost": 0.0, + "Total Cost": 9572.67 + } + ], + "Startup Cost": 10614.33, + "Strategy": "Hashed", + "Total Cost": 10616.83 + } + ], + "Sort Key": [ + "category_plaintext_1000000.value" + ], + "Startup Cost": 10626.79, + "Total Cost": 10627.42 + } + ], + "Startup Cost": 11626.82, + "Total Cost": 11685.15, + "Workers Planned": 2 + } + ], + "Startup Cost": 11626.82, + "Total Cost": 11686.4 + } + ], + "Startup Cost": 11689.53, + "Strategy": "Plain", + "Total Cost": 11689.54 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_plaintext/1000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_plaintext_1000000 GROUP BY value) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416665, + "Plan Width": 32, + "Relation Name": "category_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 50663.31 + } + ], + "Startup Cost": 52746.63, + "Strategy": "Hashed", + "Total Cost": 52749.76 + } + ], + "Sort Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 52759.72, + "Total Cost": 52760.34 + } + ], + "Startup Cost": 53759.74, + "Total Cost": 53818.08, + "Workers Planned": 2 + } + ], + "Startup Cost": 53759.74, + "Strategy": "Sorted", + "Total Cost": 53823.7 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 53829.1, + "Total Cost": 53829.73 + } + ], + "Startup Cost": 53829.1, + "Total Cost": 53829.13 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_encrypted/1000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT eql_v2.hmac_256(value), count(*) FROM category_encrypted_1000000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_1000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 416667, + "Plan Width": 8, + "Relation Name": "category_plaintext_1000000", + "Startup Cost": 0.0, + "Total Cost": 9572.67 + } + ], + "Startup Cost": 11656.0, + "Strategy": "Hashed", + "Total Cost": 11658.5 + } + ], + "Sort Key": [ + "value" + ], + "Startup Cost": 11668.46, + "Total Cost": 11669.08 + } + ], + "Startup Cost": 12668.48, + "Total Cost": 12726.82, + "Workers Planned": 2 + } + ], + "Startup Cost": 12668.48, + "Strategy": "Sorted", + "Total Cost": 12731.82 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 12737.22, + "Total Cost": 12737.85 + } + ], + "Startup Cost": 12737.22, + "Total Cost": 12737.25 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_plaintext/1000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT value, count(*) FROM category_plaintext_1000000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "1000000" +} \ No newline at end of file diff --git a/results/query/group_by_metadata_10000000.json b/results/query/group_by_metadata_10000000.json new file mode 100644 index 0000000..e82a72c --- /dev/null +++ b/results/query/group_by_metadata_10000000.json @@ -0,0 +1,459 @@ +{ + "scenarios": [ + { + "explain": [ + { + "JIT": { + "Functions": 8, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": true, + "Optimization": true + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 32, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 32, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166667, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 506629.33 + } + ], + "Startup Cost": 517046.0, + "Strategy": "Hashed", + "Total Cost": 517049.13 + } + ], + "Sort Key": [ + "((((category_encrypted_10000000.value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 517059.08, + "Total Cost": 517059.71 + } + ], + "Startup Cost": 518059.11, + "Total Cost": 518117.45, + "Workers Planned": 2 + } + ], + "Startup Cost": 518059.11, + "Total Cost": 518119.32 + } + ], + "Startup Cost": 518122.45, + "Strategy": "Plain", + "Total Cost": 518122.46 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_encrypted/10000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_encrypted_10000000 GROUP BY eql_v2.hmac_256(value)) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000000.value" + ], + "Node Type": "Group", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 12, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "category_plaintext_10000000.value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 8, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166608, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000000", + "Startup Cost": 0.0, + "Total Cost": 95721.08 + } + ], + "Startup Cost": 106137.6, + "Strategy": "Hashed", + "Total Cost": 106140.1 + } + ], + "Sort Key": [ + "category_plaintext_10000000.value" + ], + "Startup Cost": 106150.06, + "Total Cost": 106150.69 + } + ], + "Startup Cost": 107150.08, + "Total Cost": 107208.42, + "Workers Planned": 2 + } + ], + "Startup Cost": 107150.08, + "Total Cost": 107209.67 + } + ], + "Startup Cost": 107212.8, + "Strategy": "Plain", + "Total Cost": 107212.81 + } + } + ], + "id": "GROUP_BY/group_by/low_cardinality_groups_plaintext/10000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT count(*) FROM (SELECT 1 FROM category_plaintext_10000000 GROUP BY value) g", + "rows_returned": 1 + }, + { + "explain": [ + { + "JIT": { + "Functions": 8, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": true, + "Optimization": true + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 40, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "(((value).data ->> 'hm'::text))::eql_v2.hmac_256" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 40, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_encrypted_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166667, + "Plan Width": 32, + "Relation Name": "category_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 506629.33 + } + ], + "Startup Cost": 527462.67, + "Strategy": "Hashed", + "Total Cost": 527465.79 + } + ], + "Sort Key": [ + "((((value).data ->> 'hm'::text))::eql_v2.hmac_256)" + ], + "Startup Cost": 527475.75, + "Total Cost": 527476.38 + } + ], + "Startup Cost": 528475.78, + "Total Cost": 528534.11, + "Workers Planned": 2 + } + ], + "Startup Cost": 528475.78, + "Strategy": "Sorted", + "Total Cost": 528539.74 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 528545.14, + "Total Cost": 528545.76 + } + ], + "Startup Cost": 528545.14, + "Total Cost": 528545.16 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_encrypted/10000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT eql_v2.hmac_256(value), count(*) FROM category_encrypted_10000000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Finalize", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather Merge", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Sort", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 250, + "Plan Width": 16, + "Plans": [ + { + "Async Capable": false, + "Group Key": [ + "value" + ], + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 250, + "Plan Width": 16, + "Planned Partitions": 0, + "Plans": [ + { + "Alias": "category_plaintext_10000000", + "Async Capable": false, + "Node Type": "Seq Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 4166608, + "Plan Width": 8, + "Relation Name": "category_plaintext_10000000", + "Startup Cost": 0.0, + "Total Cost": 95721.08 + } + ], + "Startup Cost": 116554.12, + "Strategy": "Hashed", + "Total Cost": 116556.62 + } + ], + "Sort Key": [ + "value" + ], + "Startup Cost": 116566.58, + "Total Cost": 116567.21 + } + ], + "Startup Cost": 117566.6, + "Total Cost": 117624.94, + "Workers Planned": 2 + } + ], + "Startup Cost": 117566.6, + "Strategy": "Sorted", + "Total Cost": 117629.94 + } + ], + "Sort Key": [ + "(count(*)) DESC" + ], + "Startup Cost": 117635.34, + "Total Cost": 117635.97 + } + ], + "Startup Cost": 117635.34, + "Total Cost": 117635.37 + } + } + ], + "id": "GROUP_BY/group_by/top_n_groups_plaintext/10000000", + "indexes_used": [], + "parameters": [], + "query": "SELECT value, count(*) FROM category_plaintext_10000000 GROUP BY 1 ORDER BY count(*) DESC LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "10000000" +} \ No newline at end of file diff --git a/results/query/group_by_rows_10000.json b/results/query/group_by_rows_10000.json index b4f9670..59127d5 100644 --- a/results/query/group_by_rows_10000.json +++ b/results/query/group_by_rows_10000.json @@ -1,3 +1,5 @@ -{"reason":"benchmark-complete","id":"GROUP_BY/group_by/eql_cast/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_eql_cast_10000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[4551906125.0,4719123208.0,3697537709.0,5082560500.0,4575627875.0,4781555834.0,4956161041.0,5143554041.0,5150066250.0,4642328959.0],"unit":"ns","throughput":[],"typical":{"estimate":4730042154.2,"lower_bound":4456724984.51,"upper_bound":4953773816.5,"unit":"ns"},"mean":{"estimate":4730042154.2,"lower_bound":4456724984.51,"upper_bound":4953773816.5,"unit":"ns"},"median":{"estimate":4750339521.0,"lower_bound":4575627875.0,"upper_bound":5082560500.0,"unit":"ns"},"median_abs_dev":{"estimate":299674163.9105201,"lower_bound":54869512.032571435,"upper_bound":640974206.4666331,"unit":"ns"},"slope":null,"change":{"mean":{"estimate":0.21890863075063693,"lower_bound":0.1316813324960823,"upper_bound":0.30609274533364517,"unit":"%"},"median":{"estimate":0.2534387435964922,"lower_bound":0.11427193668794611,"upper_bound":0.3662535513712508,"unit":"%"},"change":"Regressed"}} -{"reason":"benchmark-complete","id":"GROUP_BY/group_by/hmac_extractor/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_hmac_extractor_10000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[92315167.0,177508125.0,265394167.0,365453292.0,468068709.0,548455500.0,625435166.0,740552209.0,787314334.0,916873500.0],"unit":"ns","throughput":[],"typical":{"estimate":45316144.76753247,"lower_bound":44451783.80521355,"upper_bound":46042851.41433732,"unit":"ns"},"mean":{"estimate":45350194.70299603,"lower_bound":44742306.545117065,"upper_bound":45934173.694068946,"unit":"ns"},"median":{"estimate":45693143.25,"lower_bound":44377031.25,"upper_bound":46157583.5,"unit":"ns"},"median_abs_dev":{"estimate":1193917.47233498,"lower_bound":120100.60541778803,"upper_bound":1634189.7423273304,"unit":"ns"},"slope":{"estimate":45316144.76753247,"lower_bound":44451783.80521355,"upper_bound":46042851.41433732,"unit":"ns"},"change":{"mean":{"estimate":5.682713730216364,"lower_bound":5.4506371407002945,"upper_bound":5.904896748199547,"unit":"%"},"median":{"estimate":5.842602326559897,"lower_bound":5.40180453824739,"upper_bound":6.04298685972822,"unit":"%"},"change":"Regressed"}} -{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/eql_cast/10000","GROUP_BY/group_by/hmac_extractor/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_encrypted/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_encrypted_10000","iteration_count":[34,68,102,136,170,204,238,272,306,340],"measured_values":[85553375.0,171206542.0,260006458.0,412368750.0,471071458.0,629587958.0,607270833.0,691034375.0,918281625.0,920446167.0],"unit":"ns","throughput":[],"typical":{"estimate":2768411.993659282,"lower_bound":2620947.196028179,"upper_bound":2933898.1619242057,"unit":"ns"},"mean":{"estimate":2727268.9769152664,"lower_bound":2598893.5887044817,"upper_bound":2866940.8239460783,"unit":"ns"},"median":{"estimate":2629376.3653361346,"lower_bound":2533413.093137255,"upper_bound":3000920.343137255,"unit":"ns"},"median_abs_dev":{"estimate":166595.11158969864,"lower_bound":8147.306951312775,"upper_bound":358179.1618822252,"unit":"ns"},"slope":{"estimate":2768411.993659282,"lower_bound":2620947.196028179,"upper_bound":2933898.1619242057,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_plaintext/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_plaintext_10000","iteration_count":[61,122,183,244,305,366,427,488,549,610],"measured_values":[97692250.0,200143042.0,278411083.0,355983667.0,468607417.0,546215458.0,635268375.0,729563708.0,761541500.0,888017583.0],"unit":"ns","throughput":[],"typical":{"estimate":1464548.1670427932,"lower_bound":1430256.5114684487,"upper_bound":1504736.3693301366,"unit":"ns"},"mean":{"estimate":1507682.5314298724,"lower_bound":1465711.8025591986,"upper_bound":1551864.0016912569,"unit":"ns"},"median":{"estimate":1493699.7800546447,"lower_bound":1458949.4549180327,"upper_bound":1561442.1666666667,"unit":"ns"},"median_abs_dev":{"estimate":53880.33369728514,"lower_bound":5381.576626589165,"upper_bound":126233.89500056743,"unit":"ns"},"slope":{"estimate":1464548.1670427932,"lower_bound":1430256.5114684487,"upper_bound":1504736.3693301366,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_encrypted/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_encrypted_10000","iteration_count":[34,68,102,136,170,204,238,272,306,340],"measured_values":[92583166.0,179758334.0,330706875.0,450811708.0,532411959.0,561462125.0,634575167.0,729335667.0,826571791.0,958434625.0],"unit":"ns","throughput":[],"typical":{"estimate":2794385.310160428,"lower_bound":2717159.333094742,"upper_bound":2930318.948106892,"unit":"ns"},"mean":{"estimate":2867545.952662232,"lower_bound":2727751.2079960317,"upper_bound":3027984.2645339924,"unit":"ns"},"median":{"estimate":2737649.8063725494,"lower_bound":2681381.1286764704,"upper_bound":3131835.0529411766,"unit":"ns"},"median_abs_dev":{"estimate":113154.36757787323,"lower_bound":28077.639098213174,"upper_bound":414545.57630512444,"unit":"ns"},"slope":{"estimate":2794385.310160428,"lower_bound":2717159.333094742,"upper_bound":2930318.948106892,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_plaintext/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_plaintext_10000","iteration_count":[60,120,180,240,300,360,420,480,540,600],"measured_values":[88672708.0,174902583.0,289230500.0,383723333.0,481973500.0,582998459.0,817059375.0,796312917.0,818116333.0,960387250.0],"unit":"ns","throughput":[],"typical":{"estimate":1636612.961818182,"lower_bound":1558251.42009901,"upper_bound":1754480.9929153924,"unit":"ns"},"mean":{"estimate":1608714.219183201,"lower_bound":1539602.2337962962,"upper_bound":1698270.687688492,"unit":"ns"},"median":{"estimate":1603611.875,"lower_bound":1515030.2462962964,"upper_bound":1632910.6774305555,"unit":"ns"},"median_abs_dev":{"estimate":52781.78787064422,"lower_bound":4589.161710192626,"upper_bound":178834.76706504807,"unit":"ns"},"slope":{"estimate":1636612.961818182,"lower_bound":1558251.42009901,"upper_bound":1754480.9929153924,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/low_cardinality_groups_encrypted/10000","GROUP_BY/group_by/low_cardinality_groups_plaintext/10000","GROUP_BY/group_by/top_n_groups_encrypted/10000","GROUP_BY/group_by/top_n_groups_plaintext/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} diff --git a/results/query/group_by_rows_100000.json b/results/query/group_by_rows_100000.json index 4f0503b..b95c6ca 100644 --- a/results/query/group_by_rows_100000.json +++ b/results/query/group_by_rows_100000.json @@ -1,3 +1,5 @@ -{"reason":"benchmark-complete","id":"GROUP_BY/group_by/eql_cast/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_eql_cast_100000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[36405884750.0,37149355416.0,37874740042.0,37501585083.0,39262288917.0,38213672208.0,37403792958.0,37148188000.0,36565849000.0,37661012167.0],"unit":"ns","throughput":[],"typical":{"estimate":37518636854.1,"lower_bound":37060358674.075,"upper_bound":38031094898.1,"unit":"ns"},"mean":{"estimate":37518636854.1,"lower_bound":37060358674.075,"upper_bound":38031094898.1,"unit":"ns"},"median":{"estimate":37452689020.5,"lower_bound":36857602208.0,"upper_bound":37937342187.5,"unit":"ns"},"median_abs_dev":{"estimate":538593019.1726625,"lower_bound":189479952.0014584,"upper_bound":1340112818.8236415,"unit":"ns"},"slope":null,"change":null} -{"reason":"benchmark-complete","id":"GROUP_BY/group_by/hmac_extractor/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_hmac_extractor_100000","iteration_count":[5,10,15,20,25,30,35,40,45,50],"measured_values":[1130683709.0,2242166500.0,3382185625.0,4449089041.0,5628849833.0,6703555333.0,7836147125.0,8892240584.0,10000841250.0,11165733292.0],"unit":"ns","throughput":[],"typical":{"estimate":223158114.09246755,"lower_bound":222620143.85736012,"upper_bound":223909520.99635655,"unit":"ns"},"mean":{"estimate":223864423.82338095,"lower_bound":223073082.73042974,"upper_bound":224686908.69868094,"unit":"ns"},"median":{"estimate":223670881.1452381,"lower_bound":222454452.05,"upper_bound":225153993.32,"unit":"ns"},"median_abs_dev":{"estimate":1913514.424313333,"lower_bound":206550.87397798602,"upper_bound":2314014.734368041,"unit":"ns"},"slope":{"estimate":223158114.09246755,"lower_bound":222620143.85736012,"upper_bound":223909520.99635655,"unit":"ns"},"change":null} -{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/eql_cast/100000","GROUP_BY/group_by/hmac_extractor/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_encrypted/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_encrypted_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[120182458.0,227850667.0,382197500.0,452489792.0,522169875.0,684518000.0,713885250.0,773198208.0,894605250.0,1021482000.0],"unit":"ns","throughput":[],"typical":{"estimate":25778858.765584417,"lower_bound":25049542.33182731,"upper_bound":27166761.407232706,"unit":"ns"},"mean":{"estimate":27333297.024404764,"lower_bound":25934033.666815475,"upper_bound":28824584.945833337,"unit":"ns"},"median":{"estimate":27194552.875,"lower_bound":25193597.916666664,"upper_bound":29263473.9375,"unit":"ns"},"median_abs_dev":{"estimate":2487916.8895556447,"lower_bound":178632.0462286463,"upper_bound":4395031.747860085,"unit":"ns"},"slope":{"estimate":25778858.765584417,"lower_bound":25049542.33182731,"upper_bound":27166761.407232706,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_plaintext/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_plaintext_100000","iteration_count":[10,20,30,40,50,60,70,80,90,100],"measured_values":[98176666.0,197353167.0,292479291.0,385008125.0,470750000.0,586870250.0,689746833.0,752345209.0,857049583.0,988499292.0],"unit":"ns","throughput":[],"typical":{"estimate":9670325.595584415,"lower_bound":9504531.543639153,"upper_bound":9824569.788711706,"unit":"ns"},"mean":{"estimate":9692161.597099207,"lower_bound":9578866.077131944,"upper_bound":9796420.096741669,"unit":"ns"},"median":{"estimate":9765240.266666666,"lower_bound":9520101.5625,"upper_bound":9853526.185714286,"unit":"ns"},"median_abs_dev":{"estimate":164695.16416707748,"lower_bound":25700.233025730096,"upper_bound":311647.1475921571,"unit":"ns"},"slope":{"estimate":9670325.595584415,"lower_bound":9504531.543639153,"upper_bound":9824569.788711706,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_encrypted/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_encrypted_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[109242792.0,235555917.0,387093083.0,498659125.0,522243083.0,600860125.0,718247333.0,882676333.0,986063833.0,1035897292.0],"unit":"ns","throughput":[],"typical":{"estimate":26802166.202597402,"lower_bound":26024370.68494777,"upper_bound":27900796.096813727,"unit":"ns"},"mean":{"estimate":27785055.27441468,"lower_bound":26450109.364138644,"upper_bound":29281158.690694444,"unit":"ns"},"median":{"estimate":27350680.013888888,"lower_bound":25881922.307142854,"upper_bound":29444489.625,"unit":"ns"},"median_abs_dev":{"estimate":2336753.4419409996,"lower_bound":202328.49566107616,"upper_bound":3932052.0148389973,"unit":"ns"},"slope":{"estimate":26802166.202597402,"lower_bound":26024370.68494777,"upper_bound":27900796.096813727,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_plaintext/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_plaintext_100000","iteration_count":[9,18,27,36,45,54,63,72,81,90],"measured_values":[89829792.0,178766167.0,269837000.0,376179375.0,453549209.0,556424917.0,649650917.0,717962666.0,818612875.0,932561500.0],"unit":"ns","throughput":[],"typical":{"estimate":10202676.708513709,"lower_bound":10071385.97891963,"upper_bound":10319883.077687444,"unit":"ns"},"mean":{"estimate":10149071.745573193,"lower_bound":10041637.810943563,"upper_bound":10262949.249232803,"unit":"ns"},"median":{"estimate":10092601.550617285,"lower_bound":9981088.0,"upper_bound":10332979.787037037,"unit":"ns"},"median_abs_dev":{"estimate":209080.4622582671,"lower_bound":16500.795459830202,"upper_bound":313251.8721627416,"unit":"ns"},"slope":{"estimate":10202676.708513709,"lower_bound":10071385.97891963,"upper_bound":10319883.077687444,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/low_cardinality_groups_encrypted/100000","GROUP_BY/group_by/low_cardinality_groups_plaintext/100000","GROUP_BY/group_by/top_n_groups_encrypted/100000","GROUP_BY/group_by/top_n_groups_plaintext/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} diff --git a/results/query/group_by_rows_1000000.json b/results/query/group_by_rows_1000000.json new file mode 100644 index 0000000..e9589f8 --- /dev/null +++ b/results/query/group_by_rows_1000000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_encrypted/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_encrypted_1000000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[91807875.0,181678750.0,298732125.0,370949375.0,465330666.0,1596057458.0,1078899500.0,745505000.0,910224125.0,1635991958.0],"unit":"ns","throughput":[],"typical":{"estimate":137159559.82597402,"lower_bound":98389810.09469697,"upper_bound":176448418.26509187,"unit":"ns"},"mean":{"estimate":124608951.29722221,"lower_bound":96314736.32122223,"upper_bound":161712298.90654153,"unit":"ns"},"median":{"estimate":96382750.0,"lower_bound":92437004.1,"upper_bound":154128500.0,"unit":"ns"},"median_abs_dev":{"estimate":6914949.235568449,"lower_bound":424596.6544269114,"upper_bound":80877496.48913741,"unit":"ns"},"slope":{"estimate":137159559.82597402,"lower_bound":98389810.09469697,"upper_bound":176448418.26509187,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_plaintext/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_plaintext_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[94020167.0,146903625.0,238489334.0,299776000.0,431504666.0,473521583.0,531436458.0,753184292.0,657080542.0,727156458.0],"unit":"ns","throughput":[],"typical":{"estimate":39262170.45064935,"lower_bound":36931330.39702233,"upper_bound":43204644.75605536,"unit":"ns"},"mean":{"estimate":40146287.33055556,"lower_bound":37871365.93744444,"upper_bound":42734310.04333333,"unit":"ns"},"median":{"estimate":38709939.45833333,"lower_bound":36725906.25,"upper_bound":43379152.91666667,"unit":"ns"},"median_abs_dev":{"estimate":3105674.8946299106,"lower_bound":328294.6243549436,"upper_bound":6953555.265796385,"unit":"ns"},"slope":{"estimate":39262170.45064935,"lower_bound":36931330.39702233,"upper_bound":43204644.75605536,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_encrypted/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_encrypted_1000000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[92915209.0,192756750.0,283755083.0,399292875.0,488676458.0,581079916.0,664538375.0,753644291.0,853289375.0,964962042.0],"unit":"ns","throughput":[],"typical":{"estimate":95758116.86233766,"lower_bound":94905681.13740458,"upper_bound":96835998.41392833,"unit":"ns"},"mean":{"estimate":95872949.93853174,"lower_bound":94756176.70087896,"upper_bound":97089360.7308125,"unit":"ns"},"median":{"estimate":95656214.28571428,"lower_bound":94507733.46527778,"upper_bound":97115747.9,"unit":"ns"},"median_abs_dev":{"estimate":1676542.5827354193,"lower_bound":258732.89860657704,"upper_bound":3375669.156382403,"unit":"ns"},"slope":{"estimate":95758116.86233766,"lower_bound":94905681.13740458,"upper_bound":96835998.41392833,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_plaintext/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_plaintext_1000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[111430792.0,226973375.0,341314875.0,455492834.0,583437834.0,672188084.0,790675292.0,1068964292.0,1073733833.0,1141009042.0],"unit":"ns","throughput":[],"typical":{"estimate":39412768.375757575,"lower_bound":37819700.0098401,"upper_bound":41567635.399683245,"unit":"ns"},"mean":{"estimate":38708668.006613754,"lower_bound":37722722.65822884,"upper_bound":40153613.415513225,"unit":"ns"},"median":{"estimate":37940805.58333333,"lower_bound":37586339.138888896,"upper_bound":38900777.23703703,"unit":"ns"},"median_abs_dev":{"estimate":657254.6125147219,"lower_bound":81364.88887549072,"upper_bound":1877368.854050032,"unit":"ns"},"slope":{"estimate":39412768.375757575,"lower_bound":37819700.0098401,"upper_bound":41567635.399683245,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/low_cardinality_groups_encrypted/1000000","GROUP_BY/group_by/low_cardinality_groups_plaintext/1000000","GROUP_BY/group_by/top_n_groups_encrypted/1000000","GROUP_BY/group_by/top_n_groups_plaintext/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} diff --git a/results/query/group_by_rows_10000000.json b/results/query/group_by_rows_10000000.json new file mode 100644 index 0000000..6b12864 --- /dev/null +++ b/results/query/group_by_rows_10000000.json @@ -0,0 +1,5 @@ +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_encrypted/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_encrypted_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[2233089833.0,2009730000.0,1336109166.0,1284293209.0,1309175750.0,1287950750.0,1277164416.0,1295465709.0,1365978042.0,1256754583.0],"unit":"ns","throughput":[],"typical":{"estimate":1465571145.8,"lower_bound":1293736333.4,"upper_bound":1694576195.9,"unit":"ns"},"mean":{"estimate":1465571145.8,"lower_bound":1293736333.4,"upper_bound":1694576195.9,"unit":"ns"},"median":{"estimate":1302320729.5,"lower_bound":1282557583.0,"upper_bound":1672919583.0,"unit":"ns"},"median_abs_dev":{"estimate":43695742.3992455,"lower_bound":8282174.102962017,"upper_bound":499355115.37887454,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/low_cardinality_groups_plaintext/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_low_cardinality_groups_plaintext_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[428560541.0,429533542.0,433347542.0,429138458.0,427634166.0,428794625.0,437798167.0,431361125.0,429356583.0,429225208.0],"unit":"ns","throughput":[],"typical":{"estimate":430474995.7,"lower_bound":428962199.6,"upper_bound":432464120.6675,"unit":"ns"},"mean":{"estimate":430474995.7,"lower_bound":428962199.6,"upper_bound":432464120.6675,"unit":"ns"},"median":{"estimate":429290895.5,"lower_bound":428794625.0,"upper_bound":431440542.0,"unit":"ns"},"median_abs_dev":{"estimate":909297.0963567495,"lower_bound":161696.0596293211,"upper_bound":3877926.297453046,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_encrypted/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_encrypted_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[1279084625.0,1525057667.0,1253108417.0,1248775125.0,1226363417.0,1238075166.0,1252042834.0,1375722000.0,1378001166.0,1339752625.0],"unit":"ns","throughput":[],"typical":{"estimate":1311598304.2,"lower_bound":1262254388.5775,"upper_bound":1371546541.6,"unit":"ns"},"mean":{"estimate":1311598304.2,"lower_bound":1262254388.5775,"upper_bound":1371546541.6,"unit":"ns"},"median":{"estimate":1266096521.0,"lower_bound":1245059000.0,"upper_bound":1375722000.0,"unit":"ns"},"median_abs_dev":{"estimate":50226379.565003514,"lower_bound":3379091.4516091347,"upper_bound":161547336.31946146,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"GROUP_BY/group_by/top_n_groups_plaintext/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY/group_by_top_n_groups_plaintext_10000000","iteration_count":[2,2,2,2,2,2,2,2,2,2],"measured_values":[924582125.0,924613625.0,918011875.0,956007833.0,916910958.0,923533542.0,925552750.0,913883084.0,914487292.0,917499625.0],"unit":"ns","throughput":[],"typical":{"estimate":461754135.45,"lower_bound":458941653.585,"upper_bound":465812200.0,"unit":"ns"},"mean":{"estimate":461754135.45,"lower_bound":458941653.585,"upper_bound":465812200.0,"unit":"ns"},"median":{"estimate":460386354.25,"lower_bound":457996729.25,"upper_bound":462533718.75,"unit":"ns"},"median_abs_dev":{"estimate":2854993.472863734,"lower_bound":371437.62465566397,"upper_bound":6012205.313462019,"unit":"ns"},"slope":null,"change":null} +{"reason":"group-complete","group_name":"GROUP_BY","benchmarks":["GROUP_BY/group_by/low_cardinality_groups_encrypted/10000000","GROUP_BY/group_by/low_cardinality_groups_plaintext/10000000","GROUP_BY/group_by/top_n_groups_encrypted/10000000","GROUP_BY/group_by/top_n_groups_plaintext/10000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/GROUP_BY"} diff --git a/results/query/match_metadata_10000.json b/results/query/match_metadata_10000.json new file mode 100644 index 0000000..d5e6f61 --- /dev/null +++ b/results/query/match_metadata_10000.json @@ -0,0 +1,254 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1603,1164,10,1555,1789}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 56.22 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1603,1164,10,1555,1789}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + ], + "Startup Cost": 56.22, + "Total Cost": 60.73 + } + } + ], + "id": "MATCH/match/eql_cast_firstname/10000", + "indexes_used": [ + "string_encrypted_10000_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 1603, + 1164, + 10, + 1555, + 1789 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1381,1185,1609,835,1715,513,1967,543,461,1098,237,523,1987,820,1196,1846,1665,242,765,290,1061,702,44,1659,97,574,518,2024,450,1988}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 264.6 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1381,1185,1609,835,1715,513,1967,543,461,1098,237,523,1987,820,1196,1846,1665,242,765,290,1061,702,44,1659,97,574,518,2024,450,1988}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + ], + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + } + ], + "id": "MATCH/match/eql_cast_lastname/10000", + "indexes_used": [ + "string_encrypted_10000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1381, + 1185, + 1609, + 835, + 1715, + 513, + 1967, + 543, + 461, + 1098, + 237, + 523, + 1987, + 820, + 1196, + 1846, + 1665, + 242, + 765, + 290, + 1061, + 702, + 44, + 1659, + 97, + 574, + 518, + 2024, + 450, + 1988 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1659,2024,543,1967,518,1381,242,1185,450,290,835,820,1987,765,1846,237,461,44,1609,523,1715,1988,1098,702,97,574,1665,1061,513}'::smallint[])", + "Index Name": "string_encrypted_10000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 264.6 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1659,2024,543,1967,518,1381,242,1185,450,290,835,820,1987,765,1846,237,461,44,1609,523,1715,1988,1098,702,97,574,1665,1061,513}'::smallint[])", + "Relation Name": "string_encrypted_10000", + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + ], + "Startup Cost": 264.6, + "Total Cost": 269.11 + } + } + ], + "id": "MATCH/match/eql_bloom/10000", + "indexes_used": [ + "string_encrypted_10000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1196, + 1659, + 2024, + 543, + 1967, + 518, + 1381, + 242, + 1185, + 450, + 290, + 835, + 820, + 1987, + 765, + 1846, + 237, + 461, + 44, + 1609, + 523, + 1715, + 1988, + 1098, + 702, + 97, + 574, + 1665, + 1061, + 513 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000 WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "10000" +} \ No newline at end of file diff --git a/results/query/match_metadata_100000.json b/results/query/match_metadata_100000.json new file mode 100644 index 0000000..ce016b6 --- /dev/null +++ b/results/query/match_metadata_100000.json @@ -0,0 +1,254 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1555,10,36,1603,1164,1789}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 93.35 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1555,10,36,1603,1164,1789}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + ], + "Startup Cost": 93.35, + "Total Cost": 97.86 + } + } + ], + "id": "MATCH/match/eql_cast_firstname/100000", + "indexes_used": [ + "string_encrypted_100000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1555, + 10, + 36, + 1603, + 1164, + 1789 + ], + "i": { + "c": "value", + "t": "string_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_100000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1185,518,820,835,1987,237,574,1715,702,1988,290,1196,513,242,97,44,1609,461,1381,2024,765,1659,1967,1665,523,1846,450,1098,543,1061}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 458.47 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1185,518,820,835,1987,237,574,1715,702,1988,290,1196,513,242,97,44,1609,461,1381,2024,765,1659,1967,1665,523,1846,450,1098,543,1061}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + ], + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + } + ], + "id": "MATCH/match/eql_cast_lastname/100000", + "indexes_used": [ + "string_encrypted_100000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1185, + 518, + 820, + 835, + 1987, + 237, + 574, + 1715, + 702, + 1988, + 290, + 1196, + 513, + 242, + 97, + 44, + 1609, + 461, + 1381, + 2024, + 765, + 1659, + 1967, + 1665, + 523, + 1846, + 450, + 1098, + 543, + 1061 + ], + "i": { + "c": "value", + "t": "string_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_100000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,518,1659,1988,1098,44,765,574,513,2024,290,450,702,543,1967,1196,1381,1715,1185,97,237,1609,1061,1846,1665,242,820,835,1987,523}'::smallint[])", + "Index Name": "string_encrypted_100000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 458.47 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,518,1659,1988,1098,44,765,574,513,2024,290,450,702,543,1967,1196,1381,1715,1185,97,237,1609,1061,1846,1665,242,820,835,1987,523}'::smallint[])", + "Relation Name": "string_encrypted_100000", + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + ], + "Startup Cost": 458.48, + "Total Cost": 462.99 + } + } + ], + "id": "MATCH/match/eql_bloom/100000", + "indexes_used": [ + "string_encrypted_100000_gin_index" + ], + "parameters": [ + { + "bf": [ + 461, + 518, + 1659, + 1988, + 1098, + 44, + 765, + 574, + 513, + 2024, + 290, + 450, + 702, + 543, + 1967, + 1196, + 1381, + 1715, + 1185, + 97, + 237, + 1609, + 1061, + 1846, + 1665, + 242, + 820, + 835, + 1987, + 523 + ], + "i": { + "c": "value", + "t": "string_encrypted_100000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_100000 WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "100000" +} \ No newline at end of file diff --git a/results/query/match_metadata_1000000.json b/results/query/match_metadata_1000000.json new file mode 100644 index 0000000..ab6a1dc --- /dev/null +++ b/results/query/match_metadata_1000000.json @@ -0,0 +1,254 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,10,1164,1555,1603,1789}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 307.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,10,1164,1555,1603,1789}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 307.85, + "Total Cost": 312.36 + } + ], + "Startup Cost": 307.85, + "Total Cost": 312.36 + } + } + ], + "id": "MATCH/match/eql_cast_firstname/1000000", + "indexes_used": [ + "string_encrypted_1000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 10, + 1164, + 1555, + 1603, + 1789 + ], + "i": { + "c": "value", + "t": "string_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_1000000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1987,543,1609,574,765,835,461,1967,513,1665,97,523,1185,1061,450,1846,702,1659,2024,518,1196,1098,242,237,1381,1715,1988,44,820,290}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1526.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1987,543,1609,574,765,835,461,1967,513,1665,97,523,1185,1061,450,1846,702,1659,2024,518,1196,1098,242,237,1381,1715,1988,44,820,290}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + ], + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + } + ], + "id": "MATCH/match/eql_cast_lastname/1000000", + "indexes_used": [ + "string_encrypted_1000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1987, + 543, + 1609, + 574, + 765, + 835, + 461, + 1967, + 513, + 1665, + 97, + 523, + 1185, + 1061, + 450, + 1846, + 702, + 1659, + 2024, + 518, + 1196, + 1098, + 242, + 237, + 1381, + 1715, + 1988, + 44, + 820, + 290 + ], + "i": { + "c": "value", + "t": "string_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_1000000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1967,1988,702,2024,1665,1185,290,835,765,461,523,1987,1715,1659,543,518,820,574,1098,450,242,1061,237,1609,97,513,1381,44,1846}'::smallint[])", + "Index Name": "string_encrypted_1000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1526.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{1196,1967,1988,702,2024,1665,1185,290,835,765,461,523,1987,1715,1659,543,518,820,574,1098,450,242,1061,237,1609,97,513,1381,44,1846}'::smallint[])", + "Relation Name": "string_encrypted_1000000", + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + ], + "Startup Cost": 1526.85, + "Total Cost": 1531.36 + } + } + ], + "id": "MATCH/match/eql_bloom/1000000", + "indexes_used": [ + "string_encrypted_1000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 1196, + 1967, + 1988, + 702, + 2024, + 1665, + 1185, + 290, + 835, + 765, + 461, + 523, + 1987, + 1715, + 1659, + 543, + 518, + 820, + 574, + 1098, + 450, + 242, + 1061, + 237, + 1609, + 97, + 513, + 1381, + 44, + 1846 + ], + "i": { + "c": "value", + "t": "string_encrypted_1000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_1000000 WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "1000000" +} \ No newline at end of file diff --git a/results/query/match_metadata_10000000.json b/results/query/match_metadata_10000000.json new file mode 100644 index 0000000..997dbda --- /dev/null +++ b/results/query/match_metadata_10000000.json @@ -0,0 +1,254 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 2254.85 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{36,1789,1603,1555,10,1164}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 2254.85, + "Total Cost": 2259.36 + } + ], + "Startup Cost": 2254.85, + "Total Cost": 2259.36 + } + } + ], + "id": "MATCH/match/eql_cast_firstname/10000000", + "indexes_used": [ + "string_encrypted_10000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 36, + 1789, + 1603, + 1555, + 10, + 1164 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,450,513,765,1846,2024,1665,543,97,242,1609,835,1061,290,1987,1381,1715,237,1967,574,1185,44,523,702,1196,1988,1098,820,518,1659}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 11270.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{461,450,513,765,1846,2024,1665,543,97,242,1609,835,1061,290,1987,1381,1715,237,1967,574,1185,44,523,702,1196,1988,1098,820,518,1659}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + ], + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + } + ], + "id": "MATCH/match/eql_cast_lastname/10000000", + "indexes_used": [ + "string_encrypted_10000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 461, + 450, + 513, + 765, + 1846, + 2024, + 1665, + 543, + 97, + 242, + 1609, + 835, + 1061, + 290, + 1987, + 1381, + 1715, + 237, + 1967, + 574, + 1185, + 44, + 523, + 702, + 1196, + 1988, + 1098, + 820, + 518, + 1659 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000000 WHERE value LIKE $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Alias": "string_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{574,702,1846,237,1659,44,242,1967,1196,518,290,1381,1665,450,1609,835,2024,513,1098,765,820,1715,1185,1987,97,1061,1988,523,543,461}'::smallint[])", + "Index Name": "string_encrypted_10000000_gin_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 1, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 11270.1 + } + ], + "Recheck Cond": "((eql_v2.bloom_filter(value))::smallint[] @> '{574,702,1846,237,1659,44,242,1967,1196,518,290,1381,1665,450,1609,835,2024,513,1098,765,820,1715,1185,1987,97,1061,1988,523,543,461}'::smallint[])", + "Relation Name": "string_encrypted_10000000", + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + ], + "Startup Cost": 11270.1, + "Total Cost": 11274.61 + } + } + ], + "id": "MATCH/match/eql_bloom/10000000", + "indexes_used": [ + "string_encrypted_10000000_gin_index" + ], + "parameters": [ + { + "bf": [ + 574, + 702, + 1846, + 237, + 1659, + 44, + 242, + 1967, + 1196, + 518, + 290, + 1381, + 1665, + 450, + 1609, + 835, + 2024, + 513, + 1098, + 765, + 820, + 1715, + 1185, + 1987, + 97, + 1061, + 1988, + 523, + 543, + 461 + ], + "i": { + "c": "value", + "t": "string_encrypted_10000000" + }, + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM string_encrypted_10000000 WHERE eql_v2.bloom_filter(value) @> eql_v2.bloom_filter($1) LIMIT 10", + "rows_returned": 10 + } + ], + "target_rows": "10000000" +} \ No newline at end of file diff --git a/results/query/match_rows_10000.json b/results/query/match_rows_10000.json index fb967d7..66a0058 100644 --- a/results/query/match_rows_10000.json +++ b/results/query/match_rows_10000.json @@ -1,7 +1,7 @@ -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_10000","iteration_count":[135,270,405,540,675,810,945,1080,1215,1350],"measured_values":[99008334.0,197721709.0,259991958.0,344571667.0,441238667.0,531873833.0,615490459.0,727639125.0,799260958.0,946674583.0],"unit":"ns","throughput":[],"typical":{"estimate":670318.2547763347,"lower_bound":653629.1307591279,"upper_bound":686747.2512187401,"unit":"ns"},"mean":{"estimate":674019.1066281599,"lower_bound":654612.6254791298,"upper_bound":695993.5823071136,"unit":"ns"},"median":{"estimate":657231.1553497943,"lower_bound":647821.182962963,"upper_bound":703021.2782407408,"unit":"ns"},"median_abs_dev":{"estimate":23561.833644749324,"lower_bound":3069.749114735576,"upper_bound":58277.82616113949,"unit":"ns"},"slope":{"estimate":670318.2547763347,"lower_bound":653629.1307591279,"upper_bound":686747.2512187401,"unit":"ns"},"change":{"mean":{"estimate":0.01970805041069945,"lower_bound":-0.015275098699091131,"upper_bound":0.057096646042586026,"unit":"%"},"median":{"estimate":-0.0062513046142086415,"lower_bound":-0.02295063127033925,"upper_bound":0.08082170108618891,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[122159167.0,224108416.0,321455167.0,422570958.0,527025875.0,641924333.0,771012500.0,928474875.0,947304916.0,1095146333.0],"unit":"ns","throughput":[],"typical":{"estimate":27281684.921428572,"lower_bound":26566804.927419353,"upper_bound":28052472.393282387,"unit":"ns"},"mean":{"estimate":27509378.44941468,"lower_bound":26788510.981597226,"upper_bound":28383468.67908482,"unit":"ns"},"median":{"estimate":27083294.454166666,"lower_bound":26410684.875,"upper_bound":28275500.27901786,"unit":"ns"},"median_abs_dev":{"estimate":1041237.5845493361,"lower_bound":99280.62901658379,"upper_bound":2035153.0646031876,"unit":"ns"},"slope":{"estimate":27281684.921428572,"lower_bound":26566804.927419353,"upper_bound":28052472.393282387,"unit":"ns"},"change":{"mean":{"estimate":-0.04958123934462433,"lower_bound":-0.10859613062591118,"upper_bound":0.0010691447482613988,"unit":"%"},"median":{"estimate":-0.04780196815338156,"lower_bound":-0.07483746698719074,"upper_bound":-0.005298270648365078,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_10000","iteration_count":[103,206,309,412,515,618,721,824,927,1030],"measured_values":[94234375.0,195533042.0,298727083.0,374953250.0,486989084.0,532926334.0,634208042.0,704718333.0,774291667.0,945934666.0],"unit":"ns","throughput":[],"typical":{"estimate":883090.9785146891,"lower_bound":855665.9461720291,"upper_bound":914484.4392484233,"unit":"ns"},"mean":{"estimate":903738.4367248422,"lower_bound":877435.678808368,"upper_bound":929119.2384928724,"unit":"ns"},"median":{"estimate":912488.7742718447,"lower_bound":862340.3462783172,"upper_bound":945609.8718446601,"unit":"ns"},"median_abs_dev":{"estimate":51758.93468682334,"lower_bound":6154.618670636585,"upper_bound":75530.21559903845,"unit":"ns"},"slope":{"estimate":883090.9785146891,"lower_bound":855665.9461720291,"upper_bound":914484.4392484233,"unit":"ns"},"change":{"mean":{"estimate":-0.054550379456170806,"lower_bound":-0.1192818405589943,"upper_bound":0.007200867850503521,"unit":"%"},"median":{"estimate":-0.0233341882462742,"lower_bound":-0.11370417557102908,"upper_bound":0.05456825175182156,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[96045792.0,224267291.0,331386292.0,443821250.0,546358625.0,636713291.0,759782375.0,903360958.0,993206292.0,1109883792.0],"unit":"ns","throughput":[],"typical":{"estimate":27564386.985714287,"lower_bound":27150059.959737826,"upper_bound":27863585.866189152,"unit":"ns"},"mean":{"estimate":27194813.676726185,"lower_bound":26390118.4339747,"upper_bound":27763182.219226193,"unit":"ns"},"median":{"estimate":27602294.0,"lower_bound":26923825.854166664,"upper_bound":27886119.75,"unit":"ns"},"median_abs_dev":{"estimate":530385.4072462767,"lower_bound":97533.1852084413,"upper_bound":1151287.0331730656,"unit":"ns"},"slope":{"estimate":27564386.985714287,"lower_bound":27150059.959737826,"upper_bound":27863585.866189152,"unit":"ns"},"change":{"mean":{"estimate":-0.020276880079356463,"lower_bound":-0.056652436713236935,"upper_bound":0.012069510878030262,"unit":"%"},"median":{"estimate":-0.015378792845818334,"lower_bound":-0.04234600619626083,"upper_bound":0.03373932194025464,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_10000","iteration_count":[103,206,309,412,515,618,721,824,927,1030],"measured_values":[96478792.0,207202292.0,359094500.0,414809667.0,514673792.0,491864167.0,652048333.0,806033125.0,890544042.0,983358625.0],"unit":"ns","throughput":[],"typical":{"estimate":949011.3596015635,"lower_bound":905619.8385238646,"upper_bound":984727.5302820157,"unit":"ns"},"mean":{"estimate":970467.7125878409,"lower_bound":917130.6769070735,"upper_bound":1026021.0631206656,"unit":"ns"},"median":{"estimate":969434.3622572816,"lower_bound":929541.8658113731,"upper_bound":1005836.3689320388,"unit":"ns"},"median_abs_dev":{"estimate":51260.20316956108,"lower_bound":6253.758547517453,"upper_bound":151896.7559843615,"unit":"ns"},"slope":{"estimate":949011.3596015635,"lower_bound":905619.8385238646,"upper_bound":984727.5302820157,"unit":"ns"},"change":{"mean":{"estimate":0.1284240912832999,"lower_bound":0.05737595146538302,"upper_bound":0.1983362536194862,"unit":"%"},"median":{"estimate":0.1259848244204822,"lower_bound":0.068147760463106,"upper_bound":0.18490343093454853,"unit":"%"},"change":"Regressed"}} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[145826459.0,230930250.0,342373292.0,435881334.0,574001500.0,653803625.0,770607333.0,901833375.0,1002966292.0,1153892625.0],"unit":"ns","throughput":[],"typical":{"estimate":28146560.14935065,"lower_bound":27684808.686651584,"upper_bound":28580052.301126517,"unit":"ns"},"mean":{"estimate":28944995.358581353,"lower_bound":27816005.43747024,"upper_bound":30755224.36597222,"unit":"ns"},"median":{"estimate":28356700.317708336,"lower_bound":27521690.464285713,"upper_bound":28847315.625,"unit":"ns"},"median_abs_dev":{"estimate":745826.7146172635,"lower_bound":123208.69093760848,"upper_bound":1747072.8816332584,"unit":"ns"},"slope":{"estimate":28146560.14935065,"lower_bound":27684808.686651584,"upper_bound":28580052.301126517,"unit":"ns"},"change":{"mean":{"estimate":0.03356877083581988,"lower_bound":-0.019146800515889413,"upper_bound":0.10762911524921695,"unit":"%"},"median":{"estimate":0.030437434451316747,"lower_bound":-0.036505137146440436,"upper_bound":0.05380871325758463,"unit":"%"},"change":"NoChange"}} -{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/1000000","MATCH/match/eql_cast_firstname/100000","MATCH/match_decrypt/eql_cast_firstname/100000","MATCH/match/eql_cast_lastname/100000","MATCH/match_decrypt/eql_bloom/100000","MATCH/match/eql_bloom/100000","MATCH/match_decrypt/eql_cast_lastname/100000","MATCH/match_decrypt/eql_cast_firstname/1000000","MATCH/match/eql_bloom/1000000","MATCH/match/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_bloom/1000000","MATCH/match/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_firstname/10000","MATCH/match/eql_cast_lastname/10000","MATCH/match_decrypt/eql_cast_lastname/10000","MATCH/match/eql_bloom/10000","MATCH/match_decrypt/eql_bloom/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH"} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_10000","iteration_count":[120,240,360,480,600,720,840,960,1080,1200],"measured_values":[77065500.0,153482000.0,245133416.0,344342584.0,452260375.0,563286375.0,584602292.0,655268417.0,808079500.0,1136732667.0],"unit":"ns","throughput":[],"typical":{"estimate":781649.9082034632,"lower_bound":701815.1218852459,"upper_bound":870626.9820220355,"unit":"ns"},"mean":{"estimate":729016.2210380291,"lower_bound":682949.4107523148,"upper_bound":787902.4538252314,"unit":"ns"},"median":{"estimate":706667.7464285714,"lower_bound":662391.8838541666,"upper_bound":765281.9733796297,"unit":"ns"},"median_abs_dev":{"estimate":65718.88142964548,"lower_bound":11140.96337887499,"upper_bound":118424.05822644163,"unit":"ns"},"slope":{"estimate":781649.9082034632,"lower_bound":701815.1218852459,"upper_bound":870626.9820220355,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[125109875.0,216524333.0,340327834.0,512088375.0,546225208.0,659323042.0,766419209.0,886398084.0,1010660625.0,1099322250.0],"unit":"ns","throughput":[],"typical":{"estimate":27831069.542207792,"lower_bound":27490797.417786676,"upper_bound":28482684.775641024,"unit":"ns"},"mean":{"estimate":28412125.769464284,"lower_bound":27504268.88283036,"upper_bound":29570559.10946428,"unit":"ns"},"median":{"estimate":27591498.1875,"lower_bound":27372114.60714286,"upper_bound":29675687.5,"unit":"ns"},"median_abs_dev":{"estimate":565349.3585680436,"lower_bound":90222.44590823518,"upper_bound":2380114.9700489,"unit":"ns"},"slope":{"estimate":27831069.542207792,"lower_bound":27490797.417786676,"upper_bound":28482684.775641024,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_10000","iteration_count":[86,172,258,344,430,516,602,688,774,860],"measured_values":[83178125.0,168454875.0,270565667.0,846581334.0,996244250.0,581016708.0,857481125.0,1167595834.0,1286472709.0,1561668583.0],"unit":"ns","throughput":[],"typical":{"estimate":1679960.9322863184,"lower_bound":1462568.4075212667,"upper_bound":1866745.9568914245,"unit":"ns"},"mean":{"estimate":1549859.8522083794,"lower_bound":1243623.944134436,"upper_bound":1877939.1306251155,"unit":"ns"},"median":{"estimate":1543248.3469915097,"lower_bound":1048704.1356589147,"upper_bound":2006967.030523256,"unit":"ns"},"median_abs_dev":{"estimate":675910.7943532853,"lower_bound":69473.11050439642,"upper_bound":966134.5208320635,"unit":"ns"},"slope":{"estimate":1679960.9322863184,"lower_bound":1462568.4075212667,"upper_bound":1866745.9568914245,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_10000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[27629583.0,65703792.0,89717542.0,111573958.0,133032042.0,184793292.0,279107875.0,244564708.0,280590458.0,290486541.0],"unit":"ns","throughput":[],"typical":{"estimate":31139890.67012987,"lower_bound":29081664.398924418,"upper_bound":34311720.23886369,"unit":"ns"},"mean":{"estimate":30635461.99603175,"lower_bound":28723701.09741667,"upper_bound":33074263.59698413,"unit":"ns"},"median":{"estimate":30238217.916666664,"lower_bound":27893489.5,"upper_bound":31825389.0,"unit":"ns"},"median_abs_dev":{"estimate":2619970.786056216,"lower_bound":449323.46090625034,"upper_bound":4629779.8756849775,"unit":"ns"},"slope":{"estimate":31139890.67012987,"lower_bound":29081664.398924418,"upper_bound":34311720.23886369,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_10000","iteration_count":[84,168,252,336,420,504,588,672,756,840],"measured_values":[89670917.0,164704917.0,262482958.0,359658834.0,397272667.0,492188583.0,592584458.0,764988833.0,703602875.0,889571750.0],"unit":"ns","throughput":[],"typical":{"estimate":1022906.7730055659,"lower_bound":961625.2578741171,"upper_bound":1079286.6506129603,"unit":"ns"},"mean":{"estimate":1021824.0073237906,"lower_bound":984342.3015254156,"upper_bound":1060252.1181712963,"unit":"ns"},"median":{"estimate":1024697.8684807257,"lower_bound":963136.856547619,"upper_bound":1067510.9166666667,"unit":"ns"},"median_abs_dev":{"estimate":66736.85506518396,"lower_bound":8450.23298747849,"upper_bound":115628.46026385104,"unit":"ns"},"slope":{"estimate":1022906.7730055659,"lower_bound":961625.2578741171,"upper_bound":1079286.6506129603,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[105557459.0,233408542.0,341762292.0,469255292.0,539739875.0,669648333.0,824812583.0,955156167.0,1006337500.0,1124124750.0],"unit":"ns","throughput":[],"typical":{"estimate":28509411.933116883,"lower_bound":27934639.47232143,"upper_bound":29246432.270202022,"unit":"ns"},"mean":{"estimate":28362624.753819443,"lower_bound":27687092.851736113,"upper_bound":29001293.12019965,"unit":"ns"},"median":{"estimate":28291654.875,"lower_bound":27470406.597222224,"upper_bound":29328455.75,"unit":"ns"},"median_abs_dev":{"estimate":1424195.7275904715,"lower_bound":149079.04119082072,"upper_bound":1948527.3084942251,"unit":"ns"},"slope":{"estimate":28509411.933116883,"lower_bound":27934639.47232143,"upper_bound":29246432.270202022,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/10000","MATCH/match_decrypt/eql_cast_firstname/10000","MATCH/match/eql_cast_lastname/10000","MATCH/match_decrypt/eql_cast_lastname/10000","MATCH/match/eql_bloom/10000","MATCH/match_decrypt/eql_bloom/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH"} diff --git a/results/query/match_rows_100000.json b/results/query/match_rows_100000.json index 8adffa5..a78e735 100644 --- a/results/query/match_rows_100000.json +++ b/results/query/match_rows_100000.json @@ -1,7 +1,7 @@ -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_100000","iteration_count":[83,166,249,332,415,498,581,664,747,830],"measured_values":[97782959.0,184410458.0,271682125.0,404076542.0,452206625.0,609347000.0,702409333.0,771393625.0,880385333.0,980778834.0],"unit":"ns","throughput":[],"typical":{"estimate":1177729.3760287904,"lower_bound":1154510.4739964884,"upper_bound":1196132.1376722765,"unit":"ns"},"mean":{"estimate":1164137.421296137,"lower_bound":1133476.4592950374,"upper_bound":1192522.7653198508,"unit":"ns"},"median":{"estimate":1178334.6479250335,"lower_bound":1110906.373493976,"upper_bound":1208966.1497418245,"unit":"ns"},"median_abs_dev":{"estimate":51442.41767366236,"lower_bound":2634.065708898677,"upper_bound":79564.75059632906,"unit":"ns"},"slope":{"estimate":1177729.3760287904,"lower_bound":1154510.4739964884,"upper_bound":1196132.1376722765,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[115074375.0,241029375.0,337491833.0,430877375.0,543720458.0,752521791.0,805142500.0,899609583.0,1007454625.0,1132295834.0],"unit":"ns","throughput":[],"typical":{"estimate":28434919.018831167,"lower_bound":27900786.973742798,"upper_bound":29282848.807692308,"unit":"ns"},"mean":{"estimate":28565265.380307544,"lower_bound":27847627.261378966,"upper_bound":29392721.27935045,"unit":"ns"},"median":{"estimate":28215857.633333333,"lower_bound":27649411.184375,"upper_bound":29441880.58035714,"unit":"ns"},"median_abs_dev":{"estimate":809475.6928239356,"lower_bound":103388.16194783054,"upper_bound":2181385.646440164,"unit":"ns"},"slope":{"estimate":28434919.018831167,"lower_bound":27900786.973742798,"upper_bound":29282848.807692308,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_100000","iteration_count":[33,66,99,132,165,198,231,264,297,330],"measured_values":[91106833.0,196809583.0,255567375.0,369264208.0,503606125.0,555357292.0,659196875.0,730998458.0,786261334.0,935434417.0],"unit":"ns","throughput":[],"typical":{"estimate":2791949.7282959465,"lower_bound":2716605.6414141413,"upper_bound":2869683.457893856,"unit":"ns"},"mean":{"estimate":2808330.838496874,"lower_bound":2727582.3953992305,"upper_bound":2891128.709007576,"unit":"ns"},"median":{"estimate":2801145.4646464647,"lower_bound":2708139.055976431,"upper_bound":2908306.5636363635,"unit":"ns"},"median_abs_dev":{"estimate":68831.93088707986,"lower_bound":26613.599896453543,"upper_bound":248052.92676234187,"unit":"ns"},"slope":{"estimate":2791949.7282959465,"lower_bound":2716605.6414141413,"upper_bound":2869683.457893856,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[103205458.0,213804291.0,385671042.0,423312666.0,618902667.0,721411708.0,825436375.0,952927625.0,1068347958.0,1113859750.0],"unit":"ns","throughput":[],"typical":{"estimate":29194328.675324675,"lower_bound":28380953.49786419,"upper_bound":30001802.85648148,"unit":"ns"},"mean":{"estimate":28890883.52502976,"lower_bound":27667314.54330729,"upper_bound":30107823.345863093,"unit":"ns"},"median":{"estimate":29578101.351190478,"lower_bound":26725536.375,"upper_bound":30362060.815625,"unit":"ns"},"median_abs_dev":{"estimate":2297021.4946997175,"lower_bound":221735.980829026,"upper_bound":3575428.127582833,"unit":"ns"},"slope":{"estimate":29194328.675324675,"lower_bound":28380953.49786419,"upper_bound":30001802.85648148,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_100000","iteration_count":[36,72,108,144,180,216,252,288,324,360],"measured_values":[89448416.0,184227709.0,271747459.0,376730667.0,470580041.0,566689417.0,713852917.0,745447917.0,873608334.0,932829125.0],"unit":"ns","throughput":[],"typical":{"estimate":2646783.953607504,"lower_bound":2591456.447887671,"upper_bound":2717738.2818586924,"unit":"ns"},"mean":{"estimate":2612228.196901455,"lower_bound":2560141.307476852,"upper_bound":2673798.754384921,"unit":"ns"},"median":{"estimate":2602762.7875,"lower_bound":2552270.499421296,"upper_bound":2656253.6030092593,"unit":"ns"},"median_abs_dev":{"estimate":48068.808299385826,"lower_bound":6841.127425490042,"upper_bound":150999.3211500602,"unit":"ns"},"slope":{"estimate":2646783.953607504,"lower_bound":2591456.447887671,"upper_bound":2717738.2818586924,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[106731041.0,201005958.0,385516459.0,473044166.0,584949042.0,710398291.0,879213541.0,984166083.0,1011503208.0,1240378209.0],"unit":"ns","throughput":[],"typical":{"estimate":30051778.16038961,"lower_bound":28895702.749244712,"upper_bound":30885477.31245547,"unit":"ns"},"mean":{"estimate":29360995.810922623,"lower_bound":28024282.691171873,"upper_bound":30573642.949802086,"unit":"ns"},"median":{"estimate":29582594.583333336,"lower_bound":27965106.175,"upper_bound":31077836.85044643,"unit":"ns"},"median_abs_dev":{"estimate":2158772.2285666335,"lower_bound":286990.663712398,"upper_bound":3497248.2625614326,"unit":"ns"},"slope":{"estimate":30051778.16038961,"lower_bound":28895702.749244712,"upper_bound":30885477.31245547,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_100000","iteration_count":[88,176,264,352,440,528,616,704,792,880],"measured_values":[85677500.0,183023458.0,268052541.0,370069208.0,464215458.0,539308584.0,633765625.0,798449375.0,838526291.0,905780458.0],"unit":"ns","throughput":[],"typical":{"estimate":1054356.0578217236,"lower_bound":1029463.7241758804,"upper_bound":1089511.2881799163,"unit":"ns"},"mean":{"estimate":1040769.301809614,"lower_bound":1018197.676818182,"upper_bound":1066574.7620125362,"unit":"ns"},"median":{"estimate":1034600.9931818182,"lower_bound":1021417.7727272727,"upper_bound":1055039.1470959596,"unit":"ns"},"median_abs_dev":{"estimate":26673.78465712752,"lower_bound":5494.767282372647,"upper_bound":60361.965440633605,"unit":"ns"},"slope":{"estimate":1054356.0578217236,"lower_bound":1029463.7241758804,"upper_bound":1089511.2881799163,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[96447250.0,220087500.0,315921542.0,410497208.0,508278125.0,624599333.0,709050167.0,788909917.0,914446791.0,1030810458.0],"unit":"ns","throughput":[],"typical":{"estimate":25472804.243506495,"lower_bound":25112573.339325406,"upper_bound":25798816.508196723,"unit":"ns"},"mean":{"estimate":25619271.548125,"lower_bound":25097105.178125,"upper_bound":26179446.904166665,"unit":"ns"},"median":{"estimate":25534990.875,"lower_bound":25027367.328125,"upper_bound":26048528.308333334,"unit":"ns"},"median_abs_dev":{"estimate":537629.2301026717,"lower_bound":76570.72889059782,"upper_bound":1528979.476852063,"unit":"ns"},"slope":{"estimate":25472804.243506495,"lower_bound":25112573.339325406,"upper_bound":25798816.508196723,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_100000","iteration_count":[30,60,90,120,150,180,210,240,270,300],"measured_values":[96230042.0,187934875.0,279344125.0,391952334.0,457174583.0,553717000.0,644194917.0,735862541.0,852014417.0,908558333.0],"unit":"ns","throughput":[],"typical":{"estimate":3085376.1253679655,"lower_bound":3048559.5030533154,"upper_bound":3135664.374383453,"unit":"ns"},"mean":{"estimate":3115187.0645542326,"lower_bound":3073886.6209627977,"upper_bound":3161603.6771369055,"unit":"ns"},"median":{"estimate":3090014.583333333,"lower_bound":3057712.698095238,"upper_bound":3169957.9916666667,"unit":"ns"},"median_abs_dev":{"estimate":62578.5903280079,"lower_bound":8608.388163004147,"upper_bound":124106.59446888961,"unit":"ns"},"slope":{"estimate":3085376.1253679655,"lower_bound":3048559.5030533154,"upper_bound":3135664.374383453,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[114649625.0,196185917.0,336185542.0,431083791.0,540683834.0,696958791.0,801554916.0,937055208.0,1062057416.0,1119558458.0],"unit":"ns","throughput":[],"typical":{"estimate":28562670.496753246,"lower_bound":27868473.945402298,"upper_bound":29106901.773024842,"unit":"ns"},"mean":{"estimate":27961847.88454365,"lower_bound":27010598.274583332,"upper_bound":28743019.690793645,"unit":"ns"},"median":{"estimate":28321211.55952381,"lower_bound":27034191.7,"upper_bound":29039949.625,"unit":"ns"},"median_abs_dev":{"estimate":1245755.929570911,"lower_bound":306148.2504772809,"upper_bound":2242722.5670120683,"unit":"ns"},"slope":{"estimate":28562670.496753246,"lower_bound":27868473.945402298,"upper_bound":29106901.773024842,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_100000","iteration_count":[31,62,93,124,155,186,217,248,279,310],"measured_values":[91443958.0,405558708.0,385294292.0,361392834.0,473369583.0,575331625.0,666706584.0,744025375.0,807097708.0,987186834.0],"unit":"ns","throughput":[],"typical":{"estimate":3106640.138332635,"lower_bound":2989257.957900492,"upper_bound":3299508.8066338617,"unit":"ns"},"mean":{"estimate":3484544.025915259,"lower_bound":2998342.2568033156,"upper_bound":4221761.273486944,"unit":"ns"},"median":{"estimate":3063188.9405529955,"lower_bound":2949805.0967741935,"upper_bound":3618065.0779569894,"unit":"ns"},"median_abs_dev":{"estimate":173959.80139611245,"lower_bound":29046.705715608787,"upper_bound":845868.8565996003,"unit":"ns"},"slope":{"estimate":3106640.138332635,"lower_bound":2989257.957900492,"upper_bound":3299508.8066338617,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[102674334.0,209133458.0,329981500.0,462745625.0,534877500.0,631621625.0,745918167.0,919155209.0,1045979750.0,1136939041.0],"unit":"ns","throughput":[],"typical":{"estimate":28041469.156493507,"lower_bound":27041058.916935325,"upper_bound":28637295.15926641,"unit":"ns"},"mean":{"estimate":27413377.225168653,"lower_bound":26673319.075541917,"upper_bound":28157492.898219742,"unit":"ns"},"median":{"estimate":27121166.666666664,"lower_bound":26317567.708333332,"upper_bound":28723600.28125,"unit":"ns"},"median_abs_dev":{"estimate":1691493.6953774828,"lower_bound":260767.7758954447,"upper_bound":2042201.7925261694,"unit":"ns"},"slope":{"estimate":28041469.156493507,"lower_bound":27041058.916935325,"upper_bound":28637295.15926641,"unit":"ns"},"change":null} {"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/100000","MATCH/match_decrypt/eql_cast_firstname/100000","MATCH/match/eql_cast_lastname/100000","MATCH/match_decrypt/eql_cast_lastname/100000","MATCH/match/eql_bloom/100000","MATCH/match_decrypt/eql_bloom/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH"} diff --git a/results/query/match_rows_1000000.json b/results/query/match_rows_1000000.json index 729b338..5371055 100644 --- a/results/query/match_rows_1000000.json +++ b/results/query/match_rows_1000000.json @@ -1,5 +1,7 @@ -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_1000000","iteration_count":[19,38,57,76,95,114,133,152,171,190],"measured_values":[90527292.0,181007792.0,270681584.0,382648500.0,472861334.0,556310375.0,652804250.0,745992833.0,811661667.0,919180416.0],"unit":"ns","throughput":[],"typical":{"estimate":4857372.812713603,"lower_bound":4804118.623007029,"upper_bound":4921375.720422911,"unit":"ns"},"mean":{"estimate":4856951.02995614,"lower_bound":4798861.696658991,"upper_bound":4918643.218279605,"unit":"ns"},"median":{"estimate":4858853.616666666,"lower_bound":4756697.01754386,"upper_bound":4942667.655921053,"unit":"ns"},"median_abs_dev":{"estimate":140661.6503938091,"lower_bound":11708.534171079176,"upper_bound":187954.49993353686,"unit":"ns"},"slope":{"estimate":4857372.812713603,"lower_bound":4804118.623007029,"upper_bound":4921375.720422911,"unit":"ns"},"change":{"mean":{"estimate":-0.9874380852198805,"lower_bound":-0.988655238953072,"upper_bound":-0.9856820751407159,"unit":"%"},"median":{"estimate":-0.9877678246182628,"lower_bound":-0.9888109232100681,"upper_bound":-0.9862896355655763,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_1000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[94940542.0,174636917.0,270874084.0,360227083.0,491246500.0,535855750.0,672654375.0,774155916.0,870580750.0,904978458.0],"unit":"ns","throughput":[],"typical":{"estimate":31303853.89004329,"lower_bound":30420351.36057043,"upper_bound":32102739.677119244,"unit":"ns"},"mean":{"estimate":31008591.20457672,"lower_bound":30249930.321666665,"upper_bound":31766979.361190476,"unit":"ns"},"median":{"estimate":30906397.96666667,"lower_bound":29933442.166666664,"upper_bound":32243731.48148148,"unit":"ns"},"median_abs_dev":{"estimate":1676373.4369050884,"lower_bound":108989.64292004907,"upper_bound":1876174.2377468045,"unit":"ns"},"slope":{"estimate":31303853.89004329,"lower_bound":30420351.36057043,"upper_bound":32102739.677119244,"unit":"ns"},"change":{"mean":{"estimate":-0.9259031882487296,"lower_bound":-0.9305094046118007,"upper_bound":-0.9206422404783118,"unit":"%"},"median":{"estimate":-0.926852975001608,"lower_bound":-0.931325999335721,"upper_bound":-0.9166641227130601,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_1000000","iteration_count":[6,12,18,24,30,36,42,48,54,60],"measured_values":[111553875.0,207288959.0,311476875.0,414722167.0,517945250.0,637749375.0,733010375.0,825896500.0,926161166.0,1036259459.0],"unit":"ns","throughput":[],"typical":{"estimate":17303880.214285713,"lower_bound":17212006.102217603,"upper_bound":17456341.402515724,"unit":"ns"},"mean":{"estimate":17451178.43715609,"lower_bound":17256475.23703704,"upper_bound":17736942.944285713,"unit":"ns"},"median":{"estimate":17277085.104166668,"lower_bound":17238584.03333333,"upper_bound":17509765.625,"unit":"ns"},"median_abs_dev":{"estimate":72716.89558401704,"lower_bound":6745.317147749628,"upper_bound":356275.9395748358,"unit":"ns"},"slope":{"estimate":17303880.214285713,"lower_bound":17212006.102217603,"upper_bound":17456341.402515724,"unit":"ns"},"change":{"mean":{"estimate":-0.8683813811923236,"lower_bound":-0.8783045967657279,"upper_bound":-0.8565042367466531,"unit":"%"},"median":{"estimate":-0.8679102403790255,"lower_bound":-0.8841517136386209,"upper_bound":-0.8519472185853121,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_1000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[118174375.0,254394625.0,385308916.0,561893083.0,659088084.0,782043042.0,906888875.0,1032976292.0,1198792125.0,1300024916.0],"unit":"ns","throughput":[],"typical":{"estimate":43653309.1974026,"lower_bound":43205112.12660984,"upper_bound":44250044.48168498,"unit":"ns"},"mean":{"estimate":43277286.46849205,"lower_bound":42154169.95920636,"upper_bound":44337357.00142857,"unit":"ns"},"median":{"estimate":43259674.1952381,"lower_bound":42719891.5,"upper_bound":43939205.6,"unit":"ns"},"median_abs_dev":{"estimate":835522.0485798541,"lower_bound":193961.98875648555,"upper_bound":2974334.1016533505,"unit":"ns"},"slope":{"estimate":43653309.1974026,"lower_bound":43205112.12660984,"upper_bound":44250044.48168498,"unit":"ns"},"change":{"mean":{"estimate":-0.7244581915909477,"lower_bound":-0.7410750185121298,"upper_bound":-0.7072158607164999,"unit":"%"},"median":{"estimate":-0.7243138132939773,"lower_bound":-0.7367488787189185,"upper_bound":-0.704323479834285,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_1000000","iteration_count":[6,12,18,24,30,36,42,48,54,60],"measured_values":[102656833.0,208275084.0,311191791.0,420131875.0,520374917.0,618091916.0,727908083.0,825663417.0,976896708.0,1031436500.0],"unit":"ns","throughput":[],"typical":{"estimate":17424604.0017316,"lower_bound":17211435.41709256,"upper_bound":17760868.739164695,"unit":"ns"},"mean":{"estimate":17358846.13791667,"lower_bound":17225031.53172222,"upper_bound":17545902.758055557,"unit":"ns"},"median":{"estimate":17309788.833333332,"lower_bound":17185270.538194444,"upper_bound":17425662.679166667,"unit":"ns"},"median_abs_dev":{"estimate":168755.56751023885,"lower_bound":18615.64881950709,"upper_bound":277301.2160102539,"unit":"ns"},"slope":{"estimate":17424604.0017316,"lower_bound":17211435.41709256,"upper_bound":17760868.739164695,"unit":"ns"},"change":{"mean":{"estimate":-0.009974561731766918,"lower_bound":-0.021364787760249988,"upper_bound":0.0035480852378329086,"unit":"%"},"median":{"estimate":-0.01383237043330865,"lower_bound":-0.028437591500036774,"upper_bound":-0.00018150635036928708,"unit":"%"},"change":"NoChange"}} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_1000000","iteration_count":[20,40,60,80,100,120,140,160,180,200],"measured_values":[92363625.0,186380333.0,273056458.0,378651042.0,462890708.0,564554833.0,666599042.0,726641167.0,827620125.0,935175000.0],"unit":"ns","throughput":[],"typical":{"estimate":4646796.639740259,"lower_bound":4592532.777392739,"upper_bound":4704879.908801498,"unit":"ns"},"mean":{"estimate":4647199.286065477,"lower_bound":4603980.199541667,"upper_bound":4690513.632380953,"unit":"ns"},"median":{"estimate":4644207.702500001,"lower_bound":4584561.108333333,"upper_bound":4704623.608333333,"unit":"ns"},"median_abs_dev":{"estimate":79121.9313278052,"lower_bound":22684.7025157668,"upper_bound":130364.24973733733,"unit":"ns"},"slope":{"estimate":4646796.639740259,"lower_bound":4592532.777392739,"upper_bound":4704879.908801498,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[108544750.0,211809875.0,326539042.0,471726042.0,574831708.0,650356000.0,824029000.0,945852333.0,995579209.0,1225960958.0],"unit":"ns","throughput":[],"typical":{"estimate":29045340.55779221,"lower_bound":27889319.427740864,"upper_bound":29980697.388670754,"unit":"ns"},"mean":{"estimate":28343813.29268849,"lower_bound":27534986.600697428,"upper_bound":29180686.775993306,"unit":"ns"},"median":{"estimate":28198281.713888887,"lower_bound":27136187.5,"upper_bound":29493746.27455357,"unit":"ns"},"median_abs_dev":{"estimate":1728296.7943165966,"lower_bound":84078.36805730873,"upper_bound":2278448.4273869544,"unit":"ns"},"slope":{"estimate":29045340.55779221,"lower_bound":27889319.427740864,"upper_bound":29980697.388670754,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_1000000","iteration_count":[5,10,15,20,25,30,35,40,45,50],"measured_values":[108743750.0,210253083.0,321599500.0,430525584.0,531467292.0,631428333.0,760199875.0,861037375.0,958719958.0,1058762375.0],"unit":"ns","throughput":[],"typical":{"estimate":21344342.185454544,"lower_bound":21205191.152941175,"upper_bound":21522287.16836735,"unit":"ns"},"mean":{"estimate":21377267.320579365,"lower_bound":21227310.325277776,"upper_bound":21528792.35252381,"unit":"ns"},"median":{"estimate":21372427.31111111,"lower_bound":21153151.39,"upper_bound":21622965.401785716,"unit":"ns"},"median_abs_dev":{"estimate":260219.7945901746,"lower_bound":63727.86105610614,"upper_bound":457802.16187238507,"unit":"ns"},"slope":{"estimate":21344342.185454544,"lower_bound":21205191.152941175,"upper_bound":21522287.16836735,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[86652208.0,174504833.0,263045000.0,358621708.0,461604500.0,551382875.0,617275334.0,705528042.0,792318667.0,916884375.0],"unit":"ns","throughput":[],"typical":{"estimate":44857749.1987013,"lower_bound":44157687.696186475,"upper_bound":45593836.629807696,"unit":"ns"},"mean":{"estimate":44577840.23829365,"lower_bound":43994895.55221726,"upper_bound":45210414.62857143,"unit":"ns"},"median":{"estimate":44093298.95535714,"lower_bound":43821955.98611111,"upper_bound":45844218.75,"unit":"ns"},"median_abs_dev":{"estimate":890675.8260123432,"lower_bound":60939.48615977487,"upper_bound":1661786.1416473947,"unit":"ns"},"slope":{"estimate":44857749.1987013,"lower_bound":44157687.696186475,"upper_bound":45593836.629807696,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_1000000","iteration_count":[5,10,15,20,25,30,35,40,45,50],"measured_values":[105195375.0,220300833.0,337805417.0,419863166.0,534265166.0,646023917.0,736887292.0,849578709.0,975518250.0,1077467959.0],"unit":"ns","throughput":[],"typical":{"estimate":21452114.204675324,"lower_bound":21249713.99514563,"upper_bound":21619440.779963892,"unit":"ns"},"mean":{"estimate":21500834.780690476,"lower_bound":21238293.671617858,"upper_bound":21802302.998125006,"unit":"ns"},"median":{"estimate":21452368.60333333,"lower_bound":21053922.62857143,"upper_bound":21789721.240000002,"unit":"ns"},"median_abs_dev":{"estimate":462764.4522242879,"lower_bound":56051.142834892424,"upper_bound":749733.4800375743,"unit":"ns"},"slope":{"estimate":21452114.204675324,"lower_bound":21249713.99514563,"upper_bound":21619440.779963892,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_1000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[137718416.0,276242041.0,406271750.0,550647750.0,653145291.0,800304459.0,943097125.0,1050158542.0,1205087250.0,1324228875.0],"unit":"ns","throughput":[],"typical":{"estimate":44389769.84242424,"lower_bound":44071300.25063955,"upper_bound":44811890.299578056,"unit":"ns"},"mean":{"estimate":44841929.1554762,"lower_bound":44318065.53269841,"upper_bound":45370072.08944444,"unit":"ns"},"median":{"estimate":44771124.00793651,"lower_bound":44108982.375,"upper_bound":45887312.5,"unit":"ns"},"median_abs_dev":{"estimate":1219200.965246524,"lower_bound":158331.68199405,"upper_bound":1579492.7621833999,"unit":"ns"},"slope":{"estimate":44389769.84242424,"lower_bound":44071300.25063955,"upper_bound":44811890.299578056,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/1000000","MATCH/match_decrypt/eql_cast_firstname/1000000","MATCH/match/eql_cast_lastname/1000000","MATCH/match_decrypt/eql_cast_lastname/1000000","MATCH/match/eql_bloom/1000000","MATCH/match_decrypt/eql_bloom/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH"} diff --git a/results/query/match_rows_10000000.json b/results/query/match_rows_10000000.json new file mode 100644 index 0000000..be177b8 --- /dev/null +++ b/results/query/match_rows_10000000.json @@ -0,0 +1,7 @@ +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_firstname/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_firstname_10000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[111041958.0,219267250.0,308583125.0,420331041.0,533163250.0,630845208.0,728483625.0,872527375.0,936985875.0,1068536417.0],"unit":"ns","throughput":[],"typical":{"estimate":35329332.39393939,"lower_bound":34829339.860888906,"upper_bound":35818395.11420144,"unit":"ns"},"mean":{"estimate":35483036.581468254,"lower_bound":34976477.192579366,"upper_bound":36026446.54277083,"unit":"ns"},"median":{"estimate":35295586.33333333,"lower_bound":34703180.55555555,"upper_bound":36355307.291666664,"unit":"ns"},"median_abs_dev":{"estimate":888296.5736962474,"lower_bound":250478.09082812734,"upper_bound":1495309.4795862772,"unit":"ns"},"slope":{"estimate":35329332.39393939,"lower_bound":34829339.860888906,"upper_bound":35818395.11420144,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_firstname/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_firstname_10000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[122998417.0,249862375.0,362520542.0,478672125.0,594595625.0,724144917.0,868100000.0,954454959.0,1107127042.0,1248087625.0],"unit":"ns","throughput":[],"typical":{"estimate":61169065.22077922,"lower_bound":60081365.00552076,"upper_bound":61910788.43001761,"unit":"ns"},"mean":{"estimate":60959589.73918651,"lower_bound":60288830.85333085,"upper_bound":61637557.648115076,"unit":"ns"},"median":{"estimate":60959649.41666667,"lower_bound":59834015.625,"upper_bound":62007142.85714286,"unit":"ns"},"median_abs_dev":{"estimate":1610939.1885876132,"lower_bound":267728.9225343615,"upper_bound":1905412.0039846748,"unit":"ns"},"slope":{"estimate":61169065.22077922,"lower_bound":60081365.00552076,"upper_bound":61910788.43001761,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_cast_lastname/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_cast_lastname_10000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[684310958.0,624505459.0,673523292.0,627330834.0,632473542.0,625673708.0,615057875.0,617592584.0,610422000.0,603910333.0],"unit":"ns","throughput":[],"typical":{"estimate":210493352.83333334,"lower_bound":205849658.05166668,"upper_bound":216161639.01583335,"unit":"ns"},"mean":{"estimate":210493352.83333334,"lower_bound":205849658.05166668,"upper_bound":216161639.01583335,"unit":"ns"},"median":{"estimate":208363194.5,"lower_bound":204669097.3333333,"upper_bound":216809021.0,"unit":"ns"},"median_abs_dev":{"estimate":4331343.669903293,"lower_bound":698150.150105372,"upper_bound":12506904.750058047,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_cast_lastname/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_cast_lastname_10000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[679046625.0,694819208.0,701414167.0,707026209.0,707030750.0,807709250.0,709258125.0,726795667.0,723585500.0,781076917.0],"unit":"ns","throughput":[],"typical":{"estimate":241258747.2666667,"lower_bound":234207558.3666667,"upper_bound":249760260.5408333,"unit":"ns"},"mean":{"estimate":241258747.2666667,"lower_bound":234207558.3666667,"upper_bound":249760260.5408333,"unit":"ns"},"median":{"estimate":236048145.8333333,"lower_bound":233640902.8333333,"upper_bound":250777069.5,"unit":"ns"},"median_abs_dev":{"estimate":7108150.6270051,"lower_bound":552628.5148888532,"upper_bound":19264049.586194783,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"MATCH/match/eql_bloom/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_eql_bloom_10000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[734535792.0,701544291.0,609766334.0,636766292.0,621721292.0,620038584.0,627025042.0,632955458.0,659997375.0,627256250.0],"unit":"ns","throughput":[],"typical":{"estimate":215720223.66666666,"lower_bound":208707633.6525,"upper_bound":224320887.5333333,"unit":"ns"},"mean":{"estimate":215720223.66666666,"lower_bound":208707633.6525,"upper_bound":224320887.5333333,"unit":"ns"},"median":{"estimate":210035284.66666666,"lower_bound":207240430.66666666,"upper_bound":223051763.8333333,"unit":"ns"},"median_abs_dev":{"estimate":4559447.6062536165,"lower_bound":1367688.0975186825,"upper_bound":19331837.022191294,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"MATCH/match_decrypt/eql_bloom/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH/match_decrypt_eql_bloom_10000000","iteration_count":[3,3,3,3,3,3,3,3,3,3],"measured_values":[769165000.0,718551833.0,726085125.0,730922292.0,689377708.0,682644209.0,686239166.0,706592041.0,726438250.0,698718667.0],"unit":"ns","throughput":[],"typical":{"estimate":237824476.36666664,"lower_bound":232957038.9666667,"upper_bound":243310805.03500003,"unit":"ns"},"mean":{"estimate":237824476.36666664,"lower_bound":232957038.9666667,"upper_bound":243310805.03500003,"unit":"ns"},"median":{"estimate":237523979.0,"lower_bound":229792569.33333334,"upper_bound":242834569.5,"unit":"ns"},"median_abs_dev":{"estimate":7960738.521468647,"lower_bound":1282521.1304307058,"upper_bound":16279328.739184096,"unit":"ns"},"slope":null,"change":null} +{"reason":"group-complete","group_name":"MATCH","benchmarks":["MATCH/match/eql_cast_firstname/10000000","MATCH/match_decrypt/eql_cast_firstname/10000000","MATCH/match/eql_cast_lastname/10000000","MATCH/match_decrypt/eql_cast_lastname/10000000","MATCH/match/eql_bloom/10000000","MATCH/match_decrypt/eql_bloom/10000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/MATCH"} diff --git a/results/query/ore_metadata_10000.json b/results/query/ore_metadata_10000.json new file mode 100644 index 0000000..22a049a --- /dev/null +++ b/results/query/ore_metadata_10000.json @@ -0,0 +1,479 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6505e5d0db03c5dd653e9ad5bbbf37b01663a79c310597f2cca4feea88f7f863fdf7e0a642334bc851ef546007bab4c16748773788325e7693c2983f64e84420fefe66ebd55fba175369ff1cb035880cace69ada40eaa9c4e562258c34290667bbe9f9e089e37dee0a7fa68a1d6ecbb0e227b1711af6f0c662e7b9f665d2460a0460e1c7c84171e8115895dca66cfde0a3d5c59e35674c512b243ce1e9d6a2ec34d88a8d54d49cb3ed640b680b20d58dd07744ee54fcccb4e383b625ffacc120fe18629047851013df66e79cccf101ba839bb63c98bfa01121a41bf239c283e288df5d9730e3f463e905c464c9f7be623a47c2b4f9f948270cd132c67cbb3ef0e32320e83d411a6b4427aed3f657e7d\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7766.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } + ], + "id": "ORE/ore/range_gt_10/10000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6505e5d0db03c5dd653e9ad5bbbf37b01663a79c310597f2cca4feea88f7f863fdf7e0a642334bc851ef546007bab4c16748773788325e7693c2983f64e84420fefe66ebd55fba175369ff1cb035880cace69ada40eaa9c4e562258c34290667bbe9f9e089e37dee0a7fa68a1d6ecbb0e227b1711af6f0c662e7b9f665d2460a0460e1c7c84171e8115895dca66cfde0a3d5c59e35674c512b243ce1e9d6a2ec34d88a8d54d49cb3ed640b680b20d58dd07744ee54fcccb4e383b625ffacc120fe18629047851013df66e79cccf101ba839bb63c98bfa01121a41bf239c283e288df5d9730e3f463e905c464c9f7be623a47c2b4f9f948270cd132c67cbb3ef0e32320e83d411a6b4427aed3f657e7d" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf77977b33152775a0849e0fb9e90d1b5724a136449d77f85f9623e8a6ee61f10e0d8f485ea13f3e7522cfed28560e0a59a0c03c4b547b09f9da863d6889b7453b1c0c0e5b54222a6259b22ed2b98f752603ce6628b08da4e993c6165b3d7fdaf8ae72965268d0e524c2f0603d44d47e9c0fb410e16e2b1a4ee3cdd465a2c541aad8cc6273d11c66daf989bbd1b1536b816041cb55ab273f1882f078247272f15ccd5e7a1293dcfc299aa809bb595a54eb89afe5f91948671bf96d684828b23d22f6ce70c119dadf107c6882a2c9c7fc478dc285f3c3268ceb2fea1f52e991aae7182e4422c8e41c3e1b07844a705c7687118ea35ab9c896c944fdf4298ad5825005f80ecbaaad437e4bd489ff0d1441e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7766.5 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.9 + } + } + ], + "id": "ORE/ore/range_gt_100/10000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf77977b33152775a0849e0fb9e90d1b5724a136449d77f85f9623e8a6ee61f10e0d8f485ea13f3e7522cfed28560e0a59a0c03c4b547b09f9da863d6889b7453b1c0c0e5b54222a6259b22ed2b98f752603ce6628b08da4e993c6165b3d7fdaf8ae72965268d0e524c2f0603d44d47e9c0fb410e16e2b1a4ee3cdd465a2c541aad8cc6273d11c66daf989bbd1b1536b816041cb55ab273f1882f078247272f15ccd5e7a1293dcfc299aa809bb595a54eb89afe5f91948671bf96d684828b23d22f6ce70c119dadf107c6882a2c9c7fc478dc285f3c3268ceb2fea1f52e991aae7182e4422c8e41c3e1b07844a705c7687118ea35ab9c896c944fdf4298ad5825005f80ecbaaad437e4bd489ff0d1441e" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bceda16bf25f19b2ba0c94d71aae8910336edbe8f825a9f1be66459c95f7d5ce637ffd968733af28c55772302718b1537642462eae63269ca3e1b1806a4285ea492b8b37638b391569cf41a9958e7c039252ea8645bcdb8b1104998e7eec88bb77ca2eca6e5c67125bff1dbb77ba8545eec1a301162fef42843b650e8f058ba0c1a91e9cb871057791d996b8de16fcb07d261a98f909f2be733592615197af1670d7d9d0691d9615721cd2a76f48db165128a311ba268e1cf2c26039f0b2c48bcaca64d340d0dbd03b7cbe0c44cdf32e9deb4fc11ceea9c799693678136e8a8934a696410c4dd99dc339af41270c2b5fa709e60ba4768d1440d612f7895df7724840a5c6f493f382091b10f8aadc17d266\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7791.25 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } + ], + "id": "ORE/ore/range_lt_10/10000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bceda16bf25f19b2ba0c94d71aae8910336edbe8f825a9f1be66459c95f7d5ce637ffd968733af28c55772302718b1537642462eae63269ca3e1b1806a4285ea492b8b37638b391569cf41a9958e7c039252ea8645bcdb8b1104998e7eec88bb77ca2eca6e5c67125bff1dbb77ba8545eec1a301162fef42843b650e8f058ba0c1a91e9cb871057791d996b8de16fcb07d261a98f909f2be733592615197af1670d7d9d0691d9615721cd2a76f48db165128a311ba268e1cf2c26039f0b2c48bcaca64d340d0dbd03b7cbe0c44cdf32e9deb4fc11ceea9c799693678136e8a8934a696410c4dd99dc339af41270c2b5fa709e60ba4768d1440d612f7895df7724840a5c6f493f382091b10f8aadc17d266" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value < $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc981f0239ae333c99d66e5d01c963193aaa470df62b2cf1d8fadc9dacfefbf678db1d341af31e204af6bedb5687884f5926aecccff21542589f17ccd5d92f58039d7cb9bc26558dcbe00ad147970e8efd3c8dfe3c269ecd91a9eebd4169d2509d9c9593ce79991fa754adee5102cb0f6bd53e197d022d06f31e56e1a7c964b87fd1e2de5c0e3a5c7bc2bf8dde1b96b79bde395c2bae3528d2b8f03bbe012db7858b2fcdfd76140c593eefbfbcb6f096f7e267094ebcbfcf2b97e1d63355f7402900e78841ae4d014f529dc4ac6726ceefd7f53b331dac99225d26122bc018fb3ef32ef60e18632be85cce7c73801c2094c8eb1f0c966755c54c626568cf3c01bd6f9968d16011a17308379262242d3faf\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 0.0, + "Total Cost": 7791.25 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.31 + } + } + ], + "id": "ORE/ore/range_lt_100/10000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc981f0239ae333c99d66e5d01c963193aaa470df62b2cf1d8fadc9dacfefbf678db1d341af31e204af6bedb5687884f5926aecccff21542589f17ccd5d92f58039d7cb9bc26558dcbe00ad147970e8efd3c8dfe3c269ecd91a9eebd4169d2509d9c9593ce79991fa754adee5102cb0f6bd53e197d022d06f31e56e1a7c964b87fd1e2de5c0e3a5c7bc2bf8dde1b96b79bde395c2bae3528d2b8f03bbe012db7858b2fcdfd76140c593eefbfbcb6f096f7e267094ebcbfcf2b97e1d63355f7402900e78841ae4d014f529dc4ac6726ceefd7f53b331dac99225d26122bc018fb3ef32ef60e18632be85cce7c73801c2094c8eb1f0c966755c54c626568cf3c01bd6f9968d16011a17308379262242d3faf" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value < $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 50, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 36, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91dae460933df85e4969c1af944c2e28978bc4808c2e4f10131b732b607dac7eb48f29e66b0599ad7182328009dd2b61f89ba48fd10657e90a6c1f16fd41e97fbaf99a11818257f963c1bc6eecde30663acdc615d65a0653b21704d00ff0a3173de2d878f31fcfdc9c34c77ebc71b41f1e4f0dd617395e5797ae691fc2e5864765f567790a9db72d781467b7f6e1b83cef0fb5a34b54983d0a195334289bf80c6f03ea0c7a1011e4c0177758c82b54eb4b5cd429895f5f79bba741349e330d04b4c5fea589b5765cc5a8584e55c86728e0cc19ef5c808bec946522e12d6c97d690da317f5f493c51d0eb8ee79a859e2864d057a50c5cfc93cc0807e18b9aaa251e349afc80ff526bcbf63b9dc41ffc567\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91dae460933df85e4969c1af944c2e28978bc4808c2e4f10131b732b607dac7eb48f29e66b0599ad7182328009dd2b61f89ba48fd10657e90a6c1f16fd41e97fbaf99a11818257f963c1bc6eecde30663acdc615d65a0653b21704d00ff0a3173de2d878f31fcfdc9c34c77ebc71b41f1e4f0dd617395e5797ae691fc2e5864765f567790a9db72d781467b7f6e1b83cef0fb5a34b54983d0a195334289bf80c6f03ea0c7a1011e4c0177758c82b54eb4b5cd429895f5f79bba741349e330d04b4c5fea589b5765cc5a8584e55c86728e0cc19ef5c808bec946522e12d6c97d690da317f5f493c51d0eb8ee79a859e2864d057a50c5cfc93cc0807e18b9aaa251e349afc80ff526bcbf63b9dc41ffc567\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 226.86 + } + ], + "Startup Cost": 16.92, + "Total Cost": 226.86 + } + } + ], + "id": "ORE/ore/range_selective_gt_100/10000", + "indexes_used": [ + "integer_encrypted_10000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91dae460933df85e4969c1af944c2e28978bc4808c2e4f10131b732b607dac7eb48f29e66b0599ad7182328009dd2b61f89ba48fd10657e90a6c1f16fd41e97fbaf99a11818257f963c1bc6eecde30663acdc615d65a0653b21704d00ff0a3173de2d878f31fcfdc9c34c77ebc71b41f1e4f0dd617395e5797ae691fc2e5864765f567790a9db72d781467b7f6e1b83cef0fb5a34b54983d0a195334289bf80c6f03ea0c7a1011e4c0177758c82b54eb4b5cd429895f5f79bba741349e330d04b4c5fea589b5765cc5a8584e55c86728e0cc19ef5c808bec946522e12d6c97d690da317f5f493c51d0eb8ee79a859e2864d057a50c5cfc93cc0807e18b9aaa251e349afc80ff526bcbf63b9dc41ffc567" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value > $1 LIMIT 100", + "rows_returned": 21 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3670b0657354ad4a7421ca41d370e370ff590a6b30fe2af4027fa71292f0e45ac799af17fb03cafe6be194889d475340b068b3fae2b2c12943b5c72e09c2e8299fc9549f3d90e06beb4b7e115ff92c5d982130fceb631a012c1322f858a5426a8765e9803d47a570d7d4b3bc9c311122d9c8dd1235314b4b423d38be0ca0203f990b9610edfe06e1f081c5a36c43316ef6394f9e76b4460031fcb6f0e20a2c90b0801c50a2663bf5f442d47d59266e3279dfaf34b249b4e60518b671af379d156f42f6311b475dbaae20f9db0a1db11a29231de62e70bf65889b9395cb4b00fc9056dfc254cea86d313be589ed5a46fe921ad46fb991ff6bc3b6784eef66189b75e6d0e00661387099c3b52495247cc159\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.54, + "Total Cost": 229.9 + } + ], + "Startup Cost": 0.54, + "Total Cost": 46.41 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_10/10000", + "indexes_used": [ + "integer_encrypted_10000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3670b0657354ad4a7421ca41d370e370ff590a6b30fe2af4027fa71292f0e45ac799af17fb03cafe6be194889d475340b068b3fae2b2c12943b5c72e09c2e8299fc9549f3d90e06beb4b7e115ff92c5d982130fceb631a012c1322f858a5426a8765e9803d47a570d7d4b3bc9c311122d9c8dd1235314b4b423d38be0ca0203f990b9610edfe06e1f081c5a36c43316ef6394f9e76b4460031fcb6f0e20a2c90b0801c50a2663bf5f442d47d59266e3279dfaf34b249b4e60518b671af379d156f42f6311b475dbaae20f9db0a1db11a29231de62e70bf65889b9395cb4b00fc9056dfc254cea86d313be589ed5a46fe921ad46fb991ff6bc3b6784eef66189b75e6d0e00661387099c3b52495247cc159" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value > $1 LIMIT 10", + "rows_returned": 3 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc14347b7005145baed64bf5fd2b8c091f589680a0075cc7b0ffc370b8403d88e39ef58e2e11513beaeb537b61e17653181c5098ad15b1b4938d2295de2d7182221083e77a080cf8d5811fcbbbb8915865d1c1ca4f1ee713737a75b21e2874b003d9a5e9ec064049a77b210642d44390b830b7ed1001be4cdeed88ba168bc01d5714ddac2c8ba033bd00da6aa4eea70669b3ca6214f798d3abca3debbbdc0aac1bd8110a55015cd6dc522f8e1fe161cb6de2b1f60456d5041488cd50dc15f9ddec1076b2202a0291c2a34a28459ffc061ef95890d8829788296cb6a4c54c8ed3e6c886fce7a37ed38c84c42f83f79eb0581b6592858e80879d01d855bcb646e76612af9987ffdf73d0d65127b8409d5388\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5049, + "Plan Width": 68, + "Relation Name": "integer_encrypted_10000", + "Scan Direction": "Forward", + "Startup Cost": 0.54, + "Total Cost": 9909.19 + } + ], + "Startup Cost": 0.54, + "Total Cost": 20.16 + } + } + ], + "id": "ORE/ore/range_lt_hybrid_ordered_10/10000", + "indexes_used": [ + "integer_encrypted_10000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc14347b7005145baed64bf5fd2b8c091f589680a0075cc7b0ffc370b8403d88e39ef58e2e11513beaeb537b61e17653181c5098ad15b1b4938d2295de2d7182221083e77a080cf8d5811fcbbbb8915865d1c1ca4f1ee713737a75b21e2874b003d9a5e9ec064049a77b210642d44390b830b7ed1001be4cdeed88ba168bc01d5714ddac2c8ba033bd00da6aa4eea70669b3ca6214f798d3abca3debbbdc0aac1bd8110a55015cd6dc522f8e1fe161cb6de2b1f60456d5041488cd50dc15f9ddec1076b2202a0291c2a34a28459ffc061ef95890d8829788296cb6a4c54c8ed3e6c886fce7a37ed38c84c42f83f79eb0581b6592858e80879d01d855bcb646e76612af9987ffdf73d0d65127b8409d5388" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000 WHERE value < $1 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91a80367663852bdfcbc395253c06c9c19d4bb4234c922426de81be8473af8ab59a928fbff4b7f6f70d275c6b00206fb739b00718ed29aeebbbad1fa73bd2ed0789d978867c805e75a42d2517e204e9a807d88bd71a40c8c975cf9bafef627ffefdd245ebb16b7959f956a5916e058dc6f757866458c67afb9f17f60aa1fa4366d91f9ed39cc0d642c80329c3d762ed4a70d7818ac373604b2a15f1efcdb7af4605006becd7e953169cf2c0a1ef5c970875ce3c033f1d15e9ae7c04ef0e0674774397cddbaedbb588d1ad491ea5e1d74bb13f55290e2e9ea95cce66ee2f7e36963557a39358de046dd56a7d263254b0abde73b81fcab424245c1a5aaaf4c6d29ea997cecf2ccc24eeb8fa1181ee17c050\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91a80367663852bdfcbc395253c06c9c19d4bb4234c922426de81be8473af8ab59a928fbff4b7f6f70d275c6b00206fb739b00718ed29aeebbbad1fa73bd2ed0789d978867c805e75a42d2517e204e9a807d88bd71a40c8c975cf9bafef627ffefdd245ebb16b7959f956a5916e058dc6f757866458c67afb9f17f60aa1fa4366d91f9ed39cc0d642c80329c3d762ed4a70d7818ac373604b2a15f1efcdb7af4605006becd7e953169cf2c0a1ef5c970875ce3c033f1d15e9ae7c04ef0e0674774397cddbaedbb588d1ad491ea5e1d74bb13f55290e2e9ea95cce66ee2f7e36963557a39358de046dd56a7d263254b0abde73b81fcab424245c1a5aaaf4c6d29ea997cecf2ccc24eeb8fa1181ee17c050\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 214.36 + } + ], + "Startup Cost": 214.49, + "Strategy": "Plain", + "Total Cost": 214.5 + } + } + ], + "id": "ORE/ore/range_selective_gt_count/10000", + "indexes_used": [ + "integer_encrypted_10000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b91a80367663852bdfcbc395253c06c9c19d4bb4234c922426de81be8473af8ab59a928fbff4b7f6f70d275c6b00206fb739b00718ed29aeebbbad1fa73bd2ed0789d978867c805e75a42d2517e204e9a807d88bd71a40c8c975cf9bafef627ffefdd245ebb16b7959f956a5916e058dc6f757866458c67afb9f17f60aa1fa4366d91f9ed39cc0d642c80329c3d762ed4a70d7818ac373604b2a15f1efcdb7af4605006becd7e953169cf2c0a1ef5c970875ce3c033f1d15e9ae7c04ef0e0674774397cddbaedbb588d1ad491ea5e1d74bb13f55290e2e9ea95cce66ee2f7e36963557a39358de046dd56a7d263254b0abde73b81fcab424245c1a5aaaf4c6d29ea997cecf2ccc24eeb8fa1181ee17c050" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_10000 WHERE value > $1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36ca01feb59b53a7fd3ec6c294403e0cae2f48e415c42c793a57bca9c9401973eb8ec69c36c2666090eec127850a13fa5739a8b2a4355604b79b3cfedb0230770970707cb62140e7e842ebfd292cfe957f0fa584e76cb7234fdaa826b1f97a98f10afbbc2cae030607a9450893cbd7b464ed9d61c8beeb67a0bc3e125d8911d9091e2b3525dd5ceae3cb99153363aebed8d9184296d198d25b68c82ba42bf1e193d97bbd2f3c58c359d48efd3aa1468f83b720cfba85742b14e70818e39a881303cf1e38f2a3b5c86b7380485e0fb0a79de67098e2c9aa8a7f3f587b86d4f87b2931f5a69d65ebd8d01fc3c65496cbc73d02888eb69744d8c06f28f1a6ffb93d854a252ba483dbf1d79cc7ba4a6829b3c4\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 16.91 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36ca01feb59b53a7fd3ec6c294403e0cae2f48e415c42c793a57bca9c9401973eb8ec69c36c2666090eec127850a13fa5739a8b2a4355604b79b3cfedb0230770970707cb62140e7e842ebfd292cfe957f0fa584e76cb7234fdaa826b1f97a98f10afbbc2cae030607a9450893cbd7b464ed9d61c8beeb67a0bc3e125d8911d9091e2b3525dd5ceae3cb99153363aebed8d9184296d198d25b68c82ba42bf1e193d97bbd2f3c58c359d48efd3aa1468f83b720cfba85742b14e70818e39a881303cf1e38f2a3b5c86b7380485e0fb0a79de67098e2c9aa8a7f3f587b86d4f87b2931f5a69d65ebd8d01fc3c65496cbc73d02888eb69744d8c06f28f1a6ffb93d854a252ba483dbf1d79cc7ba4a6829b3c4\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000", + "Startup Cost": 16.92, + "Total Cost": 214.36 + } + ], + "Startup Cost": 214.49, + "Strategy": "Plain", + "Total Cost": 214.5 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_count/10000", + "indexes_used": [ + "integer_encrypted_10000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36ca01feb59b53a7fd3ec6c294403e0cae2f48e415c42c793a57bca9c9401973eb8ec69c36c2666090eec127850a13fa5739a8b2a4355604b79b3cfedb0230770970707cb62140e7e842ebfd292cfe957f0fa584e76cb7234fdaa826b1f97a98f10afbbc2cae030607a9450893cbd7b464ed9d61c8beeb67a0bc3e125d8911d9091e2b3525dd5ceae3cb99153363aebed8d9184296d198d25b68c82ba42bf1e193d97bbd2f3c58c359d48efd3aa1468f83b720cfba85742b14e70818e39a881303cf1e38f2a3b5c86b7380485e0fb0a79de67098e2c9aa8a7f3f587b86d4f87b2931f5a69d65ebd8d01fc3c65496cbc73d02888eb69744d8c06f28f1a6ffb93d854a252ba483dbf1d79cc7ba4a6829b3c4" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_10000 WHERE value > $1", + "rows_returned": 1 + } + ], + "target_rows": "10000" +} \ No newline at end of file diff --git a/results/query/ore_metadata_100000.json b/results/query/ore_metadata_100000.json new file mode 100644 index 0000000..f1f7a69 --- /dev/null +++ b/results/query/ore_metadata_100000.json @@ -0,0 +1,467 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcbfbaaf8c7a29ce322f2feca2f5d3c6e328479bb189afe2e41b80a02090795ddbb699a2e1bffcd2230148afe271b8c45a54f37c24a512ac8a25770563056b21c1d266bc81d1f57e26823716a03123c9ab2eb62ad6638179e7fa5e5e429a09c6462b4f91bf55a6a67dee3ec8989db162b9043b601675f777bfbdb67ae8099a830b561298bdf02bcde34e856ee07d24b63ecb4aa992f069413c89977f7f843a352873a8d9b8dcee7f144d2777d467d872804291cdfbc6a23e2e0a5d2e6577a575de6c23eacec41b5fb2a12749cec33753d81e6e51d58ad801dcb4f8f2ea4e52591bf9f3ed15f7ab4f3ae314bfa07216e11091fbd9752548b51cbd1b595653eb340ad259388bbdb8187a324e364151bf267c\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77911.0 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } + ], + "id": "ORE/ore/range_gt_10/100000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcbfbaaf8c7a29ce322f2feca2f5d3c6e328479bb189afe2e41b80a02090795ddbb699a2e1bffcd2230148afe271b8c45a54f37c24a512ac8a25770563056b21c1d266bc81d1f57e26823716a03123c9ab2eb62ad6638179e7fa5e5e429a09c6462b4f91bf55a6a67dee3ec8989db162b9043b601675f777bfbdb67ae8099a830b561298bdf02bcde34e856ee07d24b63ecb4aa992f069413c89977f7f843a352873a8d9b8dcee7f144d2777d467d872804291cdfbc6a23e2e0a5d2e6577a575de6c23eacec41b5fb2a12749cec33753d81e6e51d58ad801dcb4f8f2ea4e52591bf9f3ed15f7ab4f3ae314bfa07216e11091fbd9752548b51cbd1b595653eb340ad259388bbdb8187a324e364151bf267c" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3943e443c9ca6f4a982f878e9289d6a48ac5f9ef9aa8d64610a04e000b51a7a85953d8d28eb42c358a9bcb0b42258c2aa8df440203737f4ecbc1d7dcfd885d9a18e8a0c1f7e6faf95ed6107733228ec20d2f416ef1b95dc6a92d119ac82e0f83bb9e9a8adcac7b037e751ce2182b695ed8903ab442c10b38a96249e1b0775ccd94ae45b14329e72262fb9c5e28b917f68c32a7b22df72e08df89f928b2342ed47719918426305f4f80b36ec1313156ea576bbbc3c51666af80c1bec0a677dfdb264d13cd09c2b84b1eb7d3555811ba9e436f2c22429952e9f2e4e5258e62f70d3290cf6ecbd6e7ceb95dfe74ef647c9a8a09e9366682d1e0b9d532a305bfd5c1ece2f3d9ad55c2b32df39f76a540a267\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77911.0 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } + ], + "id": "ORE/ore/range_gt_100/100000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3943e443c9ca6f4a982f878e9289d6a48ac5f9ef9aa8d64610a04e000b51a7a85953d8d28eb42c358a9bcb0b42258c2aa8df440203737f4ecbc1d7dcfd885d9a18e8a0c1f7e6faf95ed6107733228ec20d2f416ef1b95dc6a92d119ac82e0f83bb9e9a8adcac7b037e751ce2182b695ed8903ab442c10b38a96249e1b0775ccd94ae45b14329e72262fb9c5e28b917f68c32a7b22df72e08df89f928b2342ed47719918426305f4f80b36ec1313156ea576bbbc3c51666af80c1bec0a677dfdb264d13cd09c2b84b1eb7d3555811ba9e436f2c22429952e9f2e4e5258e62f70d3290cf6ecbd6e7ceb95dfe74ef647c9a8a09e9366682d1e0b9d532a305bfd5c1ece2f3d9ad55c2b32df39f76a540a267" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcaa6d7dda1508dcb025ba4530f8c3283179584ab0db22d5f36e29f6ecec3892e371e95c1cb17c18fd442b575b22772c54a8f37e09eecc2b7ebd17426304de2d8c3d51b8b751081eb9681847729ec9fe0f6126b2d97d6606391df657ebd98df675340fe7813d96d776ceeefdbeabd6b602ba4d42e0d56c08a164cb88a1c14d81d49e4a88c62d536e581ecbe33674dbe0e97a9d22a8b3349e133bc2c0641086d916143b94c13c91426c0bc9ff4c365f07bdcd95a441f89de86a5d67b6ac1c0c03e7d9d744a045ccc675536d3d1e929381be28eda544056e9c8106f7062e69e6442dba0aa8af37a4c53298a24e7b08c0ca08434d405bb77041336f27d8aec49fb16f101fec1a03dd72fc9f28a6e5084d02dd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77660.75 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } + ], + "id": "ORE/ore/range_lt_10/100000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcaa6d7dda1508dcb025ba4530f8c3283179584ab0db22d5f36e29f6ecec3892e371e95c1cb17c18fd442b575b22772c54a8f37e09eecc2b7ebd17426304de2d8c3d51b8b751081eb9681847729ec9fe0f6126b2d97d6606391df657ebd98df675340fe7813d96d776ceeefdbeabd6b602ba4d42e0d56c08a164cb88a1c14d81d49e4a88c62d536e581ecbe33674dbe0e97a9d22a8b3349e133bc2c0641086d916143b94c13c91426c0bc9ff4c365f07bdcd95a441f89de86a5d67b6ac1c0c03e7d9d744a045ccc675536d3d1e929381be28eda544056e9c8106f7062e69e6442dba0aa8af37a4c53298a24e7b08c0ca08434d405bb77041336f27d8aec49fb16f101fec1a03dd72fc9f28a6e5084d02dd" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value < $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1c2266c60d3f36b6fec5b21c89ab896040fdcebe88c40452415319fbf1105cdc7fcb7a7b777f1357c695bf6c21c1002124c4e8195aade6ea2e0cc76a6aad644587ac052d449bdeb7eb2b6a4689bc34cea01fc52422cb7a2e816c8e27b87d26c1af5ee9d9a3dd1e66b3d65b59d4808307ff87f869f4e7e2b38c974414242243d321317ab87c8b111901468c4f8f94f377ca888e719e08a6dfa57b3b1be60a1e263b350f4eacde5727edabb2a2be584febfafe0d22ece42e758b818ba3afa824f43b905fa626164dfacacd011d54c8594feaf7ac4faf0c2f43944f8f6f739d27293e75a09c7aeaf4e5d326ae9e4f5c3d01009b14effabb4e6b28e60998e387b55f09d06171bd6d4187011f6abf4292b954\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 0.0, + "Total Cost": 77660.75 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } + ], + "id": "ORE/ore/range_lt_100/100000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1c2266c60d3f36b6fec5b21c89ab896040fdcebe88c40452415319fbf1105cdc7fcb7a7b777f1357c695bf6c21c1002124c4e8195aade6ea2e0cc76a6aad644587ac052d449bdeb7eb2b6a4689bc34cea01fc52422cb7a2e816c8e27b87d26c1af5ee9d9a3dd1e66b3d65b59d4808307ff87f869f4e7e2b38c974414242243d321317ab87c8b111901468c4f8f94f377ca888e719e08a6dfa57b3b1be60a1e263b350f4eacde5727edabb2a2be584febfafe0d22ece42e758b818ba3afa824f43b905fa626164dfacacd011d54c8594feaf7ac4faf0c2f43944f8f6f739d27293e75a09c7aeaf4e5d326ae9e4f5c3d01009b14effabb4e6b28e60998e387b55f09d06171bd6d4187011f6abf4292b954" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value < $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9358a15a5e641746b7c6b66e189423d4c88a64df34327a742e1ece8193d81f95d623e0dfd605ded1cdb56a0690278539530b9d2c2437dcc5bf6c7811fe180ca2b2290c0ed9dec1a8c7c9370dc255211b22c425a0a074c63b77b441a0b4eacdfbe703fa8abf7ca3d5a53d4f9c796d8129d90bc964f7a9f92f38560e4c5bd3a1e774bf50bcad83d1ad8346da0b6228f28030edf79ee04a6445ccef6208586fba71e916b61706536965a95cceab3c54a89478da21a3d6c88d86845a142501a1f80d9a18d33fbee14ec3b393ae83304e7d3b4f64ee3a20e45395ba1ca08b86bdc553e22b4583c26b8e66db16f0eeafaf24ef3295156365e60099fba4b0c2f4a946c9cfc7415acb93a1061ecc738114f45caa0\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 2258.41 + } + ], + "Startup Cost": 0.67, + "Total Cost": 452.22 + } + } + ], + "id": "ORE/ore/range_selective_gt_100/100000", + "indexes_used": [ + "integer_encrypted_100000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9358a15a5e641746b7c6b66e189423d4c88a64df34327a742e1ece8193d81f95d623e0dfd605ded1cdb56a0690278539530b9d2c2437dcc5bf6c7811fe180ca2b2290c0ed9dec1a8c7c9370dc255211b22c425a0a074c63b77b441a0b4eacdfbe703fa8abf7ca3d5a53d4f9c796d8129d90bc964f7a9f92f38560e4c5bd3a1e774bf50bcad83d1ad8346da0b6228f28030edf79ee04a6445ccef6208586fba71e916b61706536965a95cceab3c54a89478da21a3d6c88d86845a142501a1f80d9a18d33fbee14ec3b393ae83304e7d3b4f64ee3a20e45395ba1ca08b86bdc553e22b4583c26b8e66db16f0eeafaf24ef3295156365e60099fba4b0c2f4a946c9cfc7415acb93a1061ecc738114f45caa0" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36be52a8e1a0ba9ecad24828bfb15d8aba9d468853d6224316b9899ee388a0e35b84e9617e64f848ff68574fec6d156cd2c5e65253ed45558cda5b28324f5da2edd5d7858baadc96ee0f670887a7e7ef91815b506074bb0bbb390d2c101f30cd2212650fb306e18af5014af77ac727d7fe921145425de18f46d170d9d09f69c7e94191a4d9f3fc0b90bcd30e25d306a1d4d38276b35483d076745c11eebf13cf73b71ab4204ff2e1e372c01f2b90e9c6f3ae24d60b67d8a63796665e005ce57e9a69e00d1c8de465d52942972eba441695c6a52fc4c8fa6fd89c06044ef8857624f8ccdb2329040d4e9a043a335c8bb7db8f94c790b501c3d67993f6f9ba9d1525574a92f099e499d1e2a5843a986f9124\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 36, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 2258.41 + } + ], + "Startup Cost": 0.67, + "Total Cost": 45.82 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_10/100000", + "indexes_used": [ + "integer_encrypted_100000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36be52a8e1a0ba9ecad24828bfb15d8aba9d468853d6224316b9899ee388a0e35b84e9617e64f848ff68574fec6d156cd2c5e65253ed45558cda5b28324f5da2edd5d7858baadc96ee0f670887a7e7ef91815b506074bb0bbb390d2c101f30cd2212650fb306e18af5014af77ac727d7fe921145425de18f46d170d9d09f69c7e94191a4d9f3fc0b90bcd30e25d306a1d4d38276b35483d076745c11eebf13cf73b71ab4204ff2e1e372c01f2b90e9c6f3ae24d60b67d8a63796665e005ce57e9a69e00d1c8de465d52942972eba441695c6a52fc4c8fa6fd89c06044ef8857624f8ccdb2329040d4e9a043a335c8bb7db8f94c790b501c3d67993f6f9ba9d1525574a92f099e499d1e2a5843a986f9124" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value > $1 LIMIT 10", + "rows_returned": 8 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc45bfb34f421b183dbc0afce3324395f8bef03f4e86acd2d9873d90821dc67ee31528425717dd7ab738e15f40335adcdc3460689f78a87b3db6030b688cda7c956ced6821448aca5d76a79c74742ab7fc12523bdd5a82c94083a5faf23c56b77c0ab28ef07cb4fac38cd5059659a362986d4f172f43e3ed178b00925553d54b5a63f17f625b6e99cb9af47e1b2cded836d6f8d160fb9c4f329c684bd947b22f2cfec1fca5ee9a194ff77a41f351cfd33a4412fc82acd01de3347123f23dd773f6e4427dbea13f354adc736dc7f592d97d68349758f1c25e889fcce2a04c3d6c3bee1fc2ea724dde039c2f7b817e5ef7549a198ac130d560296230209d4c52ca200438f350a726ffb9231d9b70100fb30e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 49499, + "Plan Width": 68, + "Relation Name": "integer_encrypted_100000", + "Scan Direction": "Forward", + "Startup Cost": 0.67, + "Total Cost": 98196.21 + } + ], + "Startup Cost": 0.67, + "Total Cost": 20.51 + } + } + ], + "id": "ORE/ore/range_lt_hybrid_ordered_10/100000", + "indexes_used": [ + "integer_encrypted_100000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc45bfb34f421b183dbc0afce3324395f8bef03f4e86acd2d9873d90821dc67ee31528425717dd7ab738e15f40335adcdc3460689f78a87b3db6030b688cda7c956ced6821448aca5d76a79c74742ab7fc12523bdd5a82c94083a5faf23c56b77c0ab28ef07cb4fac38cd5059659a362986d4f172f43e3ed178b00925553d54b5a63f17f625b6e99cb9af47e1b2cded836d6f8d160fb9c4f329c684bd947b22f2cfec1fca5ee9a194ff77a41f351cfd33a4412fc82acd01de3347123f23dd773f6e4427dbea13f354adc736dc7f592d97d68349758f1c25e889fcce2a04c3d6c3bee1fc2ea724dde039c2f7b817e5ef7549a198ac130d560296230209d4c52ca200438f350a726ffb9231d9b70100fb30e" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_100000 WHERE value < $1 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cb2fa1de61f20783cf700958dbdc86fe842e6501d43305c38a1e009b32d508c312c90ef12f3ac4761c63cc40f96b16726ab527a83508f025835c1c571285a81aa11ef90d28d65f2f60ca84e39f1b8e8e1fddaec53a536e4c7c4bb61fb061fae99c9c2dcfd81f5e407f2298f9f1042a707e3e4a338928c3797845b44f4a2815cd68515c4c80b6c391ae477bbc321223c9509010c237d2322552bfbbfd7fd507b1015feb169590fa5c6622cd5041cfd866e4fd7765f25198786a4aabcecfeca4ce9f898c47d786639785f602dcc06e5a78547b07f498e8f3d2da57cb9c07aa7aaaec29f1f5fc237fb80c3742d2723e91ca1c6a4d99ccf4207a412828212f02e1872ba17e28d316c8338cd43190be359dfb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 160.42 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cb2fa1de61f20783cf700958dbdc86fe842e6501d43305c38a1e009b32d508c312c90ef12f3ac4761c63cc40f96b16726ab527a83508f025835c1c571285a81aa11ef90d28d65f2f60ca84e39f1b8e8e1fddaec53a536e4c7c4bb61fb061fae99c9c2dcfd81f5e407f2298f9f1042a707e3e4a338928c3797845b44f4a2815cd68515c4c80b6c391ae477bbc321223c9509010c237d2322552bfbbfd7fd507b1015feb169590fa5c6622cd5041cfd866e4fd7765f25198786a4aabcecfeca4ce9f898c47d786639785f602dcc06e5a78547b07f498e8f3d2da57cb9c07aa7aaaec29f1f5fc237fb80c3742d2723e91ca1c6a4d99ccf4207a412828212f02e1872ba17e28d316c8338cd43190be359dfb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 160.54, + "Total Cost": 2109.63 + } + ], + "Startup Cost": 2110.88, + "Strategy": "Plain", + "Total Cost": 2110.89 + } + } + ], + "id": "ORE/ore/range_selective_gt_count/100000", + "indexes_used": [ + "integer_encrypted_100000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cb2fa1de61f20783cf700958dbdc86fe842e6501d43305c38a1e009b32d508c312c90ef12f3ac4761c63cc40f96b16726ab527a83508f025835c1c571285a81aa11ef90d28d65f2f60ca84e39f1b8e8e1fddaec53a536e4c7c4bb61fb061fae99c9c2dcfd81f5e407f2298f9f1042a707e3e4a338928c3797845b44f4a2815cd68515c4c80b6c391ae477bbc321223c9509010c237d2322552bfbbfd7fd507b1015feb169590fa5c6622cd5041cfd866e4fd7765f25198786a4aabcecfeca4ce9f898c47d786639785f602dcc06e5a78547b07f498e8f3d2da57cb9c07aa7aaaec29f1f5fc237fb80c3742d2723e91ca1c6a4d99ccf4207a412828212f02e1872ba17e28d316c8338cd43190be359dfb" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_100000 WHERE value > $1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Simple", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_100000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e368f1931ce1aaed0f0d318ba891c284a36d19dfe4ce9734d5bcccf4b9651d28863dec1c887347ec8025f748b7c81f23a1cd808d61a996f0269c4c72909fbb60650e7f31320af6118e2b428052d5fd7960617cf51b7845f5c6c1ad5c3c67d6b69823cdb08715a368123f2b1b6f04f3611243e36663effedbb3ac9e55822e9d44ad66f5e3cc6b55cb9b997b68039e050f2bf5c6709dca85cd3055974c152606ccd04771d3f5ca11fadbeca51df522fcfe4ef64bccd12ba8e9f96e21764abbb339bd37f3f0b3f8fc767b023e99b8b6dedd952885a1867760b9bb357f786cde2983bdac807ddfbbe166dc6c95524526461e5b8058722912abae104e29277b6e185b05c16823094d0599047663f8259bd3fc6f2\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_100000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 500, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 160.42 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e368f1931ce1aaed0f0d318ba891c284a36d19dfe4ce9734d5bcccf4b9651d28863dec1c887347ec8025f748b7c81f23a1cd808d61a996f0269c4c72909fbb60650e7f31320af6118e2b428052d5fd7960617cf51b7845f5c6c1ad5c3c67d6b69823cdb08715a368123f2b1b6f04f3611243e36663effedbb3ac9e55822e9d44ad66f5e3cc6b55cb9b997b68039e050f2bf5c6709dca85cd3055974c152606ccd04771d3f5ca11fadbeca51df522fcfe4ef64bccd12ba8e9f96e21764abbb339bd37f3f0b3f8fc767b023e99b8b6dedd952885a1867760b9bb357f786cde2983bdac807ddfbbe166dc6c95524526461e5b8058722912abae104e29277b6e185b05c16823094d0599047663f8259bd3fc6f2\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_100000", + "Startup Cost": 160.54, + "Total Cost": 2109.63 + } + ], + "Startup Cost": 2110.88, + "Strategy": "Plain", + "Total Cost": 2110.89 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_count/100000", + "indexes_used": [ + "integer_encrypted_100000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_100000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e368f1931ce1aaed0f0d318ba891c284a36d19dfe4ce9734d5bcccf4b9651d28863dec1c887347ec8025f748b7c81f23a1cd808d61a996f0269c4c72909fbb60650e7f31320af6118e2b428052d5fd7960617cf51b7845f5c6c1ad5c3c67d6b69823cdb08715a368123f2b1b6f04f3611243e36663effedbb3ac9e55822e9d44ad66f5e3cc6b55cb9b997b68039e050f2bf5c6709dca85cd3055974c152606ccd04771d3f5ca11fadbeca51df522fcfe4ef64bccd12ba8e9f96e21764abbb339bd37f3f0b3f8fc767b023e99b8b6dedd952885a1867760b9bb357f786cde2983bdac807ddfbbe166dc6c95524526461e5b8058722912abae104e29277b6e185b05c16823094d0599047663f8259bd3fc6f2" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_100000 WHERE value > $1", + "rows_returned": 1 + } + ], + "target_rows": "100000" +} \ No newline at end of file diff --git a/results/query/ore_metadata_1000000.json b/results/query/ore_metadata_1000000.json new file mode 100644 index 0000000..0ad2a29 --- /dev/null +++ b/results/query/ore_metadata_1000000.json @@ -0,0 +1,523 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc62a3c03889bfda8d82b216c4c6410faf2006e3d1ba7ade1f8a5773f57be7c3889d905819937b3b99776e0b980b91841c9b1a3f100dc7369dbb5ab31b515155266325bfa0d72dca1d2f2397116230d2452b04424d8677fce4568b2aca0d381b807750d9853d700ebb2eb6ee72ac727a61726856e98b5ac66186a66ae9d10fe8e22c22cf2535b2debf2ed031c20f591367d37596733f4c86af0723c4cc47eb19ba05546b15b79775cae964d41415ad63a25b33bef2a82ce8c0fe7ed9e7d2082270a657241339382f54cf688e06dacb697a11d45c1407d15a9f1a3f7e3fa63a2535d8a96499a19775650b806548e0eedcad5c9416620d39a210fa374b0371139a68d0fa07b7ea6fc98d9a579fb5f9cf8332\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 495003, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 776611.81 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } + ], + "id": "ORE/ore/range_gt_10/1000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc62a3c03889bfda8d82b216c4c6410faf2006e3d1ba7ade1f8a5773f57be7c3889d905819937b3b99776e0b980b91841c9b1a3f100dc7369dbb5ab31b515155266325bfa0d72dca1d2f2397116230d2452b04424d8677fce4568b2aca0d381b807750d9853d700ebb2eb6ee72ac727a61726856e98b5ac66186a66ae9d10fe8e22c22cf2535b2debf2ed031c20f591367d37596733f4c86af0723c4cc47eb19ba05546b15b79775cae964d41415ad63a25b33bef2a82ce8c0fe7ed9e7d2082270a657241339382f54cf688e06dacb697a11d45c1407d15a9f1a3f7e3fa63a2535d8a96499a19775650b806548e0eedcad5c9416620d39a210fa374b0371139a68d0fa07b7ea6fc98d9a579fb5f9cf8332" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3a5e60fce4b20c5f84cdf50c14bb7a2d93695db169f646450ac3a5839e639cbd8b2fbaadd3d61d8aee86fb79d304fe3eff4cc04dda0fc39bdcded21ce5d97a3278149bf39f3933c1e689331931d97d079476e424b629c12ad329b6b41806200bbb52c37f553a6093a27a8a65eee6261473a9db28624a3847e95e9065dfcee285883f8d2711165d2cee42679e5c28b2be736f603179abcef7a841dff93d11a12f4f3e4aca7c87a8eed898416b23207dc4cd4c7b320f19517754dd16c3967a9c052d2503f8109595ac3c5ca3cf1c8591dcca454c3e3c415a57dcc9219781d4ac55ec1341c6496303e0af009865c1fa553745301a5c839de1d06216e0c31a6c193b692b545994e1d8bd1ed874bdd9f29b21\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 495003, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 776611.81 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } + ], + "id": "ORE/ore/range_gt_100/1000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3a5e60fce4b20c5f84cdf50c14bb7a2d93695db169f646450ac3a5839e639cbd8b2fbaadd3d61d8aee86fb79d304fe3eff4cc04dda0fc39bdcded21ce5d97a3278149bf39f3933c1e689331931d97d079476e424b629c12ad329b6b41806200bbb52c37f553a6093a27a8a65eee6261473a9db28624a3847e95e9065dfcee285883f8d2711165d2cee42679e5c28b2be736f603179abcef7a841dff93d11a12f4f3e4aca7c87a8eed898416b23207dc4cd4c7b320f19517754dd16c3967a9c052d2503f8109595ac3c5ca3cf1c8591dcca454c3e3c415a57dcc9219781d4ac55ec1341c6496303e0af009865c1fa553745301a5c839de1d06216e0c31a6c193b692b545994e1d8bd1ed874bdd9f29b21" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1f10ea56d47b8492c75f1339860acd4db023a4fcd171ec5d4697c28095e685544b67b814c2ed713ac34de8068c7b4ed893a668246f7494028dd7591cb861b84561dbb641380a18cb04cbd414456b7a08c1e10a9813c6cc2c50ccde3fe28aadcd8ef4960cb6114ac2dd81a2e060240adc0ac941879b1280595677c4edef6403049b3f0f043a4b722bad4daa5617cd9311d1015b47e7a1a693ec0cb1e6253bcf60b8d379950b516793044422f1914c421979291af0da9bd487bdaa416bb66e365212f03dd67a8f0824d2399141ac9ac19d7e7d5098b8fe7274c3db4a7ce80579fb9eb78fc9c6701c2496d901bd624ff9e93e67fc0f3a2d1a282a29f662273606e22f2c7d79631cf462aa5ffafa19632d53\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 779111.56 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } + ], + "id": "ORE/ore/range_lt_10/1000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc1f10ea56d47b8492c75f1339860acd4db023a4fcd171ec5d4697c28095e685544b67b814c2ed713ac34de8068c7b4ed893a668246f7494028dd7591cb861b84561dbb641380a18cb04cbd414456b7a08c1e10a9813c6cc2c50ccde3fe28aadcd8ef4960cb6114ac2dd81a2e060240adc0ac941879b1280595677c4edef6403049b3f0f043a4b722bad4daa5617cd9311d1015b47e7a1a693ec0cb1e6253bcf60b8d379950b516793044422f1914c421979291af0da9bd487bdaa416bb66e365212f03dd67a8f0824d2399141ac9ac19d7e7d5098b8fe7274c3db4a7ce80579fb9eb78fc9c6701c2496d901bd624ff9e93e67fc0f3a2d1a282a29f662273606e22f2c7d79631cf462aa5ffafa19632d53" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value < $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6a8b6086d0750409358d7141ee7450549514d09b6b1a827332087189e81351a040fabc979b3346f720e5114878db511790c234464edff1c5e59cab46a193b96539dc941cdfcac58b29f905f12e479cb1d26cefc26b569cd911b604d60f80556b989eaa5bf3e3d1715072db7f740692572acb594cdef91fcb53780f0ef54d2938ca7505af0d24e96abaad261abc0279f155168079957d8173918856c0d830cf751668ca7f2c1135c748b7446dfdce13a150b6b1e64923f01ea372d4dab76b4b924995eae1e7ecd91fe36476585bf1ab4a0552bd4c39830be772c47f2ee89a7343f2daaa62ce49e6e70d774892737171676dbff0c58468e23b653a9f2ae33a51b79ec16f6ef653b1aeb454c618041a73b\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 0.0, + "Total Cost": 779111.56 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } + ], + "id": "ORE/ore/range_lt_100/1000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce6a8b6086d0750409358d7141ee7450549514d09b6b1a827332087189e81351a040fabc979b3346f720e5114878db511790c234464edff1c5e59cab46a193b96539dc941cdfcac58b29f905f12e479cb1d26cefc26b569cd911b604d60f80556b989eaa5bf3e3d1715072db7f740692572acb594cdef91fcb53780f0ef54d2938ca7505af0d24e96abaad261abc0279f155168079957d8173918856c0d830cf751668ca7f2c1135c748b7446dfdce13a150b6b1e64923f01ea372d4dab76b4b924995eae1e7ecd91fe36476585bf1ab4a0552bd4c39830be772c47f2ee89a7343f2daaa62ce49e6e70d774892737171676dbff0c58468e23b653a9f2ae33a51b79ec16f6ef653b1aeb454c618041a73b" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value < $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cc6e472988d60f56a47cba7d9f30e0b64788545ad1dae1999c46fa0b156e1d563f48daebc786bb70ddd61e32974a69ff117a5e76328f922ba4b6a728aee7aee75e06f47c38560954532333812d8322f8c433d41947ca9c3d626dd95cdf01ab694e17346cd07c1c1869c471ab70218ed87648af057fb257188b8a25dc0b0f1974c3b3c7c20ecbf543001e7eb4c5e0ef7b997122321b55f36f294c760a1a172897c72096fe39bbc637ee039159d7f5a5383ae1f4d27c5aed077d2b3e70f7f4a598195da798e683799c8b902de06cd5639baaf9dfe6c3ee74434131ad9b6ff51b7e2c2c777714cfe9c8dbbba410f6696b1543feabece5b01e8c58ea66190e540b112a9b4837b01342bc11dd829309f33937\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 22557.45 + } + ], + "Startup Cost": 0.8, + "Total Cost": 451.93 + } + } + ], + "id": "ORE/ore/range_selective_gt_100/1000000", + "indexes_used": [ + "integer_encrypted_1000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9cc6e472988d60f56a47cba7d9f30e0b64788545ad1dae1999c46fa0b156e1d563f48daebc786bb70ddd61e32974a69ff117a5e76328f922ba4b6a728aee7aee75e06f47c38560954532333812d8322f8c433d41947ca9c3d626dd95cdf01ab694e17346cd07c1c1869c471ab70218ed87648af057fb257188b8a25dc0b0f1974c3b3c7c20ecbf543001e7eb4c5e0ef7b997122321b55f36f294c760a1a172897c72096fe39bbc637ee039159d7f5a5383ae1f4d27c5aed077d2b3e70f7f4a598195da798e683799c8b902de06cd5639baaf9dfe6c3ee74434131ad9b6ff51b7e2c2c777714cfe9c8dbbba410f6696b1543feabece5b01e8c58ea66190e540b112a9b4837b01342bc11dd829309f33937" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36826025d5cccf199ed561780d68e3f75a38dc99751d8f63a595ec23b8f2f37ff3da38d3ec2cc33796b230696cb12da7b98fd2727e7fba44500e9751626a532b4348105c6cf120473fbb73abc2457b147f06c825823fcf3151941e7f4864973da05e29cdb222744a3be998783538888e06673213bd43ebfecd3b17910ef45ffa0c022f5ccba16d575a8f60afc94c4c23a8ba9e4e7b7b104e25053b46a20208237cd7a61df5bb17c36f6e4fb06081d6397884f6a4c9fe0c2468973a1aeff11b9cef9f5b65b017ba46bb9b0cc4c30dbf4369ea81ba25a16dd54de7d478260a946dc800999ca00925622c07ba831d002454865013eb4d8e7a4616395e6e9f7d8b7671a7879332cbd5f470985cb90f3c264995\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 22557.45 + } + ], + "Startup Cost": 0.8, + "Total Cost": 45.91 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_10/1000000", + "indexes_used": [ + "integer_encrypted_1000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36826025d5cccf199ed561780d68e3f75a38dc99751d8f63a595ec23b8f2f37ff3da38d3ec2cc33796b230696cb12da7b98fd2727e7fba44500e9751626a532b4348105c6cf120473fbb73abc2457b147f06c825823fcf3151941e7f4864973da05e29cdb222744a3be998783538888e06673213bd43ebfecd3b17910ef45ffa0c022f5ccba16d575a8f60afc94c4c23a8ba9e4e7b7b104e25053b46a20208237cd7a61df5bb17c36f6e4fb06081d6397884f6a4c9fe0c2468973a1aeff11b9cef9f5b65b017ba46bb9b0cc4c30dbf4369ea81ba25a16dd54de7d478260a946dc800999ca00925622c07ba831d002454865013eb4d8e7a4616395e6e9f7d8b7671a7879332cbd5f470985cb90f3c264995" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcc7454297a75c940d0951c142be9814e95ec61cd4924e18ceef6e5339422e134138e197fb11a9b5ffaf528ecfdd29106b069eb2006af8da90a4adbf1e870ef0dfdeb2c01cb92b7ea432a9c5f320ff1f7fbb94bb2ee96eaef5d9980765a818a423adec67987cb6bd8ea297fb9c70c8be9c8238514f049602b581d884494a25d1c51b0bf2c7cffd3ed35846e7b19b4a7f7ae42f1871e99ea271f9596c446135319b172fdd89d1c4c718d9443fedfcd83f6199e3eca994f50f771e1b86e0baeded94fee1e70065464c7c38b9395bafd86ae52a3a81641fe4cce0fc7a7d1573dfc0e6e264097915a6688509a5cf1693b73ce4c9baa47dba4f86437f05411bb2d99915740198d4c43c6c2e2921c75cd7ab1943\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 505002, + "Plan Width": 68, + "Relation Name": "integer_encrypted_1000000", + "Scan Direction": "Forward", + "Startup Cost": 0.8, + "Total Cost": 990161.03 + } + ], + "Startup Cost": 0.8, + "Total Cost": 20.41 + } + } + ], + "id": "ORE/ore/range_lt_hybrid_ordered_10/1000000", + "indexes_used": [ + "integer_encrypted_1000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcc7454297a75c940d0951c142be9814e95ec61cd4924e18ceef6e5339422e134138e197fb11a9b5ffaf528ecfdd29106b069eb2006af8da90a4adbf1e870ef0dfdeb2c01cb92b7ea432a9c5f320ff1f7fbb94bb2ee96eaef5d9980765a818a423adec67987cb6bd8ea297fb9c70c8be9c8238514f049602b581d884494a25d1c51b0bf2c7cffd3ed35846e7b19b4a7f7ae42f1871e99ea271f9596c446135319b172fdd89d1c4c718d9443fedfcd83f6199e3eca994f50f771e1b86e0baeded94fee1e70065464c7c38b9395bafd86ae52a3a81641fe4cce0fc7a7d1573dfc0e6e264097915a6688509a5cf1693b73ce4c9baa47dba4f86437f05411bb2d99915740198d4c43c6c2e2921c75cd7ab1943" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_1000000 WHERE value < $1 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 2083, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9303e5e42d7aa93e853d4cd2cfd026e2b789aec720254a8e67101993039721b076eb3afb9eb0dfe84b93129133a06d9f8bb6ac7aad0eec110cb7d286dcc591ed6c2430fdb333bcb29dd1c18d029fea02819000a1713c8e1abddd3fb338620b1808d5636b4027888fc67079bfddca56c591a7f8a1cf70a8d0281b6dd446584d5deadd261e420c30908be061542fdde4bbb6f669b6915e473cf9c8955806c044f274e14d4277c6a331b2cc0c01b411263e9b07047af7fa93efd92ed73cba8c9499bc6869ccac4c63ff6aae4fad5545917c50c275cc17c21b7edd5511e505618f6651cc1b3d9eecb932838a4533635e8651f89a2947701a3b39ceb6f134a679a293b6f25034382cbd274fb90b1a488c53693\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1598.3 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9303e5e42d7aa93e853d4cd2cfd026e2b789aec720254a8e67101993039721b076eb3afb9eb0dfe84b93129133a06d9f8bb6ac7aad0eec110cb7d286dcc591ed6c2430fdb333bcb29dd1c18d029fea02819000a1713c8e1abddd3fb338620b1808d5636b4027888fc67079bfddca56c591a7f8a1cf70a8d0281b6dd446584d5deadd261e420c30908be061542fdde4bbb6f669b6915e473cf9c8955806c044f274e14d4277c6a331b2cc0c01b411263e9b07047af7fa93efd92ed73cba8c9499bc6869ccac4c63ff6aae4fad5545917c50c275cc17c21b7edd5511e505618f6651cc1b3d9eecb932838a4533635e8651f89a2947701a3b39ceb6f134a679a293b6f25034382cbd274fb90b1a488c53693\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 1599.55, + "Total Cost": 19587.07 + } + ], + "Startup Cost": 19592.28, + "Strategy": "Plain", + "Total Cost": 19592.29 + } + ], + "Single Copy": false, + "Startup Cost": 20592.28, + "Total Cost": 20592.49, + "Workers Planned": 2 + } + ], + "Startup Cost": 20592.49, + "Strategy": "Plain", + "Total Cost": 20592.5 + } + } + ], + "id": "ORE/ore/range_selective_gt_count/1000000", + "indexes_used": [ + "integer_encrypted_1000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9303e5e42d7aa93e853d4cd2cfd026e2b789aec720254a8e67101993039721b076eb3afb9eb0dfe84b93129133a06d9f8bb6ac7aad0eec110cb7d286dcc591ed6c2430fdb333bcb29dd1c18d029fea02819000a1713c8e1abddd3fb338620b1808d5636b4027888fc67079bfddca56c591a7f8a1cf70a8d0281b6dd446584d5deadd261e420c30908be061542fdde4bbb6f669b6915e473cf9c8955806c044f274e14d4277c6a331b2cc0c01b411263e9b07047af7fa93efd92ed73cba8c9499bc6869ccac4c63ff6aae4fad5545917c50c275cc17c21b7edd5511e505618f6651cc1b3d9eecb932838a4533635e8651f89a2947701a3b39ceb6f134a679a293b6f25034382cbd274fb90b1a488c53693" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_1000000 WHERE value > $1", + "rows_returned": 1 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_1000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 2083, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36336ff616214277b1f9a6899ff2fb29346bf2f5c3a21d9eb5d5d6cf0dc00240357a33aafcd12627cbf3992b39f610d077f9226a19af9b25cc95151efdb252be4e2d587b5c259e89390549fb08c6c868134b46199626902ea1f21c2fb68c5ce1f9189f75add605ce84b08ba514b0c7db8b9226350fb7af98e052037f121a305d1a73b27f80d20be84baffc513e7a8234d3709825c65b66cd35462d28bc25f3bbb1fb5a1b51007fe9d1546883962b42a5606ad48d38b1c79c768eaf1b21bd8fd52ca8b9d933bcc3878aba92719f35aac23166144ff1c237a89bdb5e3de96c81be1128e7e839832e23cbf82abcbfafecd214a440a0092f03adf2c9f3e46e5712f3323d254efbb3de9f5cbb698fa9013d1ea6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_1000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 1598.3 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36336ff616214277b1f9a6899ff2fb29346bf2f5c3a21d9eb5d5d6cf0dc00240357a33aafcd12627cbf3992b39f610d077f9226a19af9b25cc95151efdb252be4e2d587b5c259e89390549fb08c6c868134b46199626902ea1f21c2fb68c5ce1f9189f75add605ce84b08ba514b0c7db8b9226350fb7af98e052037f121a305d1a73b27f80d20be84baffc513e7a8234d3709825c65b66cd35462d28bc25f3bbb1fb5a1b51007fe9d1546883962b42a5606ad48d38b1c79c768eaf1b21bd8fd52ca8b9d933bcc3878aba92719f35aac23166144ff1c237a89bdb5e3de96c81be1128e7e839832e23cbf82abcbfafecd214a440a0092f03adf2c9f3e46e5712f3323d254efbb3de9f5cbb698fa9013d1ea6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_1000000", + "Startup Cost": 1599.55, + "Total Cost": 19587.07 + } + ], + "Startup Cost": 19592.28, + "Strategy": "Plain", + "Total Cost": 19592.29 + } + ], + "Single Copy": false, + "Startup Cost": 20592.28, + "Total Cost": 20592.49, + "Workers Planned": 2 + } + ], + "Startup Cost": 20592.49, + "Strategy": "Plain", + "Total Cost": 20592.5 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_count/1000000", + "indexes_used": [ + "integer_encrypted_1000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_1000000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36336ff616214277b1f9a6899ff2fb29346bf2f5c3a21d9eb5d5d6cf0dc00240357a33aafcd12627cbf3992b39f610d077f9226a19af9b25cc95151efdb252be4e2d587b5c259e89390549fb08c6c868134b46199626902ea1f21c2fb68c5ce1f9189f75add605ce84b08ba514b0c7db8b9226350fb7af98e052037f121a305d1a73b27f80d20be84baffc513e7a8234d3709825c65b66cd35462d28bc25f3bbb1fb5a1b51007fe9d1546883962b42a5606ad48d38b1c79c768eaf1b21bd8fd52ca8b9d933bcc3878aba92719f35aac23166144ff1c237a89bdb5e3de96c81be1128e7e839832e23cbf82abcbfafecd214a440a0092f03adf2c9f3e46e5712f3323d254efbb3de9f5cbb698fa9013d1ea6" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_1000000 WHERE value > $1", + "rows_returned": 1 + } + ], + "target_rows": "1000000" +} \ No newline at end of file diff --git a/results/query/ore_metadata_10000000.json b/results/query/ore_metadata_10000000.json new file mode 100644 index 0000000..6b137b5 --- /dev/null +++ b/results/query/ore_metadata_10000000.json @@ -0,0 +1,541 @@ +{ + "scenarios": [ + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce035ad53ca2690eed1e71042c260c9e6ee809838442e212025aab171a1e201c10b8f1ed816c170862c88e71d8f1bbb6ea753a69763773f04aa828616f2dd406571a5105ffb7f0fd2645e30ab97bd8db9695307bc53fef51485e3703569531275349e644604a43d3dc36351733b7ab42841f7e31c17334884cab9c34c825f3e4f1eb5ca73ed4ae08cd4472b1de7923671aa4023c454c0477c0b6bb635e84ffa6a933f1b8bbd2247eb853b54615ff841f7df80eb76849f616aef146bd19016cb3248887cbf00ecfd99745dc8bbf3aaeb514286a2cab99df87029a71ff87e63358b9d0688b079fb4c720e5d1461b38f5b2cfb3c42be361bdce13d4ea5b336f9e8e58d8844c007786f9f4c3abb0fb42e9fc9\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5050002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7791074.54 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.43 + } + } + ], + "id": "ORE/ore/range_gt_10/10000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bce035ad53ca2690eed1e71042c260c9e6ee809838442e212025aab171a1e201c10b8f1ed816c170862c88e71d8f1bbb6ea753a69763773f04aa828616f2dd406571a5105ffb7f0fd2645e30ab97bd8db9695307bc53fef51485e3703569531275349e644604a43d3dc36351733b7ab42841f7e31c17334884cab9c34c825f3e4f1eb5ca73ed4ae08cd4472b1de7923671aa4023c454c0477c0b6bb635e84ffa6a933f1b8bbd2247eb853b54615ff841f7df80eb76849f616aef146bd19016cb3248887cbf00ecfd99745dc8bbf3aaeb514286a2cab99df87029a71ff87e63358b9d0688b079fb4c720e5d1461b38f5b2cfb3c42be361bdce13d4ea5b336f9e8e58d8844c007786f9f4c3abb0fb42e9fc9" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf22472e31028b9267367f6ae1d7fda813082cc9cede20d048630743a6358ec81ec542cc9f6638716caebf2ce1f3762a70e5907b839e860e32106815dca3b98bb4969532c49f6ad74a4315ffe634396b78b23adbb4846f88d9a3cd0598023a858f9a7753d96f8339f75788a1d5b79f25feced5e50cffeb151ea84df8e7ecb1ce650d5f8df0c69ef1e48f9d6e3957861dcc67a7072167564a1813f95f16d860d59631db8e9ea7428bcf21fd4706f395b021f320f2ce0202437cd94de9512285cfa2ccb8080509ce91e0c4567e5894e9aef6af305ac3deb09565ed88596b21fd8f80021e5ee348af72b7c6e39195a8c5359a5a4b90d1dbd6d0275879c823624b255a7aae72714955c9987ab9437af111958\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 5050002, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7791074.54 + } + ], + "Startup Cost": 0.0, + "Total Cost": 154.28 + } + } + ], + "id": "ORE/ore/range_gt_100/10000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bcf22472e31028b9267367f6ae1d7fda813082cc9cede20d048630743a6358ec81ec542cc9f6638716caebf2ce1f3762a70e5907b839e860e32106815dca3b98bb4969532c49f6ad74a4315ffe634396b78b23adbb4846f88d9a3cd0598023a858f9a7753d96f8339f75788a1d5b79f25feced5e50cffeb151ea84df8e7ecb1ce650d5f8df0c69ef1e48f9d6e3957861dcc67a7072167564a1813f95f16d860d59631db8e9ea7428bcf21fd4706f395b021f320f2ce0202437cd94de9512285cfa2ccb8080509ce91e0c4567e5894e9aef6af305ac3deb09565ed88596b21fd8f80021e5ee348af72b7c6e39195a8c5359a5a4b90d1dbd6d0275879c823624b255a7aae72714955c9987ab9437af111958" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3f0e300ff67bc4d9fee3701c15fd2a1379f439472f348072a34d3f9e6dfc5ce064217764ce8b4d315ad49b082c9b558dd12a8de0b0c42022f1ebe75a86cf5cedd7f8a9a8446da81e80db2e3c8959ac852eee567cae6de44594030ced59d4ce678e56033858cb3ba2f7553aeebcd6fec71a72837339d1ce83b8ed6a66f88568d6769afa9ef42abbbd8f68dccfc307ad6a1ac90dd2c3f8b146db56bbfafdad3f08d921085fd9663a490327334c5021a249c5f9e3778f9b4ebdfbc85a24b4ae50921d7e553e55e07f7aa2afbdcf19bc9c7f2cfa52237826319241571e936806059603958a1b582ccfd35346335856af92aa6d8a1587b331b3359c39837c88063ba6a17ceefa37b187db9920dd4f8ba88ee5\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7766074.29 + } + ], + "Startup Cost": 0.0, + "Total Cost": 15.69 + } + } + ], + "id": "ORE/ore/range_lt_10/10000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc3f0e300ff67bc4d9fee3701c15fd2a1379f439472f348072a34d3f9e6dfc5ce064217764ce8b4d315ad49b082c9b558dd12a8de0b0c42022f1ebe75a86cf5cedd7f8a9a8446da81e80db2e3c8959ac852eee567cae6de44594030ced59d4ce678e56033858cb3ba2f7553aeebcd6fec71a72837339d1ce83b8ed6a66f88568d6769afa9ef42abbbd8f68dccfc307ad6a1ac90dd2c3f8b146db56bbfafdad3f08d921085fd9663a490327334c5021a249c5f9e3778f9b4ebdfbc85a24b4ae50921d7e553e55e07f7aa2afbdcf19bc9c7f2cfa52237826319241571e936806059603958a1b582ccfd35346335856af92aa6d8a1587b331b3359c39837c88063ba6a17ceefa37b187db9920dd4f8ba88ee5" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value < $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Filter": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc43a1ddec1ade1332d580d84e400ad9bf21691674d9edec0a1ca27d2c2d11e7c071cb97f10b33a98bc723350a42423ab0dd795c5a8347e3988a57f57599d058b161c97821aadcfaa8106ba32a7e21dbe4b46b57f4a2a1d79b56e96fd3d35520a235cda31312ecdcc17aec5b43aded4495b31006a25d72dca981c939e0351b3dfcfe98cf25896c488f13541336442e82cddbc625fb593b534672cac0b3a3dd30bd63be28eae0f3540007fc26fcbf7cb79633325cd94c3ce52b9260e85ec9368c777849d03910f89a6be4afbeb542104f507e5a4d4f9275d2922fa250c56b443739cccf1f5e74f71728219714d637e4773fdbebd76e6ec9a3d5fe303715a9d0f0a604840ba7f9df2af6aa1dc5cf16e406c6\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Node Type": "Seq Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 0.0, + "Total Cost": 7766074.29 + } + ], + "Startup Cost": 0.0, + "Total Cost": 156.89 + } + } + ], + "id": "ORE/ore/range_lt_100/10000000", + "indexes_used": [], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc43a1ddec1ade1332d580d84e400ad9bf21691674d9edec0a1ca27d2c2d11e7c071cb97f10b33a98bc723350a42423ab0dd795c5a8347e3988a57f57599d058b161c97821aadcfaa8106ba32a7e21dbe4b46b57f4a2a1d79b56e96fd3d35520a235cda31312ecdcc17aec5b43aded4495b31006a25d72dca981c939e0351b3dfcfe98cf25896c488f13541336442e82cddbc625fb593b534672cac0b3a3dd30bd63be28eae0f3540007fc26fcbf7cb79633325cd94c3ce52b9260e85ec9368c777849d03910f89a6be4afbeb542104f507e5a4d4f9275d2922fa250c56b443739cccf1f5e74f71728219714d637e4773fdbebd76e6ec9a3d5fe303715a9d0f0a604840ba7f9df2af6aa1dc5cf16e406c6" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value < $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 100, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b94da6a5c9730d37d11cfa0560bc682cabfa753c419e4719a7b1568265a12319e2b810be016244a215aa315ce894faf33a304c17197f68ddc0c5203ca82fd55a34870e5f445a834781ec684e007b489678f925aa5ea2083eda4bace925157a22ee9c1f48d64c33d18907cba79f728961e13d1457e95644139c3df24d89ffeb31d195b06d4893ca4d8a90cbadeed07fdba653fb4c62ee72e9e2c00336ba41dfc6160151c5370f7344881919a877daa7d473d628ed92b04e39da3e29347b705829051cc6cefdc8151e26582eaaa618fee547cf762daa98399af7347ed463730a56f6801c3495c5e0f880f51bf6820df041c0e16f67d4e85b0582a3f4d52fe493c66ab0f6378b831e6fe5edadb596c59260eb\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 225527.79 + } + ], + "Startup Cost": 0.94, + "Total Cost": 451.99 + } + } + ], + "id": "ORE/ore/range_selective_gt_100/10000000", + "indexes_used": [ + "integer_encrypted_10000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b94da6a5c9730d37d11cfa0560bc682cabfa753c419e4719a7b1568265a12319e2b810be016244a215aa315ce894faf33a304c17197f68ddc0c5203ca82fd55a34870e5f445a834781ec684e007b489678f925aa5ea2083eda4bace925157a22ee9c1f48d64c33d18907cba79f728961e13d1457e95644139c3df24d89ffeb31d195b06d4893ca4d8a90cbadeed07fdba653fb4c62ee72e9e2c00336ba41dfc6160151c5370f7344881919a877daa7d473d628ed92b04e39da3e29347b705829051cc6cefdc8151e26582eaaa618fee547cf762daa98399af7347ed463730a56f6801c3495c5e0f880f51bf6820df041c0e16f67d4e85b0582a3f4d52fe493c66ab0f6378b831e6fe5edadb596c59260eb" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value > $1 LIMIT 100", + "rows_returned": 100 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 36, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36b9581b419d45178f30a9a1425f682756e3bdfbb522e3ae4b80e8ce1396a389b264d8022ba559ca8817d1bad7b3dd81c3fae9777aad6410b408d953019daf32eb05ddaa96c7c307d44f5f562258b020e845f7225c1f7a24d2bc579cea64ed2466d3443af5da3191984de5ef5d676a3be46ac355a6e12de53fa351bf664472b87e4f8a84afee754fb4de1d907d8c93dfe73cbc2cfbdbf0d7d0b71f106de7d77b5dfe34a4fc4fc1723d32268d84dfa3c2b3eeba29fbd74be16a38e18ba0d22a1efa91de07ff11fb8be9a6a341f7da6d641af43018f1987d5b2aceb44e68592d1fa032f56cb4dba6226a4cddcb76d6e47b214ec07204ac1fd370df4588df09fb18e9fe9bb541594b3c0e15632acdd041728e\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 36, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 225527.79 + } + ], + "Startup Cost": 0.94, + "Total Cost": 46.04 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_10/10000000", + "indexes_used": [ + "integer_encrypted_10000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e36b9581b419d45178f30a9a1425f682756e3bdfbb522e3ae4b80e8ce1396a389b264d8022ba559ca8817d1bad7b3dd81c3fae9777aad6410b408d953019daf32eb05ddaa96c7c307d44f5f562258b020e845f7225c1f7a24d2bc579cea64ed2466d3443af5da3191984de5ef5d676a3be46ac355a6e12de53fa351bf664472b87e4f8a84afee754fb4de1d907d8c93dfe73cbc2cfbdbf0d7d0b71f106de7d77b5dfe34a4fc4fc1723d32268d84dfa3c2b3eeba29fbd74be16a38e18ba0d22a1efa91de07ff11fb8be9a6a341f7da6d641af43018f1987d5b2aceb44e68592d1fa032f56cb4dba6226a4cddcb76d6e47b214ec07204ac1fd370df4588df09fb18e9fe9bb541594b3c0e15632acdd041728e" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value > $1 LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "Plan": { + "Async Capable": false, + "Node Type": "Limit", + "Parallel Aware": false, + "Plan Rows": 10, + "Plan Width": 68, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) < '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc24f6a359f41fa3cb965233c1f31d65223e5fd83fa64ff6710ae83260a215b9d9b4d148c6297672bab63eb4affa1c28e64db59dd5af66b045c7d6be898b226b92ae831f7603e284bb1fefaa90bc751f632bb090d4438d5f600fb7289fd77b5485af1071fa0fc7f1bdcc45fbdffa5bb08e330bcf5987b536e9bba026c6f030ce6564f7107a72dbeaa665eceaacaa37f766d8bf8026a214aaaf8c79467ed8db91eb01414832c4742e38f909e8b234049d6e80c34d6533388ec2305aedc60868a03d63986a148a7952194a8ac88f122b8273a30ac4c14b1cb76adecce5a397aa7db67f507bd3d5b86e8e080e4c7cfb8bf96c59e31254b3fe5685f67c6414e79b01174f5146ddd77969c4a9f330134252ef67\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 4950001, + "Plan Width": 68, + "Relation Name": "integer_encrypted_10000000", + "Scan Direction": "Forward", + "Startup Cost": 0.94, + "Total Cost": 19385383.19 + } + ], + "Startup Cost": 0.94, + "Total Cost": 40.1 + } + } + ], + "id": "ORE/ore/range_lt_hybrid_ordered_10/10000000", + "indexes_used": [ + "integer_encrypted_10000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181813d3ba05650f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f48144b2318d70dbf219e5ccc1d1871c3b4249148392b5dab99ef56f446d7e2b2ee6e9f2875635d6b2b1b5c167a713e05cee6d388100bab0f678d763ff3cbe16bc24f6a359f41fa3cb965233c1f31d65223e5fd83fa64ff6710ae83260a215b9d9b4d148c6297672bab63eb4affa1c28e64db59dd5af66b045c7d6be898b226b92ae831f7603e284bb1fefaa90bc751f632bb090d4438d5f600fb7289fd77b5485af1071fa0fc7f1bdcc45fbdffa5bb08e330bcf5987b536e9bba026c6f030ce6564f7107a72dbeaa665eceaacaa37f766d8bf8026a214aaaf8c79467ed8db91eb01414832c4742e38f909e8b234049d6e80c34d6533388ec2305aedc60868a03d63986a148a7952194a8ac88f122b8273a30ac4c14b1cb76adecce5a397aa7db67f507bd3d5b86e8e080e4c7cfb8bf96c59e31254b3fe5685f67c6414e79b01174f5146ddd77969c4a9f330134252ef67" + ], + "v": 2 + } + ], + "query": "SELECT id,value::jsonb FROM integer_encrypted_10000000 WHERE value < $1 ORDER BY eql_v2.ore_block_u64_8_256(value) LIMIT 10", + "rows_returned": 10 + }, + { + "explain": [ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 20833, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9c22306bb84f2ee781c0cb8f7d53003060948ab2ed3082927e8862e763fa2342a844ff626ab7fe272b282a43d4e0c68d8c0d6a3874b55845ede4a7703ac1cba89ef0a4218b287cc7c21458d042a0664196c4eb69769dbaa42e692a0a14a23523453cc5186247a554401d396c8659a21420c6d22ea18e03dc07820a4dcf1c15045cefd19f78505615b38ea28d297f05fdda6da1ea2af15e5e09a5adb5f364a00ef6f72370675bb96f4c0ac07a8f7e56a5319f20543b1978620990d71c1089600ce66d6121202d28663652ad230098e1da5856d5874f2438c3a87f3c5cac4d906885bc95325fca5794b131cb8590ff5081e67ec424fb85f94a5c243d8589487a0aa86f4fc09859e72eeed9ad139336d9112\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 15963.93 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9c22306bb84f2ee781c0cb8f7d53003060948ab2ed3082927e8862e763fa2342a844ff626ab7fe272b282a43d4e0c68d8c0d6a3874b55845ede4a7703ac1cba89ef0a4218b287cc7c21458d042a0664196c4eb69769dbaa42e692a0a14a23523453cc5186247a554401d396c8659a21420c6d22ea18e03dc07820a4dcf1c15045cefd19f78505615b38ea28d297f05fdda6da1ea2af15e5e09a5adb5f364a00ef6f72370675bb96f4c0ac07a8f7e56a5319f20543b1978620990d71c1089600ce66d6121202d28663652ad230098e1da5856d5874f2438c3a87f3c5cac4d906885bc95325fca5794b131cb8590ff5081e67ec424fb85f94a5c243d8589487a0aa86f4fc09859e72eeed9ad139336d9112\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 15976.43, + "Total Cost": 195823.06 + } + ], + "Startup Cost": 195875.15, + "Strategy": "Plain", + "Total Cost": 195875.16 + } + ], + "Single Copy": false, + "Startup Cost": 196875.15, + "Total Cost": 196875.36, + "Workers Planned": 2 + } + ], + "Startup Cost": 196875.36, + "Strategy": "Plain", + "Total Cost": 196875.37 + } + } + ], + "id": "ORE/ore/range_selective_gt_count/10000000", + "indexes_used": [ + "integer_encrypted_10000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181819c54c4cd50f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12bbb0bd496b07fcd3fb5f6023b99f693a88b0a0e8c51a1c10c2af20a0e7cfc0a7e40c25d147a0ac4821b8eae3d8d762b9c22306bb84f2ee781c0cb8f7d53003060948ab2ed3082927e8862e763fa2342a844ff626ab7fe272b282a43d4e0c68d8c0d6a3874b55845ede4a7703ac1cba89ef0a4218b287cc7c21458d042a0664196c4eb69769dbaa42e692a0a14a23523453cc5186247a554401d396c8659a21420c6d22ea18e03dc07820a4dcf1c15045cefd19f78505615b38ea28d297f05fdda6da1ea2af15e5e09a5adb5f364a00ef6f72370675bb96f4c0ac07a8f7e56a5319f20543b1978620990d71c1089600ce66d6121202d28663652ad230098e1da5856d5874f2438c3a87f3c5cac4d906885bc95325fca5794b131cb8590ff5081e67ec424fb85f94a5c243d8589487a0aa86f4fc09859e72eeed9ad139336d9112" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_10000000 WHERE value > $1", + "rows_returned": 1 + }, + { + "explain": [ + { + "JIT": { + "Functions": 7, + "Options": { + "Deforming": true, + "Expressions": true, + "Inlining": false, + "Optimization": false + } + }, + "Plan": { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Partial Mode": "Finalize", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Gather", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 2, + "Plan Width": 8, + "Plans": [ + { + "Async Capable": false, + "Node Type": "Aggregate", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Partial Mode": "Partial", + "Plan Rows": 1, + "Plan Width": 8, + "Plans": [ + { + "Alias": "integer_encrypted_10000000", + "Async Capable": false, + "Node Type": "Bitmap Heap Scan", + "Parallel Aware": true, + "Parent Relationship": "Outer", + "Plan Rows": 20833, + "Plan Width": 0, + "Plans": [ + { + "Async Capable": false, + "Index Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3636a48cacc6fa21cf8b6d7e9397f66d65db0bf1139c96af507702882ec0a2b2e6788ed111afd249f56cfd3ab4345e84ff9c24a3d868f851280738122f536435565d32364de6a0ce34331f73783093fe7d25b468c99da1ba0f27cdce6fe1cbd01142f5fa9c226ebefde9fdf008cc082e47e151a647218343e65430dc173e30dfd2e73d8194c5260d63c3576f2e31b1a7bb22ca6af9cbb6becdb745325c2dd4241fadc83b7a650ec9be1ec1c808b7a9ce3c7cee5eb0706c4bc89df7f7b3c3bb11352cca1986ab8b1bc3d9d02d2c30039258bf6c0a045f6933e4c532028601e760996e0e463b5cad6bf39064caebf7f8b6a2ae3946bdcb70fbebefb6d729ad9cb1406564f445922fb1653bf5c6183ea56fbd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Index Name": "integer_encrypted_10000000_ore_index", + "Node Type": "Bitmap Index Scan", + "Parallel Aware": false, + "Parent Relationship": "Outer", + "Plan Rows": 50000, + "Plan Width": 0, + "Startup Cost": 0.0, + "Total Cost": 15963.93 + } + ], + "Recheck Cond": "(eql_v2.ore_block_u64_8_256(value) > '(\"{\"\"(\\\\\"\"\\\\\\\\\\\\\\\\x818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3636a48cacc6fa21cf8b6d7e9397f66d65db0bf1139c96af507702882ec0a2b2e6788ed111afd249f56cfd3ab4345e84ff9c24a3d868f851280738122f536435565d32364de6a0ce34331f73783093fe7d25b468c99da1ba0f27cdce6fe1cbd01142f5fa9c226ebefde9fdf008cc082e47e151a647218343e65430dc173e30dfd2e73d8194c5260d63c3576f2e31b1a7bb22ca6af9cbb6becdb745325c2dd4241fadc83b7a650ec9be1ec1c808b7a9ce3c7cee5eb0706c4bc89df7f7b3c3bb11352cca1986ab8b1bc3d9d02d2c30039258bf6c0a045f6933e4c532028601e760996e0e463b5cad6bf39064caebf7f8b6a2ae3946bdcb70fbebefb6d729ad9cb1406564f445922fb1653bf5c6183ea56fbd\\\\\"\")\"\"}\")'::eql_v2.ore_block_u64_8_256)", + "Relation Name": "integer_encrypted_10000000", + "Startup Cost": 15976.43, + "Total Cost": 195823.06 + } + ], + "Startup Cost": 195875.15, + "Strategy": "Plain", + "Total Cost": 195875.16 + } + ], + "Single Copy": false, + "Startup Cost": 196875.15, + "Total Cost": 196875.36, + "Workers Planned": 2 + } + ], + "Startup Cost": 196875.36, + "Strategy": "Plain", + "Total Cost": 196875.37 + } + } + ], + "id": "ORE/ore/range_highly_selective_gt_count/10000000", + "indexes_used": [ + "integer_encrypted_10000000_ore_index" + ], + "parameters": [ + { + "i": { + "c": "value", + "t": "integer_encrypted_10000000" + }, + "ob": [ + "818181819c74696450f0e2e50041a4028946d3b901f2227b9f40ca2d24ae4855610af3b93ab3fb03fb06a17df7471b16a573428a9f4c92b3cc79a164992485a18ab87494b45830f40b0aaa51599711df6ba2dcc070bb9c12000c1ce2da49187443be7a630b7bba4e4c788d889b7eef636659fb4d6b64dbab777c3973caa72a76ec3c372074623e3636a48cacc6fa21cf8b6d7e9397f66d65db0bf1139c96af507702882ec0a2b2e6788ed111afd249f56cfd3ab4345e84ff9c24a3d868f851280738122f536435565d32364de6a0ce34331f73783093fe7d25b468c99da1ba0f27cdce6fe1cbd01142f5fa9c226ebefde9fdf008cc082e47e151a647218343e65430dc173e30dfd2e73d8194c5260d63c3576f2e31b1a7bb22ca6af9cbb6becdb745325c2dd4241fadc83b7a650ec9be1ec1c808b7a9ce3c7cee5eb0706c4bc89df7f7b3c3bb11352cca1986ab8b1bc3d9d02d2c30039258bf6c0a045f6933e4c532028601e760996e0e463b5cad6bf39064caebf7f8b6a2ae3946bdcb70fbebefb6d729ad9cb1406564f445922fb1653bf5c6183ea56fbd" + ], + "v": 2 + } + ], + "query": "SELECT count(*) FROM integer_encrypted_10000000 WHERE value > $1", + "rows_returned": 1 + } + ], + "target_rows": "10000000" +} \ No newline at end of file diff --git a/results/query/ore_rows_10000.json b/results/query/ore_rows_10000.json index f2b2026..53de277 100644 --- a/results/query/ore_rows_10000.json +++ b/results/query/ore_rows_10000.json @@ -1,15 +1,17 @@ -{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_10000","iteration_count":[61,122,183,244,305,366,427,488,549,610],"measured_values":[111318709.0,197778750.0,256108458.0,374971000.0,479480458.0,552442917.0,651524500.0,730160209.0,803746584.0,966981667.0],"unit":"ns","throughput":[],"typical":{"estimate":1524063.6352139662,"lower_bound":1485815.4122752512,"upper_bound":1563788.4755493547,"unit":"ns"},"mean":{"estimate":1553505.7844203748,"lower_bound":1494170.8450351288,"upper_bound":1626899.9461065573,"unit":"ns"},"median":{"estimate":1531292.4473067916,"lower_bound":1494918.8899297426,"upper_bound":1596602.1852459018,"unit":"ns"},"median_abs_dev":{"estimate":70199.64716010072,"lower_bound":20281.609142388486,"upper_bound":153485.5780890208,"unit":"ns"},"slope":{"estimate":1524063.6352139662,"lower_bound":1485815.4122752512,"upper_bound":1563788.4755493547,"unit":"ns"},"change":{"mean":{"estimate":-0.378148753541114,"lower_bound":-0.40230538330324017,"upper_bound":-0.3452247959250055,"unit":"%"},"median":{"estimate":-0.3814481937513796,"lower_bound":-0.4021094360122811,"upper_bound":-0.3497238375012155,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[134498583.0,236023583.0,316222875.0,464566000.0,553139792.0,668701875.0,859420250.0,981985333.0,1087549541.0,1131559834.0],"unit":"ns","throughput":[],"typical":{"estimate":29329063.12142857,"lower_bound":28273271.201763604,"upper_bound":30220342.861180257,"unit":"ns"},"mean":{"estimate":29391376.993561514,"lower_bound":28243164.28034722,"upper_bound":30658165.34738219,"unit":"ns"},"median":{"estimate":29269161.4375,"lower_bound":27862578.125,"upper_bound":30687041.65625,"unit":"ns"},"median_abs_dev":{"estimate":2093774.778543692,"lower_bound":358693.480623584,"upper_bound":3467030.7623928995,"unit":"ns"},"slope":{"estimate":29329063.12142857,"lower_bound":28273271.201763604,"upper_bound":30220342.861180257,"unit":"ns"},"change":{"mean":{"estimate":-0.0002995325324263165,"lower_bound":-0.05084012248323879,"upper_bound":0.04973956992570959,"unit":"%"},"median":{"estimate":0.0030647276987638694,"lower_bound":-0.08083881468334486,"upper_bound":0.07326355062496415,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_10000","iteration_count":[14,28,42,56,70,84,98,112,126,140],"measured_values":[88996125.0,186091541.0,269595375.0,358466750.0,448057708.0,554859459.0,633070166.0,731034625.0,848043916.0,895247625.0],"unit":"ns","throughput":[],"typical":{"estimate":6519094.115398887,"lower_bound":6421690.88467818,"upper_bound":6632885.24692526,"unit":"ns"},"mean":{"estimate":6494154.383183106,"lower_bound":6424065.599591836,"upper_bound":6572836.760974702,"unit":"ns"},"median":{"estimate":6439418.576530612,"lower_bound":6397908.928571429,"upper_bound":6605469.75,"unit":"ns"},"median_abs_dev":{"estimate":94400.98676333272,"lower_bound":9189.906526847295,"upper_bound":202312.09770824207,"unit":"ns"},"slope":{"estimate":6519094.115398887,"lower_bound":6421690.88467818,"upper_bound":6632885.24692526,"unit":"ns"},"change":{"mean":{"estimate":-0.5606689931650426,"lower_bound":-0.5736855619806251,"upper_bound":-0.549678014533415,"unit":"%"},"median":{"estimate":-0.5541287123319921,"lower_bound":-0.5709817762771191,"upper_bound":-0.5426311757681446,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_10000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[142112417.0,294236833.0,406392292.0,570268916.0,712804250.0,808694042.0,967449125.0,1064513792.0,1233398292.0,1337631083.0],"unit":"ns","throughput":[],"typical":{"estimate":45378505.44935065,"lower_bound":44823081.76082474,"upper_bound":46274356.86639118,"unit":"ns"},"mean":{"estimate":46222798.49968253,"lower_bound":45336726.477142856,"upper_bound":47173087.131587304,"unit":"ns"},"median":{"estimate":45875212.08730159,"lower_bound":44871200.93888889,"upper_bound":47520283.333333336,"unit":"ns"},"median_abs_dev":{"estimate":2063114.143142401,"lower_bound":113960.29407679666,"upper_bound":2473964.908978343,"unit":"ns"},"slope":{"estimate":45378505.44935065,"lower_bound":44823081.76082474,"upper_bound":46274356.86639118,"unit":"ns"},"change":{"mean":{"estimate":-0.1279054180688285,"lower_bound":-0.14767969499461953,"upper_bound":-0.1072332921017398,"unit":"%"},"median":{"estimate":-0.1303365042080139,"lower_bound":-0.15455301426271273,"upper_bound":-0.0985570633517302,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_10000","iteration_count":[71,142,213,284,355,426,497,568,639,710],"measured_values":[103179875.0,169023416.0,263705500.0,348010959.0,458829917.0,598222583.0,653809750.0,701714083.0,804314500.0,884450333.0],"unit":"ns","throughput":[],"typical":{"estimate":1272419.4940552406,"lower_bound":1245604.1300480296,"upper_bound":1317926.4218923498,"unit":"ns"},"mean":{"estimate":1285908.2642627992,"lower_bound":1240690.1479208588,"upper_bound":1338202.8983446094,"unit":"ns"},"median":{"estimate":1252206.4160406885,"lower_bound":1231722.345657277,"upper_bound":1348378.5016431925,"unit":"ns"},"median_abs_dev":{"estimate":49732.28809939942,"lower_bound":9387.296640736618,"upper_bound":132609.4223355008,"unit":"ns"},"slope":{"estimate":1272419.4940552406,"lower_bound":1245604.1300480296,"upper_bound":1317926.4218923498,"unit":"ns"},"change":{"mean":{"estimate":-0.32068194341812795,"lower_bound":-0.3524467929006541,"upper_bound":-0.2845412864257665,"unit":"%"},"median":{"estimate":-0.3326100611817553,"lower_bound":-0.3640300856644596,"upper_bound":-0.2797641885527964,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[117031833.0,250547042.0,333167667.0,454434375.0,594945000.0,668385792.0,782089292.0,912762750.0,1109972125.0,1193954667.0],"unit":"ns","throughput":[],"typical":{"estimate":29302875.97987013,"lower_bound":28275293.410569105,"upper_bound":30088334.12989312,"unit":"ns"},"mean":{"estimate":29147613.92563492,"lower_bound":28441430.31319197,"upper_bound":29917019.313134916,"unit":"ns"},"median":{"estimate":28890897.09375,"lower_bound":27931760.42857143,"upper_bound":30289904.513888888,"unit":"ns"},"median_abs_dev":{"estimate":1421150.8352470293,"lower_bound":150656.87968030683,"upper_bound":2161802.6042265818,"unit":"ns"},"slope":{"estimate":29302875.97987013,"lower_bound":28275293.410569105,"upper_bound":30088334.12989312,"unit":"ns"},"change":{"mean":{"estimate":-0.026341340612251574,"lower_bound":-0.0694143149677045,"upper_bound":0.0155620549746146,"unit":"%"},"median":{"estimate":-0.023261462121507814,"lower_bound":-0.07783769011980968,"upper_bound":0.028276001700246578,"unit":"%"},"change":"NoChange"}} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_10000","iteration_count":[14,28,42,56,70,84,98,112,126,140],"measured_values":[87709709.0,179557250.0,264738000.0,351355000.0,443111417.0,534521917.0,651639041.0,737366500.0,820949583.0,901440084.0],"unit":"ns","throughput":[],"typical":{"estimate":6480983.148423006,"lower_bound":6398096.703407136,"upper_bound":6549931.900190724,"unit":"ns"},"mean":{"estimate":6413607.759795918,"lower_bound":6339117.567431972,"upper_bound":6494759.401857142,"unit":"ns"},"median":{"estimate":6388057.541666666,"lower_bound":6302179.764285713,"upper_bound":6515472.880952381,"unit":"ns"},"median_abs_dev":{"estimate":147246.59616084953,"lower_bound":35229.32877455321,"upper_bound":224779.80953936197,"unit":"ns"},"slope":{"estimate":6480983.148423006,"lower_bound":6398096.703407136,"upper_bound":6549931.900190724,"unit":"ns"},"change":{"mean":{"estimate":-0.5599168305299298,"lower_bound":-0.5711020226370892,"upper_bound":-0.5504229771237805,"unit":"%"},"median":{"estimate":-0.5571927440947941,"lower_bound":-0.5672929135875131,"upper_bound":-0.5459983315363977,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_10000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[84721292.0,185758333.0,285243334.0,349268750.0,473475208.0,593283000.0,637864833.0,769820041.0,848816125.0,936453791.0],"unit":"ns","throughput":[],"typical":{"estimate":47095602.849350646,"lower_bound":46250297.15622839,"upper_bound":47916453.99191374,"unit":"ns"},"mean":{"estimate":46444181.67537698,"lower_bound":45147932.850394845,"upper_bound":47605466.913611114,"unit":"ns"},"median":{"estimate":46989570.46944444,"lower_bound":45049088.5,"upper_bound":47730636.68125,"unit":"ns"},"median_abs_dev":{"estimate":1241801.4902365396,"lower_bound":286193.48823905067,"upper_bound":3348640.9114347384,"unit":"ns"},"slope":{"estimate":47095602.849350646,"lower_bound":46250297.15622839,"upper_bound":47916453.99191374,"unit":"ns"},"change":{"mean":{"estimate":-0.13647232247903607,"lower_bound":-0.16506611609471367,"upper_bound":-0.10840768473892491,"unit":"%"},"median":{"estimate":-0.1230879887566042,"lower_bound":-0.16679433092673557,"upper_bound":-0.10240263344081768,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_ordered_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[63495250.0,126438625.0,192023917.0,249787958.0,328427833.0,395997875.0,445772708.0,536486291.0,583475750.0,646182167.0],"unit":"ns","throughput":[],"typical":{"estimate":16256574.806493506,"lower_bound":16050854.696185187,"upper_bound":16491536.29331519,"unit":"ns"},"mean":{"estimate":16126154.853978176,"lower_bound":15924809.986145834,"upper_bound":16340450.96528646,"unit":"ns"},"median":{"estimate":16078273.629166666,"lower_bound":15862640.99107143,"upper_bound":16421391.65,"unit":"ns"},"median_abs_dev":{"estimate":354272.18100041116,"lower_bound":85713.35371578457,"upper_bound":600189.2904020103,"unit":"ns"},"slope":{"estimate":16256574.806493506,"lower_bound":16050854.696185187,"upper_bound":16491536.29331519,"unit":"ns"},"change":{"mean":{"estimate":-0.9755308569418186,"lower_bound":-0.9763844790441544,"upper_bound":-0.9747305734061379,"unit":"%"},"median":{"estimate":-0.9748876851713664,"lower_bound":-0.9765096817527757,"upper_bound":-0.9742296262650018,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ordered_10_10000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[126667542.0,249555584.0,370095625.0,522242167.0,608805500.0,774376500.0,881606291.0,1012135042.0,1109613125.0,1247589583.0],"unit":"ns","throughput":[],"typical":{"estimate":41771479.723809525,"lower_bound":41352473.05659851,"upper_bound":42336680.09803922,"unit":"ns"},"mean":{"estimate":41890162.523756616,"lower_bound":41383234.01072818,"upper_bound":42431992.702645496,"unit":"ns"},"median":{"estimate":41786924.64285715,"lower_bound":41121736.11111111,"upper_bound":42596605.041666664,"unit":"ns"},"median_abs_dev":{"estimate":816006.634546319,"lower_bound":178847.55272481914,"upper_bound":1486195.3527447537,"unit":"ns"},"slope":{"estimate":41771479.723809525,"lower_bound":41352473.05659851,"upper_bound":42336680.09803922,"unit":"ns"},"change":{"mean":{"estimate":-0.9365115016240321,"lower_bound":-0.9373889416092059,"upper_bound":-0.9356319008948646,"unit":"%"},"median":{"estimate":-0.9366081123781814,"lower_bound":-0.9375954966381621,"upper_bound":-0.9354077911051406,"unit":"%"},"change":"Improved"}} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_10000","iteration_count":[75,150,225,300,375,450,525,600,675,750],"measured_values":[91475833.0,176155458.0,324425459.0,379213583.0,458805708.0,571798208.0,623958833.0,742399334.0,818233708.0,883926708.0],"unit":"ns","throughput":[],"typical":{"estimate":1217974.4485194804,"lower_bound":1195854.2829905835,"upper_bound":1254564.9116145761,"unit":"ns"},"mean":{"estimate":1241072.0539830686,"lower_bound":1203794.3658021956,"upper_bound":1292821.084948148,"unit":"ns"},"median":{"estimate":1221579.8306666669,"lower_bound":1188493.0152380953,"upper_bound":1264045.2766666666,"unit":"ns"},"median_abs_dev":{"estimate":56006.890402678844,"lower_bound":8364.682329008294,"upper_bound":84029.63546684226,"unit":"ns"},"slope":{"estimate":1217974.4485194804,"lower_bound":1195854.2829905835,"upper_bound":1254564.9116145761,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[120961000.0,228718250.0,336342875.0,471191708.0,562109333.0,705723834.0,787965709.0,923876291.0,1004374125.0,1144335417.0],"unit":"ns","throughput":[],"typical":{"estimate":28510762.475324675,"lower_bound":28160419.46251921,"upper_bound":28908288.55562201,"unit":"ns"},"mean":{"estimate":28733914.554970235,"lower_bound":28314839.74138095,"upper_bound":29200176.261874996,"unit":"ns"},"median":{"estimate":28599083.3375,"lower_bound":28085102.69047619,"upper_bound":29405159.75,"unit":"ns"},"median_abs_dev":{"estimate":788837.4114028345,"lower_bound":83811.04116205448,"upper_bound":1238104.7826692462,"unit":"ns"},"slope":{"estimate":28510762.475324675,"lower_bound":28160419.46251921,"upper_bound":28908288.55562201,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ore_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_ore_ordered_10_10000","iteration_count":[75,150,225,300,375,450,525,600,675,750],"measured_values":[101076708.0,223080542.0,327858292.0,373852000.0,484134750.0,560835875.0,597890542.0,715279541.0,864979292.0,908548209.0],"unit":"ns","throughput":[],"typical":{"estimate":1232542.8747359307,"lower_bound":1196757.117398374,"upper_bound":1279059.4680310548,"unit":"ns"},"mean":{"estimate":1289936.2406470901,"lower_bound":1227630.2393070632,"upper_bound":1358927.6389563493,"unit":"ns"},"median":{"estimate":1263876.3737037037,"lower_bound":1211397.612,"upper_bound":1374086.9822222223,"unit":"ns"},"median_abs_dev":{"estimate":92086.18733715455,"lower_bound":25874.58118170126,"upper_bound":188624.0065122544,"unit":"ns"},"slope":{"estimate":1232542.8747359307,"lower_bound":1196757.117398374,"upper_bound":1279059.4680310548,"unit":"ns"},"change":{"mean":{"estimate":0.125253246502119,"lower_bound":0.06621155256489736,"upper_bound":0.18870546666516558,"unit":"%"},"median":{"estimate":0.11173013037705637,"lower_bound":0.050576355656023475,"upper_bound":0.20934946245168118,"unit":"%"},"change":"Regressed"}} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ore_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ore_ordered_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[122907375.0,249828166.0,343002917.0,486249250.0,577763167.0,653539250.0,788446708.0,930451459.0,1004688959.0,1229236750.0],"unit":"ns","throughput":[],"typical":{"estimate":29028524.384415586,"lower_bound":28057142.715968516,"upper_bound":30048696.954617836,"unit":"ns"},"mean":{"estimate":29292284.395763893,"lower_bound":28485160.41277604,"upper_bound":30104023.16527084,"unit":"ns"},"median":{"estimate":28982383.221875,"lower_bound":28158811.0,"upper_bound":30726843.75,"unit":"ns"},"median_abs_dev":{"estimate":1840315.3839820381,"lower_bound":255239.77834359472,"upper_bound":2342341.938102619,"unit":"ns"},"slope":{"estimate":29028524.384415586,"lower_bound":28057142.715968516,"upper_bound":30048696.954617836,"unit":"ns"},"change":{"mean":{"estimate":-0.06941090977814401,"lower_bound":-0.16045759803088852,"upper_bound":0.010754108463294327,"unit":"%"},"median":{"estimate":-0.0323046616582372,"lower_bound":-0.09882375020683087,"upper_bound":0.05335237678174454,"unit":"%"},"change":"NoChange"}} -{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore_decrypt/range_lt_ordered_10/100000","ORE/ore/range_lt_10/100000","ORE/ore_decrypt/range_lt_ore_100/10000","ORE/ore_decrypt/range_gt_ore_10/10000","ORE/ore_decrypt/range_lt_100/100000","ORE/ore_decrypt/range_gt_10/100000","ORE/ore_decrypt/range_gt_ore_100/10000","ORE/ore/range_lt_ordered_10/100000","ORE/ore/range_gt_100/100000","ORE/ore/range_lt_ore_10/10000","ORE/ore_decrypt/exact/10000","ORE/ore/range_lt_100/100000","ORE/ore_decrypt/range_lt_ore_10/10000","ORE/ore_decrypt/range_gt_100/100000","ORE/ore/range_gt_ore_100/10000","ORE/ore_decrypt/range_lt_10/100000","ORE/ore/exact/100000","ORE/ore_decrypt/exact/100000","ORE/ore/range_lt_ore_100/10000","ORE/ore/range_gt_10/100000","ORE/ore/range_gt_ore_10/10000","ORE/ore/exact/10000","ORE/ore/range_gt_10/10000","ORE/ore_decrypt/range_gt_10/10000","ORE/ore/range_gt_100/10000","ORE/ore_decrypt/range_gt_100/10000","ORE/ore/range_lt_10/10000","ORE/ore_decrypt/range_lt_10/10000","ORE/ore/range_lt_100/10000","ORE/ore_decrypt/range_lt_100/10000","ORE/ore/range_lt_ordered_10/10000","ORE/ore_decrypt/range_lt_ordered_10/10000","ORE/ore/range_lt_hybrid_ordered_10/10000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000","ORE/ore/range_lt_ore_ordered_10/10000","ORE/ore_decrypt/range_lt_ore_ordered_10/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_10000","iteration_count":[72,144,216,288,360,432,504,576,648,720],"measured_values":[76605250.0,151160958.0,229706083.0,333532291.0,392841541.0,456807083.0,545630958.0,643614792.0,710869500.0,776717875.0],"unit":"ns","throughput":[],"typical":{"estimate":1090929.4398989899,"lower_bound":1076743.738491132,"upper_bound":1106848.0803676986,"unit":"ns"},"mean":{"estimate":1085967.6865707673,"lower_bound":1068515.9027450394,"upper_bound":1106599.8780324073,"unit":"ns"},"median":{"estimate":1080687.9667658731,"lower_bound":1060692.804398148,"upper_bound":1104306.6472222223,"unit":"ns"},"median_abs_dev":{"estimate":25174.577214867713,"lower_bound":5222.992074634472,"upper_bound":49766.055802586954,"unit":"ns"},"slope":{"estimate":1090929.4398989899,"lower_bound":1076743.738491132,"upper_bound":1106848.0803676986,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[108461833.0,221612584.0,317734875.0,421536041.0,547739291.0,651759833.0,743879667.0,826327375.0,985687375.0,1091295791.0],"unit":"ns","throughput":[],"typical":{"estimate":26910527.40064935,"lower_bound":26355819.100678734,"upper_bound":27276245.80108359,"unit":"ns"},"mean":{"estimate":26923702.538998015,"lower_bound":26563842.989521828,"upper_bound":27252287.560873013,"unit":"ns"},"median":{"estimate":27136058.979166664,"lower_bound":26456566.76339286,"upper_bound":27380204.861111112,"unit":"ns"},"median_abs_dev":{"estimate":605211.8325578463,"lower_bound":77517.57283128964,"upper_bound":971363.5960360989,"unit":"ns"},"slope":{"estimate":26910527.40064935,"lower_bound":26355819.100678734,"upper_bound":27276245.80108359,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_10000","iteration_count":[14,28,42,56,70,84,98,112,126,140],"measured_values":[92904917.0,183225792.0,266286209.0,363924083.0,455236542.0,533848125.0,639622666.0,726454500.0,820491458.0,916645375.0],"unit":"ns","throughput":[],"typical":{"estimate":6499639.045269017,"lower_bound":6447342.124391234,"upper_bound":6529303.7518796995,"unit":"ns"},"mean":{"estimate":6494961.667454649,"lower_bound":6440736.916830783,"upper_bound":6544322.069671203,"unit":"ns"},"median":{"estimate":6507608.069841269,"lower_bound":6426989.580357144,"upper_bound":6543778.285714285,"unit":"ns"},"median_abs_dev":{"estimate":42682.12056724079,"lower_bound":9779.695680542185,"upper_bound":149595.11772629886,"unit":"ns"},"slope":{"estimate":6499639.045269017,"lower_bound":6447342.124391234,"upper_bound":6529303.7518796995,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_10000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[118099208.0,252183834.0,377007084.0,532765375.0,599815667.0,759614125.0,900632416.0,1025282375.0,1157813958.0,1262503500.0],"unit":"ns","throughput":[],"typical":{"estimate":42418492.85454545,"lower_bound":41848256.35153256,"upper_bound":42876049.5047081,"unit":"ns"},"mean":{"estimate":42044513.341309525,"lower_bound":41162303.94947917,"upper_bound":42854413.458730154,"unit":"ns"},"median":{"estimate":42142117.36111111,"lower_bound":41009175.06666666,"upper_bound":42881998.44444445,"unit":"ns"},"median_abs_dev":{"estimate":976931.5877518337,"lower_bound":123914.92478756717,"upper_bound":2475007.408261579,"unit":"ns"},"slope":{"estimate":42418492.85454545,"lower_bound":41848256.35153256,"upper_bound":42876049.5047081,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_10000","iteration_count":[61,122,183,244,305,366,427,488,549,610],"measured_values":[100683750.0,181408625.0,321511667.0,417218750.0,469795292.0,573121666.0,707593583.0,753785709.0,998994666.0,993006167.0],"unit":"ns","throughput":[],"typical":{"estimate":1651653.049776453,"lower_bound":1576589.4593674308,"upper_bound":1737211.3063314264,"unit":"ns"},"mean":{"estimate":1635984.716332943,"lower_bound":1575743.3416666666,"upper_bound":1698988.2876444184,"unit":"ns"},"median":{"estimate":1639216.1204918032,"lower_bound":1544642.8463114754,"upper_bound":1709912.9098360655,"unit":"ns"},"median_abs_dev":{"estimate":124451.81648230065,"lower_bound":18972.652816938695,"upper_bound":174374.77747554006,"unit":"ns"},"slope":{"estimate":1651653.049776453,"lower_bound":1576589.4593674308,"upper_bound":1737211.3063314264,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[101256708.0,228970625.0,347248500.0,424225458.0,608427708.0,700506417.0,828818917.0,889953042.0,1042927916.0,1100330500.0],"unit":"ns","throughput":[],"typical":{"estimate":28476646.318831168,"lower_bound":27819834.966414433,"upper_bound":29296692.818042815,"unit":"ns"},"mean":{"estimate":28288631.458353173,"lower_bound":27349244.162103176,"upper_bound":29130406.392647818,"unit":"ns"},"median":{"estimate":28779351.5625,"lower_bound":27162561.84375,"upper_bound":29285447.748015873,"unit":"ns"},"median_abs_dev":{"estimate":1326662.3654407857,"lower_bound":209963.77999323048,"upper_bound":2515971.8773450702,"unit":"ns"},"slope":{"estimate":28476646.318831168,"lower_bound":27819834.966414433,"upper_bound":29296692.818042815,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_10000","iteration_count":[14,28,42,56,70,84,98,112,126,140],"measured_values":[92255459.0,196599292.0,312970416.0,413528041.0,502435875.0,595993208.0,717202875.0,774693792.0,927217041.0,973075542.0],"unit":"ns","throughput":[],"typical":{"estimate":7135490.784415584,"lower_bound":6996750.97407461,"upper_bound":7310589.439393939,"unit":"ns"},"mean":{"estimate":7126470.793010203,"lower_bound":6963084.881682398,"upper_bound":7275465.769115646,"unit":"ns"},"median":{"estimate":7136406.297619048,"lower_bound":6950539.585714285,"upper_bound":7358865.404761905,"unit":"ns"},"median_abs_dev":{"estimate":300496.44082512194,"lower_bound":49860.917294790896,"upper_bound":487129.8402063596,"unit":"ns"},"slope":{"estimate":7135490.784415584,"lower_bound":6996750.97407461,"upper_bound":7310589.439393939,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_10000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[122707625.0,281117958.0,373370625.0,501168083.0,662839208.0,814528958.0,921802334.0,1516655625.0,1326025208.0,1336858333.0],"unit":"ns","throughput":[],"typical":{"estimate":48398068.46406926,"lower_bound":43971281.20039683,"upper_bound":54565910.79259259,"unit":"ns"},"mean":{"estimate":46120937.868161365,"lower_bound":43080575.56907408,"upper_bound":50455813.49482804,"unit":"ns"},"median":{"estimate":44375612.483333334,"lower_bound":41764006.916666664,"upper_bound":47181826.759259254,"unit":"ns"},"median_abs_dev":{"estimate":3772465.3166003544,"lower_bound":494147.0094571338,"upper_bound":5983249.236311419,"unit":"ns"},"slope":{"estimate":48398068.46406926,"lower_bound":43971281.20039683,"upper_bound":54565910.79259259,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_100_10000","iteration_count":[74,148,222,296,370,444,518,592,666,740],"measured_values":[83370125.0,199727542.0,277395958.0,376735500.0,447367625.0,479160000.0,599031458.0,730457917.0,818971042.0,884105083.0],"unit":"ns","throughput":[],"typical":{"estimate":1199804.386030186,"lower_bound":1161804.9911188425,"upper_bound":1230157.0784997072,"unit":"ns"},"mean":{"estimate":1210144.6868570356,"lower_bound":1165497.906575504,"upper_bound":1255228.1267192191,"unit":"ns"},"median":{"estimate":1219393.9692192192,"lower_bound":1156431.386100386,"upper_bound":1253318.342060811,"unit":"ns"},"median_abs_dev":{"estimate":61897.41580290301,"lower_bound":15259.334101615232,"upper_bound":137541.77571445148,"unit":"ns"},"slope":{"estimate":1199804.386030186,"lower_bound":1161804.9911188425,"upper_bound":1230157.0784997072,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_selective_gt_100/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_selective_gt_100_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[127096292.0,264673417.0,378235875.0,495003041.0,700402083.0,773510375.0,825789958.0,988590792.0,1223288292.0,1242109750.0],"unit":"ns","throughput":[],"typical":{"estimate":31840379.058441557,"lower_bound":30696887.36555475,"upper_bound":33231818.24578908,"unit":"ns"},"mean":{"estimate":31998423.437916666,"lower_bound":31072558.325687494,"upper_bound":32983098.368468743,"unit":"ns"},"median":{"estimate":31646864.625,"lower_bound":30937690.0625,"upper_bound":33104914.645833336,"unit":"ns"},"median_abs_dev":{"estimate":1084208.2645202056,"lower_bound":150861.45067792386,"upper_bound":2662511.317443475,"unit":"ns"},"slope":{"estimate":31840379.058441557,"lower_bound":30696887.36555475,"upper_bound":33231818.24578908,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_10_10000","iteration_count":[58,116,174,232,290,348,406,464,522,580],"measured_values":[68352917.0,103183875.0,153200417.0,302008792.0,373519125.0,838392042.0,473399250.0,1056715541.0,559766458.0,1064213833.0],"unit":"ns","throughput":[],"typical":{"estimate":1625072.1223914018,"lower_bound":1182881.1678455644,"upper_bound":2000788.9124602152,"unit":"ns"},"mean":{"estimate":1429802.161187055,"lower_bound":1129775.1699549125,"upper_bound":1772003.5610823755,"unit":"ns"},"median":{"estimate":1233247.7758620689,"lower_bound":1027762.0843596058,"upper_bound":1834851.4362068966,"unit":"ns"},"median_abs_dev":{"estimate":374082.10229980695,"lower_bound":78688.27644495788,"upper_bound":912298.5944413933,"unit":"ns"},"slope":{"estimate":1625072.1223914018,"lower_bound":1182881.1678455644,"upper_bound":2000788.9124602152,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_highly_selective_gt_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_highly_selective_gt_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[98134208.0,251304459.0,330804708.0,455459833.0,603813917.0,751628833.0,831123750.0,932282917.0,1416620875.0,993113083.0],"unit":"ns","throughput":[],"typical":{"estimate":30454991.854545455,"lower_bound":26614834.230433103,"upper_bound":35257547.21563574,"unit":"ns"},"mean":{"estimate":29648371.099295635,"lower_bound":27427116.656930055,"upper_bound":32303106.51796131,"unit":"ns"},"median":{"estimate":29408416.113839284,"lower_bound":26647033.31875,"upper_bound":31317868.041666668,"unit":"ns"},"median_abs_dev":{"estimate":2780474.6932242075,"lower_bound":752723.0913464968,"upper_bound":6138542.623929085,"unit":"ns"},"slope":{"estimate":30454991.854545455,"lower_bound":26614834.230433103,"upper_bound":35257547.21563574,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_10000","iteration_count":[44,88,132,176,220,264,308,352,396,440],"measured_values":[72966834.0,186365708.0,413354083.0,244496417.0,507432042.0,949833917.0,396053250.0,478599875.0,517766125.0,629880000.0],"unit":"ns","throughput":[],"typical":{"estimate":1680034.0468713106,"lower_bound":1378161.129334583,"upper_bound":2344547.663539652,"unit":"ns"},"mean":{"estimate":1958573.0394327198,"lower_bound":1517977.3617920727,"upper_bound":2478705.8778937333,"unit":"ns"},"median":{"estimate":1544941.2954545454,"lower_bound":1348337.2010732323,"upper_bound":2624631.231060606,"unit":"ns"},"median_abs_dev":{"estimate":368059.29892094416,"lower_bound":53289.62366329506,"upper_bound":1313443.9083206297,"unit":"ns"},"slope":{"estimate":1680034.0468713106,"lower_bound":1378161.129334583,"upper_bound":2344547.663539652,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_10000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[123593000.0,209077417.0,435705625.0,467093833.0,597752333.0,780116292.0,864227500.0,923904625.0,1079613333.0,1125690833.0],"unit":"ns","throughput":[],"typical":{"estimate":29740881.353896104,"lower_bound":28813093.657908916,"upper_bound":31121270.759383626,"unit":"ns"},"mean":{"estimate":30279637.33842262,"lower_bound":28787302.092499994,"upper_bound":31993762.223750003,"unit":"ns"},"median":{"estimate":29938437.95,"lower_bound":28667817.69375,"upper_bound":31685056.67857143,"unit":"ns"},"median_abs_dev":{"estimate":1502044.6198177524,"lower_bound":589996.7213692144,"upper_bound":4270283.203879814,"unit":"ns"},"slope":{"estimate":29740881.353896104,"lower_bound":28813093.657908916,"upper_bound":31121270.759383626,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_count/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_count_10000","iteration_count":[91,182,273,364,455,546,637,728,819,910],"measured_values":[86678958.0,169379792.0,289815000.0,330726208.0,430946500.0,516899875.0,565912334.0,658830250.0,778187625.0,994426125.0],"unit":"ns","throughput":[],"typical":{"estimate":971996.5273868989,"lower_bound":913138.4512248115,"upper_bound":1038027.5447333154,"unit":"ns"},"mean":{"estimate":958352.7359628467,"lower_bound":923196.1837388802,"upper_bound":1000863.0817621666,"unit":"ns"},"median":{"estimate":946919.1163003664,"lower_bound":908588.4835164836,"upper_bound":1005880.7234432234,"unit":"ns"},"median_abs_dev":{"estimate":40468.71624692134,"lower_bound":2568.584089013907,"upper_bound":89325.45403283738,"unit":"ns"},"slope":{"estimate":971996.5273868989,"lower_bound":913138.4512248115,"upper_bound":1038027.5447333154,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_count/10000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_count_10000","iteration_count":[104,208,312,416,520,624,728,832,936,1040],"measured_values":[88732125.0,177465792.0,280168542.0,341737417.0,430086625.0,564671667.0,565849000.0,709283208.0,867623375.0,823999750.0],"unit":"ns","throughput":[],"typical":{"estimate":845988.9777472528,"lower_bound":803163.7657493369,"upper_bound":895773.2979817021,"unit":"ns"},"mean":{"estimate":850689.1378853784,"lower_bound":822543.5762809066,"upper_bound":879397.7530929486,"unit":"ns"},"median":{"estimate":852848.6826923077,"lower_bound":809698.5576923077,"upper_bound":897976.0961538461,"unit":"ns"},"median_abs_dev":{"estimate":56703.45978826424,"lower_bound":522.2315849592919,"upper_bound":86256.68282056079,"unit":"ns"},"slope":{"estimate":845988.9777472528,"lower_bound":803163.7657493369,"upper_bound":895773.2979817021,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_10/10000","ORE/ore_decrypt/range_gt_10/10000","ORE/ore/range_gt_100/10000","ORE/ore_decrypt/range_gt_100/10000","ORE/ore/range_lt_10/10000","ORE/ore_decrypt/range_lt_10/10000","ORE/ore/range_lt_100/10000","ORE/ore_decrypt/range_lt_100/10000","ORE/ore/range_selective_gt_100/10000","ORE/ore_decrypt/range_selective_gt_100/10000","ORE/ore/range_highly_selective_gt_10/10000","ORE/ore_decrypt/range_highly_selective_gt_10/10000","ORE/ore/range_lt_hybrid_ordered_10/10000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000","ORE/ore/range_selective_gt_count/10000","ORE/ore/range_highly_selective_gt_count/10000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} diff --git a/results/query/ore_rows_100000.json b/results/query/ore_rows_100000.json index d158153..e8d28ee 100644 --- a/results/query/ore_rows_100000.json +++ b/results/query/ore_rows_100000.json @@ -1,15 +1,17 @@ -{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_100000","iteration_count":[417,834,1251,1668,2085,2502,2919,3336,3753,4170],"measured_values":[541499083.0,1112687625.0,1970853084.0,2381332250.0,2717736500.0,3484443708.0,3925985125.0,4626398459.0,5339353083.0,5614776167.0],"unit":"ns","throughput":[],"typical":{"estimate":1379022.2697499143,"lower_bound":1351338.597595711,"upper_bound":1412140.854466427,"unit":"ns"},"mean":{"estimate":1383287.48191818,"lower_bound":1341167.5942840013,"upper_bound":1435084.9775672317,"unit":"ns"},"median":{"estimate":1366639.5972122303,"lower_bound":1324223.4027064063,"upper_bound":1422689.337330136,"unit":"ns"},"median_abs_dev":{"estimate":65628.40985848404,"lower_bound":8678.047406185491,"upper_bound":119388.3062322025,"unit":"ns"},"slope":{"estimate":1379022.2697499143,"lower_bound":1351338.597595711,"upper_bound":1412140.854466427,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_100000","iteration_count":[19,38,57,76,95,114,133,152,171,190],"measured_values":[526732625.0,1102360125.0,1608775875.0,2089966250.0,2674440667.0,3323891917.0,3744356917.0,4294699166.0,4814632542.0,5329348208.0],"unit":"ns","throughput":[],"typical":{"estimate":28219612.719343815,"lower_bound":28054455.459970348,"upper_bound":28499218.805036787,"unit":"ns"},"mean":{"estimate":28237750.070789468,"lower_bound":27956931.26525877,"upper_bound":28549810.29441886,"unit":"ns"},"median":{"estimate":28154402.692982458,"lower_bound":27937388.37894737,"upper_bound":28616807.565789476,"unit":"ns"},"median_abs_dev":{"estimate":152262.0399512834,"lower_bound":3551.823140098462,"upper_bound":931378.40389762,"unit":"ns"},"slope":{"estimate":28219612.719343815,"lower_bound":28054455.459970348,"upper_bound":28499218.805036787,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_100000","iteration_count":[83,166,249,332,415,498,581,664,747,830],"measured_values":[543975000.0,1102662417.0,1561932041.0,2172263875.0,2851406125.0,3286055458.0,3871716792.0,4552995958.0,5036974708.0,5682290833.0],"unit":"ns","throughput":[],"typical":{"estimate":6752595.235174464,"lower_bound":6646764.821081108,"upper_bound":6816004.961956593,"unit":"ns"},"mean":{"estimate":6659148.384258941,"lower_bound":6546038.197349397,"upper_bound":6761087.328507364,"unit":"ns"},"median":{"estimate":6653214.502151463,"lower_bound":6553915.662650603,"upper_bound":6846133.53373494,"unit":"ns"},"median_abs_dev":{"estimate":155339.31048886274,"lower_bound":20662.26793015887,"upper_bound":334662.83511457243,"unit":"ns"},"slope":{"estimate":6752595.235174464,"lower_bound":6646764.821081108,"upper_bound":6816004.961956593,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_100000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[590660833.0,1113445459.0,1708722708.0,2279846166.0,2911576083.0,3405679625.0,4076850958.0,4603766125.0,5068511000.0,5731192500.0],"unit":"ns","throughput":[],"typical":{"estimate":47695167.18831169,"lower_bound":47277129.46459538,"upper_bound":48123233.47553191,"unit":"ns"},"mean":{"estimate":47758441.763845906,"lower_bound":47271587.470822334,"upper_bound":48256245.70449405,"unit":"ns"},"median":{"estimate":47628366.3125,"lower_bound":47197588.53703704,"upper_bound":48526268.05,"unit":"ns"},"median_abs_dev":{"estimate":760010.1968803816,"lower_bound":145064.41785792634,"upper_bound":1476293.5102413811,"unit":"ns"},"slope":{"estimate":47695167.18831169,"lower_bound":47277129.46459538,"upper_bound":48123233.47553191,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_100000","iteration_count":[375,750,1125,1500,1875,2250,2625,3000,3375,3750],"measured_values":[534974750.0,1095068583.0,1569239125.0,2299250292.0,2742920542.0,3720798375.0,4256582334.0,4519493000.0,5558433083.0,5747091125.0],"unit":"ns","throughput":[],"typical":{"estimate":1566185.6467809523,"lower_bound":1514002.764659176,"upper_bound":1616302.014556213,"unit":"ns"},"mean":{"estimate":1523853.62605164,"lower_bound":1471173.3942946666,"upper_bound":1579015.519666455,"unit":"ns"},"median":{"estimate":1519527.65,"lower_bound":1444745.1445333334,"upper_bound":1621555.1748571428,"unit":"ns"},"median_abs_dev":{"estimate":112947.81864757538,"lower_bound":19522.773659801376,"upper_bound":161494.15850597245,"unit":"ns"},"slope":{"estimate":1566185.6467809523,"lower_bound":1514002.764659176,"upper_bound":1616302.014556213,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_100000","iteration_count":[20,40,60,80,100,120,140,160,180,200],"measured_values":[580265041.0,1128292166.0,1685074500.0,2267655250.0,2803244875.0,3433411959.0,3914820916.0,4520093125.0,5212648708.0,5663049083.0],"unit":"ns","throughput":[],"typical":{"estimate":28401066.313766234,"lower_bound":28142247.581462584,"upper_bound":28682764.604530018,"unit":"ns"},"mean":{"estimate":28378303.037799604,"lower_bound":28175384.366611503,"upper_bound":28605338.595178425,"unit":"ns"},"median":{"estimate":28282913.723125,"lower_bound":28084575.0,"upper_bound":28652425.056944445,"unit":"ns"},"median_abs_dev":{"estimate":332698.17412355106,"lower_bound":70503.9992951788,"upper_bound":623013.1200993083,"unit":"ns"},"slope":{"estimate":28401066.313766234,"lower_bound":28142247.581462584,"upper_bound":28682764.604530018,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_100000","iteration_count":[83,166,249,332,415,498,581,664,747,830],"measured_values":[551059584.0,1073733500.0,1573166875.0,2169676292.0,2863928292.0,3261997209.0,3787300458.0,4417626167.0,5015883042.0,5694026291.0],"unit":"ns","throughput":[],"typical":{"estimate":6694529.1791894855,"lower_bound":6568817.410493274,"upper_bound":6787432.445405206,"unit":"ns"},"mean":{"estimate":6615849.862385254,"lower_bound":6513325.388260218,"upper_bound":6720871.5720767,"unit":"ns"},"median":{"estimate":6594733.647590362,"lower_bound":6501721.825301205,"upper_bound":6756662.048042169,"unit":"ns"},"median_abs_dev":{"estimate":145378.88967443097,"lower_bound":23429.357050914252,"upper_bound":294120.85919879325,"unit":"ns"},"slope":{"estimate":6694529.1791894855,"lower_bound":6568817.410493274,"upper_bound":6787432.445405206,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_100000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[581007208.0,1176711709.0,1633638084.0,2307465834.0,2870523958.0,3300506959.0,3934647000.0,4506712042.0,4964302875.0,5686214125.0],"unit":"ns","throughput":[],"typical":{"estimate":46830727.7530303,"lower_bound":46291754.83278146,"upper_bound":47340187.352810174,"unit":"ns"},"mean":{"estimate":47171724.070178576,"lower_bound":46469625.673799604,"upper_bound":47873049.30758185,"unit":"ns"},"median":{"estimate":47165017.40625,"lower_bound":45965767.36111111,"upper_bound":48129666.650000006,"unit":"ns"},"median_abs_dev":{"estimate":1561502.1013236288,"lower_bound":341203.9394374162,"upper_bound":2039736.550294106,"unit":"ns"},"slope":{"estimate":46830727.7530303,"lower_bound":46291754.83278146,"upper_bound":47340187.352810174,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_ordered_10_100000","iteration_count":[1,2,3,4,5,6,7,8,9,10],"measured_values":[880584792.0,1750336083.0,2623175625.0,2109022333.0,706744291.0,866724250.0,993600000.0,1161758458.0,1272025166.0,1433145959.0],"unit":"ns","throughput":[],"typical":{"estimate":185584139.9168831,"lower_bound":147430922.8815095,"upper_bound":288224566.5248869,"unit":"ns"},"mean":{"estimate":401501658.14650786,"lower_bound":215991063.19928575,"upper_bound":621450208.3597025,"unit":"ns"},"median":{"estimate":144836924.4583333,"lower_bound":141942857.14285713,"upper_bound":874391875.0,"unit":"ns"},"median_abs_dev":{"estimate":5180842.686753305,"lower_bound":575372.2162351012,"upper_bound":542522949.5915723,"unit":"ns"},"slope":{"estimate":185584139.9168831,"lower_bound":147430922.8815095,"upper_bound":288224566.5248869,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ordered_10_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[668223375.0,1403319291.0,2126737625.0,2695468083.0,3467278583.0,4184839917.0,4983647459.0,5751391333.0,6534042208.0,7145911542.0],"unit":"ns","throughput":[],"typical":{"estimate":178080868.66883117,"lower_bound":175208277.3112607,"upper_bound":179712841.46705395,"unit":"ns"},"mean":{"estimate":175376525.4154861,"lower_bound":172492187.5758924,"upper_bound":177993124.34736112,"unit":"ns"},"median":{"estimate":176321523.3958333,"lower_bound":171417542.53125,"upper_bound":178859194.203125,"unit":"ns"},"median_abs_dev":{"estimate":3916924.9036806864,"lower_bound":1052388.8490563794,"upper_bound":8306458.617952139,"unit":"ns"},"slope":{"estimate":178080868.66883117,"lower_bound":175208277.3112607,"upper_bound":179712841.46705395,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_100000","iteration_count":[402,804,1206,1608,2010,2412,2814,3216,3618,4020],"measured_values":[455982708.0,959501250.0,1628467417.0,2179276750.0,2654023042.0,3129472792.0,3492145125.0,4079736500.0,4640080625.0,4996751875.0],"unit":"ns","throughput":[],"typical":{"estimate":1271794.2667894296,"lower_bound":1254104.5507743151,"upper_bound":1298623.0395757924,"unit":"ns"},"mean":{"estimate":1268617.6713405198,"lower_bound":1226171.2960751797,"upper_bound":1307673.7172857933,"unit":"ns"},"median":{"estimate":1275536.7865533442,"lower_bound":1218191.309079602,"upper_bound":1323882.1778606963,"unit":"ns"},"median_abs_dev":{"estimate":58873.84838119822,"lower_bound":20448.792407483692,"upper_bound":118993.57961181997,"unit":"ns"},"slope":{"estimate":1271794.2667894296,"lower_bound":1254104.5507743151,"upper_bound":1298623.0395757924,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_100000","iteration_count":[20,40,60,80,100,120,140,160,180,200],"measured_values":[563447083.0,1130293834.0,1884639625.0,2273686542.0,3166591583.0,4078655333.0,3941790000.0,4596504959.0,5163361583.0,5493369167.0],"unit":"ns","throughput":[],"typical":{"estimate":29044948.73974026,"lower_bound":28064602.36676768,"upper_bound":30893463.89687684,"unit":"ns"},"mean":{"estimate":29495213.927700393,"lower_bound":28363171.86117064,"upper_bound":30825692.142373018,"unit":"ns"},"median":{"estimate":28553211.951388888,"lower_bound":28172354.15,"upper_bound":31410660.416666668,"unit":"ns"},"median_abs_dev":{"estimate":577047.8474895186,"lower_bound":87780.50844158288,"upper_bound":3524786.431487905,"unit":"ns"},"slope":{"estimate":29044948.73974026,"lower_bound":28064602.36676768,"upper_bound":30893463.89687684,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore/range_lt_ore_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_ore_ordered_10_100000","iteration_count":[431,862,1293,1724,2155,2586,3017,3448,3879,4310],"measured_values":[536311042.0,1073394000.0,1673205292.0,2204959625.0,2633848709.0,3079843125.0,3579065041.0,4350838958.0,4704162208.0,5384853917.0],"unit":"ns","throughput":[],"typical":{"estimate":1230704.9248561184,"lower_bound":1207471.68820029,"upper_bound":1251880.522512073,"unit":"ns"},"mean":{"estimate":1238603.2324752328,"lower_bound":1217650.072351209,"upper_bound":1259405.9713524887,"unit":"ns"},"median":{"estimate":1244788.9118329468,"lower_bound":1206585.764849188,"upper_bound":1264182.4802204175,"unit":"ns"},"median_abs_dev":{"estimate":40511.116232044726,"lower_bound":4403.610358038365,"upper_bound":62720.529845745514,"unit":"ns"},"slope":{"estimate":1230704.9248561184,"lower_bound":1207471.68820029,"upper_bound":1251880.522512073,"unit":"ns"},"change":null} -{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_ore_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_ore_ordered_10_100000","iteration_count":[20,40,60,80,100,120,140,160,180,200],"measured_values":[581560667.0,1097378833.0,1690728000.0,2207938500.0,2833715209.0,3359506167.0,4062331458.0,4400675666.0,5210557875.0,5776528291.0],"unit":"ns","throughput":[],"typical":{"estimate":28481545.285584416,"lower_bound":27888333.72010582,"upper_bound":28835397.819923725,"unit":"ns"},"mean":{"estimate":28297463.362892855,"lower_bound":27911479.929,"upper_bound":28678495.227995533,"unit":"ns"},"median":{"estimate":28257976.045,"lower_bound":27599231.25,"upper_bound":28949647.363214284,"unit":"ns"},"median_abs_dev":{"estimate":999504.0385052562,"lower_bound":99342.95775481033,"upper_bound":1073528.868960052,"unit":"ns"},"slope":{"estimate":28481545.285584416,"lower_bound":27888333.72010582,"upper_bound":28835397.819923725,"unit":"ns"},"change":null} -{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_10/100000","ORE/ore_decrypt/range_gt_10/100000","ORE/ore/range_gt_100/100000","ORE/ore_decrypt/range_gt_100/100000","ORE/ore/range_lt_10/100000","ORE/ore_decrypt/range_lt_10/100000","ORE/ore/range_lt_100/100000","ORE/ore_decrypt/range_lt_100/100000","ORE/ore/range_lt_ordered_10/100000","ORE/ore_decrypt/range_lt_ordered_10/100000","ORE/ore/range_lt_hybrid_ordered_10/100000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/100000","ORE/ore/range_lt_ore_ordered_10/100000","ORE/ore_decrypt/range_lt_ore_ordered_10/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_100000","iteration_count":[61,122,183,244,305,366,427,488,549,610],"measured_values":[84963042.0,195267584.0,255369542.0,391074458.0,515380917.0,607069000.0,693593875.0,845030083.0,908624667.0,1042075583.0],"unit":"ns","throughput":[],"typical":{"estimate":1670811.1081541409,"lower_bound":1624524.440861672,"upper_bound":1699713.2528962684,"unit":"ns"},"mean":{"estimate":1605938.4156186571,"lower_bound":1530234.586885246,"upper_bound":1669989.1960792348,"unit":"ns"},"median":{"estimate":1639697.8329430134,"lower_bound":1499113.075136612,"upper_bound":1689773.4983606557,"unit":"ns"},"median_abs_dev":{"estimate":66138.43726548017,"lower_bound":17271.09966382752,"upper_bound":161658.53617847105,"unit":"ns"},"slope":{"estimate":1670811.1081541409,"lower_bound":1624524.440861672,"upper_bound":1699713.2528962684,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[108817792.0,224469083.0,390099125.0,516315167.0,602043500.0,655489625.0,836792625.0,894059042.0,1054077875.0,1179826459.0],"unit":"ns","throughput":[],"typical":{"estimate":29241204.822727274,"lower_bound":28514427.09352941,"upper_bound":30017528.899371214,"unit":"ns"},"mean":{"estimate":29405568.284007944,"lower_bound":28349118.272619046,"upper_bound":30547353.750535708,"unit":"ns"},"median":{"estimate":29387801.223611113,"lower_bound":27685351.541666664,"upper_bound":31077574.41517857,"unit":"ns"},"median_abs_dev":{"estimate":2059051.1592516203,"lower_bound":319827.211740265,"upper_bound":3526346.951312329,"unit":"ns"},"slope":{"estimate":29241204.822727274,"lower_bound":28514427.09352941,"upper_bound":30017528.899371214,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_100000","iteration_count":[13,26,39,52,65,78,91,104,117,130],"measured_values":[85457416.0,183861792.0,253169792.0,358935125.0,441596500.0,655553500.0,639330291.0,767503000.0,816201500.0,892910833.0],"unit":"ns","throughput":[],"typical":{"estimate":7128869.579020979,"lower_bound":6885325.481697639,"upper_bound":7513390.540494082,"unit":"ns"},"mean":{"estimate":7048778.101178266,"lower_bound":6780861.6597680105,"upper_bound":7401699.727900182,"unit":"ns"},"median":{"estimate":6939339.877136752,"lower_bound":6721096.126923077,"upper_bound":7202722.065934066,"unit":"ns"},"median_abs_dev":{"estimate":205944.31286683455,"lower_bound":70813.56193255153,"upper_bound":633362.2763427518,"unit":"ns"},"slope":{"estimate":7128869.579020979,"lower_bound":6885325.481697639,"upper_bound":7513390.540494082,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_100000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[89169083.0,201183250.0,271543458.0,336430625.0,476808667.0,544305042.0,616937834.0,672194167.0,784681834.0,908324125.0],"unit":"ns","throughput":[],"typical":{"estimate":44341893.47272728,"lower_bound":43205091.44782609,"upper_bound":45530445.2322335,"unit":"ns"},"mean":{"estimate":45031981.03775793,"lower_bound":43665457.928624004,"upper_bound":46593066.68945089,"unit":"ns"},"median":{"estimate":44920892.25,"lower_bound":43060408.13392857,"upper_bound":46519810.1,"unit":"ns"},"median_abs_dev":{"estimate":1617042.9806084146,"lower_bound":117839.45513293147,"upper_bound":4171323.6215917044,"unit":"ns"},"slope":{"estimate":44341893.47272728,"lower_bound":43205091.44782609,"upper_bound":45530445.2322335,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_100000","iteration_count":[60,120,180,240,300,360,420,480,540,600],"measured_values":[90831083.0,201185875.0,287375875.0,361909083.0,447793834.0,549282292.0,563773750.0,646471167.0,816425583.0,954525708.0],"unit":"ns","throughput":[],"typical":{"estimate":1486965.4816017316,"lower_bound":1400129.103288595,"upper_bound":1559414.707184196,"unit":"ns"},"mean":{"estimate":1510522.6542242065,"lower_bound":1448419.5582261905,"upper_bound":1569454.7585545138,"unit":"ns"},"median":{"estimate":1512875.3055555555,"lower_bound":1427384.7218749998,"upper_bound":1590876.18,"unit":"ns"},"median_abs_dev":{"estimate":72817.947127223,"lower_bound":4371.350271143203,"upper_bound":185115.73338624724,"unit":"ns"},"slope":{"estimate":1486965.4816017316,"lower_bound":1400129.103288595,"upper_bound":1559414.707184196,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[120500750.0,250018500.0,316287125.0,439056167.0,544930750.0,718367833.0,808927458.0,970008459.0,1033796541.0,1097088958.0],"unit":"ns","throughput":[],"typical":{"estimate":28609157.706493508,"lower_bound":27768025.733674154,"upper_bound":29546396.288912285,"unit":"ns"},"mean":{"estimate":28770112.663005956,"lower_bound":27830779.900411457,"upper_bound":29721818.01146801,"unit":"ns"},"median":{"estimate":28803418.470238097,"lower_bound":27343773.96875,"upper_bound":30125187.5,"unit":"ns"},"median_abs_dev":{"estimate":2030126.0364793113,"lower_bound":154382.70901165958,"upper_bound":2715283.1971190907,"unit":"ns"},"slope":{"estimate":28609157.706493508,"lower_bound":27768025.733674154,"upper_bound":29546396.288912285,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_100000","iteration_count":[13,26,39,52,65,78,91,104,117,130],"measured_values":[89618542.0,171344542.0,272284917.0,353463833.0,449937334.0,535563167.0,629267375.0,720451708.0,822998250.0,879647583.0],"unit":"ns","throughput":[],"typical":{"estimate":6892713.036963037,"lower_bound":6810515.819055837,"upper_bound":6974870.288339038,"unit":"ns"},"mean":{"estimate":6869440.122838828,"lower_bound":6790397.888909341,"upper_bound":6937152.29014652,"unit":"ns"},"median":{"estimate":6904380.049450549,"lower_bound":6797381.403846154,"upper_bound":6951888.684615385,"unit":"ns"},"median_abs_dev":{"estimate":85597.9760072547,"lower_bound":10506.788481159747,"upper_bound":190701.6426632147,"unit":"ns"},"slope":{"estimate":6892713.036963037,"lower_bound":6810515.819055837,"upper_bound":6974870.288339038,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_100000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[151452416.0,283585375.0,424892625.0,567920500.0,700109417.0,810971334.0,977457625.0,1017248125.0,1237922417.0,1383016834.0],"unit":"ns","throughput":[],"typical":{"estimate":45526421.2969697,"lower_bound":44218021.4877451,"upper_bound":46485022.71826722,"unit":"ns"},"mean":{"estimate":46489377.123955026,"lower_bound":45275893.88247718,"upper_bound":47683468.89329761,"unit":"ns"},"median":{"estimate":46609781.16190477,"lower_bound":45577262.06666666,"upper_bound":47268500.0,"unit":"ns"},"median_abs_dev":{"estimate":1016600.4000617273,"lower_bound":95153.22395069512,"upper_bound":3308366.0460847626,"unit":"ns"},"slope":{"estimate":45526421.2969697,"lower_bound":44218021.4877451,"upper_bound":46485022.71826722,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_100_100000","iteration_count":[46,92,138,184,230,276,322,368,414,460],"measured_values":[79927834.0,171424208.0,454250542.0,340808125.0,414679750.0,538659875.0,637550083.0,709478000.0,766710542.0,889581750.0],"unit":"ns","throughput":[],"typical":{"estimate":1941784.6038961038,"lower_bound":1879916.8330298201,"upper_bound":2062220.1912675512,"unit":"ns"},"mean":{"estimate":2019310.8280969635,"lower_bound":1843645.9758454107,"upper_bound":2319184.8520341613,"unit":"ns"},"median":{"estimate":1895617.9782608696,"lower_bound":1827586.7527173911,"upper_bound":1956921.2857142857,"unit":"ns"},"median_abs_dev":{"estimate":73913.82289465144,"lower_bound":8412.848817308897,"upper_bound":179696.7456249625,"unit":"ns"},"slope":{"estimate":1941784.6038961038,"lower_bound":1879916.8330298201,"upper_bound":2062220.1912675512,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_selective_gt_100/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_selective_gt_100_100000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[124778625.0,285703125.0,354839833.0,495228750.0,615146000.0,711237542.0,857965542.0,974166708.0,1109896250.0,1263102959.0],"unit":"ns","throughput":[],"typical":{"estimate":41128972.22857143,"lower_bound":40455929.91280353,"upper_bound":41717825.84472592,"unit":"ns"},"mean":{"estimate":41508518.52074073,"lower_bound":40438305.97483333,"upper_bound":43039701.16455555,"unit":"ns"},"median":{"estimate":41058500.925925925,"lower_bound":40184349.38888889,"upper_bound":41686247.233333334,"unit":"ns"},"median_abs_dev":{"estimate":743224.0309551358,"lower_bound":186634.5168643501,"upper_bound":2152438.5594199095,"unit":"ns"},"slope":{"estimate":41128972.22857143,"lower_bound":40455929.91280353,"upper_bound":41717825.84472592,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_10_100000","iteration_count":[104,208,312,416,520,624,728,832,936,1040],"measured_values":[79966000.0,168624833.0,292855417.0,377525292.0,437269542.0,594280708.0,676456000.0,726041084.0,818679042.0,974508583.0],"unit":"ns","throughput":[],"typical":{"estimate":904461.3617132867,"lower_bound":875962.6732075668,"upper_bound":930149.2352831196,"unit":"ns"},"mean":{"estimate":883255.584739011,"lower_bound":845725.8551662087,"upper_bound":917362.1347031823,"unit":"ns"},"median":{"estimate":891084.9086538461,"lower_bound":840902.9653846154,"upper_bound":937027.4836538462,"unit":"ns"},"median_abs_dev":{"estimate":69309.1939540351,"lower_bound":6998.8762286297515,"upper_bound":104511.97597502229,"unit":"ns"},"slope":{"estimate":904461.3617132867,"lower_bound":875962.6732075668,"upper_bound":930149.2352831196,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_highly_selective_gt_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_highly_selective_gt_10_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[104502708.0,223294667.0,320149750.0,452281792.0,564169416.0,659206917.0,731727041.0,875306583.0,1093217208.0,1135834625.0],"unit":"ns","throughput":[],"typical":{"estimate":28193896.17857143,"lower_bound":27035393.30461511,"upper_bound":29253176.268666666,"unit":"ns"},"mean":{"estimate":27690914.35008929,"lower_bound":26989281.524255954,"upper_bound":28471035.90250372,"unit":"ns"},"median":{"estimate":27689394.125,"lower_bound":26679145.833333332,"upper_bound":28302168.2125,"unit":"ns"},"median_abs_dev":{"estimate":952340.2167800814,"lower_bound":138915.7813062541,"upper_bound":2234140.239926708,"unit":"ns"},"slope":{"estimate":28193896.17857143,"lower_bound":27035393.30461511,"upper_bound":29253176.268666666,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_100000","iteration_count":[68,136,204,272,340,408,476,544,612,680],"measured_values":[83426625.0,218551959.0,355335500.0,592718458.0,461151541.0,508403291.0,635128500.0,826734666.0,898742459.0,939282542.0],"unit":"ns","throughput":[],"typical":{"estimate":1445946.2454163483,"lower_bound":1366022.099444046,"upper_bound":1569455.2080416353,"unit":"ns"},"mean":{"estimate":1506109.6753373016,"lower_bound":1359302.6012114845,"upper_bound":1689004.2066850783,"unit":"ns"},"median":{"estimate":1424915.6428104574,"lower_bound":1301207.2796568628,"upper_bound":1630786.7640931373,"unit":"ns"},"median_abs_dev":{"estimate":202854.03147472412,"lower_bound":34836.8624471105,"upper_bound":386012.68162852287,"unit":"ns"},"slope":{"estimate":1445946.2454163483,"lower_bound":1366022.099444046,"upper_bound":1569455.2080416353,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_100000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[110119083.0,259542875.0,338014958.0,499617125.0,539948000.0,706297333.0,816999875.0,866085041.0,1029913167.0,1199943333.0],"unit":"ns","throughput":[],"typical":{"estimate":28893229.53961039,"lower_bound":27922568.80187761,"upper_bound":29732885.90078125,"unit":"ns"},"mean":{"estimate":29064407.60497024,"lower_bound":28071046.18703125,"upper_bound":30150440.28042262,"unit":"ns"},"median":{"estimate":28893633.023809522,"lower_bound":27529770.75,"upper_bound":30327562.927083336,"unit":"ns"},"median_abs_dev":{"estimate":1830130.7293561841,"lower_bound":422443.05265013635,"upper_bound":3084484.589980077,"unit":"ns"},"slope":{"estimate":28893229.53961039,"lower_bound":27922568.80187761,"upper_bound":29732885.90078125,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_count/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_count_100000","iteration_count":[60,120,180,240,300,360,420,480,540,600],"measured_values":[95285458.0,159484208.0,281896958.0,395559417.0,435420125.0,531963708.0,549417375.0,649144958.0,772566250.0,851366250.0],"unit":"ns","throughput":[],"typical":{"estimate":1416316.247965368,"lower_bound":1373451.4893459915,"upper_bound":1470024.4244897927,"unit":"ns"},"mean":{"estimate":1457060.5792328042,"lower_bound":1391818.9770767195,"upper_bound":1525468.5636574074,"unit":"ns"},"median":{"estimate":1441039.3287037038,"lower_bound":1352385.3291666666,"upper_bound":1566094.211111111,"unit":"ns"},"median_abs_dev":{"estimate":148747.96666405705,"lower_bound":24060.126572847425,"upper_bound":192038.13526064152,"unit":"ns"},"slope":{"estimate":1416316.247965368,"lower_bound":1373451.4893459915,"upper_bound":1470024.4244897927,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_count/100000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_count_100000","iteration_count":[90,180,270,360,450,540,630,720,810,900],"measured_values":[86660792.0,183449209.0,320459875.0,380692583.0,547042625.0,570976417.0,664739917.0,681692125.0,679639292.0,753798917.0],"unit":"ns","throughput":[],"typical":{"estimate":948347.475064935,"lower_bound":880062.9842293906,"upper_bound":1076453.055446015,"unit":"ns"},"mean":{"estimate":1017799.4347217815,"lower_bound":943741.2292557321,"upper_bound":1092512.4078015871,"unit":"ns"},"median":{"estimate":1037152.4988095239,"lower_bound":900979.2716049383,"upper_bound":1122126.0805555554,"unit":"ns"},"median_abs_dev":{"estimate":122027.3854306643,"lower_bound":1817.9150599479851,"upper_bound":243319.64200076822,"unit":"ns"},"slope":{"estimate":948347.475064935,"lower_bound":880062.9842293906,"upper_bound":1076453.055446015,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_10/100000","ORE/ore_decrypt/range_gt_10/100000","ORE/ore/range_gt_100/100000","ORE/ore_decrypt/range_gt_100/100000","ORE/ore/range_lt_10/100000","ORE/ore_decrypt/range_lt_10/100000","ORE/ore/range_lt_100/100000","ORE/ore_decrypt/range_lt_100/100000","ORE/ore/range_selective_gt_100/100000","ORE/ore_decrypt/range_selective_gt_100/100000","ORE/ore/range_highly_selective_gt_10/100000","ORE/ore_decrypt/range_highly_selective_gt_10/100000","ORE/ore/range_lt_hybrid_ordered_10/100000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/100000","ORE/ore/range_selective_gt_count/100000","ORE/ore/range_highly_selective_gt_count/100000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} diff --git a/results/query/ore_rows_1000000.json b/results/query/ore_rows_1000000.json index e69de29..097fee8 100644 --- a/results/query/ore_rows_1000000.json +++ b/results/query/ore_rows_1000000.json @@ -0,0 +1,17 @@ +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_1000000","iteration_count":[67,134,201,268,335,402,469,536,603,670],"measured_values":[98177458.0,199158958.0,243520792.0,307138917.0,432109458.0,531410542.0,621395208.0,855679625.0,727737875.0,904908667.0],"unit":"ns","throughput":[],"typical":{"estimate":1341289.2018220585,"lower_bound":1245010.1091096243,"upper_bound":1453372.0789363044,"unit":"ns"},"mean":{"estimate":1339980.4575580433,"lower_bound":1259972.9784577116,"upper_bound":1426368.1507587065,"unit":"ns"},"median":{"estimate":1323426.6243781094,"lower_bound":1211546.2288557214,"upper_bound":1465335.1940298507,"unit":"ns"},"median_abs_dev":{"estimate":169346.1808333052,"lower_bound":21270.253661332983,"upper_bound":236692.97822136694,"unit":"ns"},"slope":{"estimate":1341289.2018220585,"lower_bound":1245010.1091096243,"upper_bound":1453372.0789363044,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[132688875.0,236194792.0,317251375.0,497382750.0,568525791.0,711172166.0,846947667.0,915097708.0,1099675292.0,1183853792.0],"unit":"ns","throughput":[],"typical":{"estimate":29637049.62077922,"lower_bound":28963933.211065575,"upper_bound":30202572.163034353,"unit":"ns"},"mean":{"estimate":29726688.236984126,"lower_bound":28685253.707509916,"upper_bound":30785192.55215377,"unit":"ns"},"median":{"estimate":29614259.191666666,"lower_bound":28596803.375,"upper_bound":30667276.41964286,"unit":"ns"},"median_abs_dev":{"estimate":1445336.6868859772,"lower_bound":106490.23881941795,"upper_bound":3045943.30973203,"unit":"ns"},"slope":{"estimate":29637049.62077922,"lower_bound":28963933.211065575,"upper_bound":30202572.163034353,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_1000000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[87442416.0,181372542.0,260245834.0,363479917.0,496748250.0,556216417.0,657355292.0,765075916.0,775827500.0,989888208.0],"unit":"ns","throughput":[],"typical":{"estimate":7815867.613419914,"lower_bound":7441617.265886287,"upper_bound":8108054.833642248,"unit":"ns"},"mean":{"estimate":7687782.737189153,"lower_bound":7459478.599074075,"upper_bound":7924962.296164186,"unit":"ns"},"median":{"estimate":7648863.142361111,"lower_bound":7286868.0,"upper_bound":8037363.319047619,"unit":"ns"},"median_abs_dev":{"estimate":506065.3314780446,"lower_bound":76561.4900963176,"upper_bound":713279.1438567641,"unit":"ns"},"slope":{"estimate":7815867.613419914,"lower_bound":7441617.265886287,"upper_bound":8108054.833642248,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[78245458.0,189140250.0,279480291.0,387672791.0,469322500.0,538469667.0,570408833.0,750165291.0,837702000.0,894624875.0],"unit":"ns","throughput":[],"typical":{"estimate":45328362.86493506,"lower_bound":43674807.98821549,"upper_bound":46749915.29931973,"unit":"ns"},"mean":{"estimate":45215072.36339286,"lower_bound":43303046.16609375,"upper_bound":46812236.881562494,"unit":"ns"},"median":{"estimate":46559524.25,"lower_bound":42807980.16071428,"upper_bound":47085196.59375,"unit":"ns"},"median_abs_dev":{"estimate":1788453.12057361,"lower_bound":256734.9340857938,"upper_bound":4551912.075674906,"unit":"ns"},"slope":{"estimate":45328362.86493506,"lower_bound":43674807.98821549,"upper_bound":46749915.29931973,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_1000000","iteration_count":[60,120,180,240,300,360,420,480,540,600],"measured_values":[74873333.0,213967917.0,309051500.0,410152042.0,460506916.0,638210833.0,682841334.0,784140958.0,843456834.0,899540125.0],"unit":"ns","throughput":[],"typical":{"estimate":1594887.4965800866,"lower_bound":1541698.7942371476,"upper_bound":1675294.588864629,"unit":"ns"},"mean":{"estimate":1608533.5738055555,"lower_bound":1507570.6483611108,"upper_bound":1694162.342777778,"unit":"ns"},"median":{"estimate":1629719.8479166667,"lower_bound":1530595.3208333333,"upper_bound":1740887.3555555556,"unit":"ns"},"median_abs_dev":{"estimate":134864.5023363432,"lower_bound":39932.416879058175,"upper_bound":249762.79623315728,"unit":"ns"},"slope":{"estimate":1594887.4965800866,"lower_bound":1541698.7942371476,"upper_bound":1675294.588864629,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[118358375.0,210289416.0,360302916.0,480149292.0,612396417.0,725627708.0,824415542.0,875654375.0,1046022792.0,1217996542.0],"unit":"ns","throughput":[],"typical":{"estimate":29432795.972727273,"lower_bound":28468375.05422196,"upper_bound":30243539.97130102,"unit":"ns"},"mean":{"estimate":29307836.683303572,"lower_bound":28401417.206775296,"upper_bound":30046101.491059527,"unit":"ns"},"median":{"estimate":29799462.25,"lower_bound":28403805.71651786,"upper_bound":30237578.275,"unit":"ns"},"median_abs_dev":{"estimate":804663.999329358,"lower_bound":166908.942911773,"upper_bound":2032593.6736692472,"unit":"ns"},"slope":{"estimate":29432795.972727273,"lower_bound":28468375.05422196,"upper_bound":30243539.97130102,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_1000000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[85892625.0,171364917.0,284242542.0,355673250.0,485619750.0,568899208.0,625097500.0,719833417.0,747784416.0,910657041.0],"unit":"ns","throughput":[],"typical":{"estimate":7471107.5915584415,"lower_bound":7207417.812865497,"upper_bound":7733333.716700334,"unit":"ns"},"mean":{"estimate":7505108.967351191,"lower_bound":7287379.503462302,"upper_bound":7724646.789929315,"unit":"ns"},"median":{"estimate":7469950.832589285,"lower_bound":7157718.75,"upper_bound":7895626.166666667,"unit":"ns"},"median_abs_dev":{"estimate":475898.3127354906,"lower_bound":65534.911045897985,"upper_bound":639633.7423140233,"unit":"ns"},"slope":{"estimate":7471107.5915584415,"lower_bound":7207417.812865497,"upper_bound":7733333.716700334,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_1000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[93687792.0,173598917.0,269959041.0,355955750.0,446804708.0,561209417.0,598956875.0,752843500.0,855210125.0,959603667.0],"unit":"ns","throughput":[],"typical":{"estimate":46473038.58571429,"lower_bound":44562606.794470385,"upper_bound":47432427.87740112,"unit":"ns"},"mean":{"estimate":45650639.935634926,"lower_bound":44580556.41579364,"upper_bound":46688225.88039683,"unit":"ns"},"median":{"estimate":45880312.45833333,"lower_bound":44040100.025,"upper_bound":47177784.80555555,"unit":"ns"},"median_abs_dev":{"estimate":1916768.528280551,"lower_bound":231806.50739461405,"upper_bound":2997768.7728356323,"unit":"ns"},"slope":{"estimate":46473038.58571429,"lower_bound":44562606.794470385,"upper_bound":47432427.87740112,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_100_1000000","iteration_count":[46,92,138,184,230,276,322,368,414,460],"measured_values":[86488125.0,176785833.0,250919792.0,419906167.0,461511791.0,513023667.0,605858834.0,664175750.0,729867708.0,835346916.0],"unit":"ns","throughput":[],"typical":{"estimate":1848381.7708639186,"lower_bound":1803381.3931536835,"upper_bound":1941453.867606847,"unit":"ns"},"mean":{"estimate":1903278.5890579713,"lower_bound":1830473.7326811594,"upper_bound":2002719.7155905794,"unit":"ns"},"median":{"estimate":1869479.016304348,"lower_bound":1811542.384963768,"upper_bound":1944061.0891304347,"unit":"ns"},"median_abs_dev":{"estimate":78291.3490093986,"lower_bound":11654.540857112353,"upper_bound":169652.31649279397,"unit":"ns"},"slope":{"estimate":1848381.7708639186,"lower_bound":1803381.3931536835,"upper_bound":1941453.867606847,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_selective_gt_100/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_selective_gt_100_1000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[113259291.0,241790500.0,365899500.0,460589333.0,567741875.0,725971792.0,764325583.0,847749750.0,1066262584.0,1190529792.0],"unit":"ns","throughput":[],"typical":{"estimate":38411579.65974026,"lower_bound":36759840.186685,"upper_bound":39638731.173327014,"unit":"ns"},"mean":{"estimate":38616557.8437037,"lower_bound":37514078.7477037,"upper_bound":39616128.21564815,"unit":"ns"},"median":{"estimate":38936825.61574074,"lower_bound":37122957.333333336,"upper_bound":40298416.666666664,"unit":"ns"},"median_abs_dev":{"estimate":1886845.4354017954,"lower_bound":286319.0919123754,"upper_bound":3089961.1538394447,"unit":"ns"},"slope":{"estimate":38411579.65974026,"lower_bound":36759840.186685,"upper_bound":39638731.173327014,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_10_1000000","iteration_count":[83,166,249,332,415,498,581,664,747,830],"measured_values":[106474708.0,228772666.0,266063000.0,368912833.0,447757375.0,500281375.0,645282000.0,667020417.0,786679833.0,851643875.0],"unit":"ns","throughput":[],"typical":{"estimate":1049226.4146455955,"lower_bound":1026345.4017078574,"upper_bound":1087502.748489038,"unit":"ns"},"mean":{"estimate":1111858.5215648306,"lower_bound":1047731.6564328743,"upper_bound":1190984.642505737,"unit":"ns"},"median":{"estimate":1073729.7690763052,"lower_bound":1026076.9578313254,"upper_bound":1196734.0413080896,"unit":"ns"},"median_abs_dev":{"estimate":63089.279867591926,"lower_bound":15958.807710499927,"upper_bound":158048.95383533125,"unit":"ns"},"slope":{"estimate":1049226.4146455955,"lower_bound":1026345.4017078574,"upper_bound":1087502.748489038,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_highly_selective_gt_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_highly_selective_gt_10_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[122384583.0,231884708.0,322467542.0,475226375.0,533864167.0,642554750.0,770330250.0,907611542.0,1104384209.0,1142359666.0],"unit":"ns","throughput":[],"typical":{"estimate":28568422.134415586,"lower_bound":27489004.05140175,"upper_bound":29563243.070460632,"unit":"ns"},"mean":{"estimate":28473298.690674603,"lower_bound":27599861.967321426,"upper_bound":29368564.468230657,"unit":"ns"},"median":{"estimate":28460926.16875,"lower_bound":26872295.166666668,"upper_bound":29790867.125,"unit":"ns"},"median_abs_dev":{"estimate":2097399.5424324637,"lower_bound":191991.5445564665,"upper_bound":2745063.0862841383,"unit":"ns"},"slope":{"estimate":28568422.134415586,"lower_bound":27489004.05140175,"upper_bound":29563243.070460632,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_1000000","iteration_count":[67,134,201,268,335,402,469,536,603,670],"measured_values":[101662541.0,189980792.0,256817625.0,334350666.0,451352917.0,483669000.0,616489708.0,693278958.0,1019591500.0,745680708.0],"unit":"ns","throughput":[],"typical":{"estimate":1327507.2087226207,"lower_bound":1176971.659013963,"upper_bound":1522573.3537345654,"unit":"ns"},"mean":{"estimate":1342260.306239043,"lower_bound":1252276.794712953,"upper_bound":1446542.5519736435,"unit":"ns"},"median":{"estimate":1303953.940565032,"lower_bound":1240428.1716417912,"upper_bound":1432336.7492537312,"unit":"ns"},"median_abs_dev":{"estimate":116513.12325125461,"lower_bound":27263.058317476432,"upper_bound":262922.69715457683,"unit":"ns"},"slope":{"estimate":1327507.2087226207,"lower_bound":1176971.659013963,"upper_bound":1522573.3537345654,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_1000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[117398209.0,242486958.0,315044250.0,454379542.0,561527542.0,695679042.0,779149958.0,966116791.0,1055215167.0,1209937333.0],"unit":"ns","throughput":[],"typical":{"estimate":29302616.15064935,"lower_bound":28343522.118551575,"upper_bound":29882725.596063603,"unit":"ns"},"mean":{"estimate":28895373.439970236,"lower_bound":28102923.90043155,"upper_bound":29607779.301015627,"unit":"ns"},"median":{"estimate":29149079.583333336,"lower_bound":28076377.1,"upper_bound":30191149.71875,"unit":"ns"},"median_abs_dev":{"estimate":1567680.914447474,"lower_bound":131212.7941492567,"upper_bound":2272531.829571369,"unit":"ns"},"slope":{"estimate":29302616.15064935,"lower_bound":28343522.118551575,"upper_bound":29882725.596063603,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_count/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_count_1000000","iteration_count":[11,22,33,44,55,66,77,88,99,110],"measured_values":[84447583.0,166100667.0,243529084.0,338400792.0,414354916.0,553312167.0,614701875.0,672513375.0,822609042.0,857934458.0],"unit":"ns","throughput":[],"typical":{"estimate":7924045.573081464,"lower_bound":7699834.378777139,"upper_bound":8150954.033205566,"unit":"ns"},"mean":{"estimate":7794884.813149351,"lower_bound":7613071.7294053035,"upper_bound":7999142.165428571,"unit":"ns"},"median":{"estimate":7683990.045454545,"lower_bound":7550030.318181818,"upper_bound":8054293.203030303,"unit":"ns"},"median_abs_dev":{"estimate":210695.26767668335,"lower_bound":36123.28721891054,"upper_bound":541884.9754832548,"unit":"ns"},"slope":{"estimate":7924045.573081464,"lower_bound":7699834.378777139,"upper_bound":8150954.033205566,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_count/1000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_count_1000000","iteration_count":[17,34,51,68,85,102,119,136,153,170],"measured_values":[97233667.0,178746166.0,256218458.0,360737791.0,427085750.0,564331750.0,634897959.0,814633583.0,967588666.0,1010668959.0],"unit":"ns","throughput":[],"typical":{"estimate":5800472.688770054,"lower_bound":5369421.298226643,"upper_bound":6044904.726153503,"unit":"ns"},"mean":{"estimate":5545737.918027543,"lower_bound":5299878.7662464995,"upper_bound":5809571.606475256,"unit":"ns"},"median":{"estimate":5433970.591036415,"lower_bound":5164752.875,"upper_bound":5945111.523529412,"unit":"ns"},"median_abs_dev":{"estimate":515269.6409756646,"lower_bound":57848.671337687665,"upper_bound":723631.4105279753,"unit":"ns"},"slope":{"estimate":5800472.688770054,"lower_bound":5369421.298226643,"upper_bound":6044904.726153503,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_10/1000000","ORE/ore_decrypt/range_gt_10/1000000","ORE/ore/range_gt_100/1000000","ORE/ore_decrypt/range_gt_100/1000000","ORE/ore/range_lt_10/1000000","ORE/ore_decrypt/range_lt_10/1000000","ORE/ore/range_lt_100/1000000","ORE/ore_decrypt/range_lt_100/1000000","ORE/ore/range_selective_gt_100/1000000","ORE/ore_decrypt/range_selective_gt_100/1000000","ORE/ore/range_highly_selective_gt_10/1000000","ORE/ore_decrypt/range_highly_selective_gt_10/1000000","ORE/ore/range_lt_hybrid_ordered_10/1000000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/1000000","ORE/ore/range_selective_gt_count/1000000","ORE/ore/range_highly_selective_gt_count/1000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} diff --git a/results/query/ore_rows_10000000.json b/results/query/ore_rows_10000000.json new file mode 100644 index 0000000..01e4e64 --- /dev/null +++ b/results/query/ore_rows_10000000.json @@ -0,0 +1,17 @@ +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_10_10000000","iteration_count":[62,124,186,248,310,372,434,496,558,620],"measured_values":[106923375.0,171441209.0,272239916.0,349495291.0,494262542.0,532269792.0,591020792.0,606785208.0,746935750.0,805818542.0],"unit":"ns","throughput":[],"typical":{"estimate":1344845.9382069544,"lower_bound":1294584.991986525,"upper_bound":1431170.4998549742,"unit":"ns"},"mean":{"estimate":1422875.7892613926,"lower_bound":1344990.3279493086,"upper_bound":1512556.5375716847,"unit":"ns"},"median":{"estimate":1395922.8004032257,"lower_bound":1330753.192857143,"upper_bound":1512614.0354838711,"unit":"ns"},"median_abs_dev":{"estimate":92707.66451432505,"lower_bound":32614.13126265019,"upper_bound":234161.78464384587,"unit":"ns"},"slope":{"estimate":1344845.9382069544,"lower_bound":1294584.991986525,"upper_bound":1431170.4998549742,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_10_10000000","iteration_count":[3,6,9,12,15,18,21,24,27,30],"measured_values":[82325791.0,206189833.0,306482584.0,355998125.0,430938459.0,552518417.0,614704792.0,681754083.0,770775917.0,843128584.0],"unit":"ns","throughput":[],"typical":{"estimate":28946479.486580085,"lower_bound":28464969.857864358,"upper_bound":29961101.915514592,"unit":"ns"},"mean":{"estimate":29928135.077764552,"lower_bound":28629557.848677255,"upper_bound":31475412.613042325,"unit":"ns"},"median":{"estimate":29000443.68095238,"lower_bound":28325771.15925926,"upper_bound":31860065.43055556,"unit":"ns"},"median_abs_dev":{"estimate":1158076.8406750276,"lower_bound":239299.4008690875,"upper_bound":3569923.981872847,"unit":"ns"},"slope":{"estimate":28946479.486580085,"lower_bound":28464969.857864358,"upper_bound":29961101.915514592,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_gt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_gt_100_10000000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[101072375.0,258519125.0,273207416.0,378584125.0,465871125.0,571929791.0,686678125.0,737703375.0,811561750.0,913822709.0],"unit":"ns","throughput":[],"typical":{"estimate":7762697.069047619,"lower_bound":7625959.777375202,"upper_bound":8024809.032662842,"unit":"ns"},"mean":{"estimate":8136737.998356481,"lower_bound":7718905.076321759,"upper_bound":8782404.117447915,"unit":"ns"},"median":{"estimate":7825844.010416666,"lower_bound":7615189.241666666,"upper_bound":8183083.618055555,"unit":"ns"},"median_abs_dev":{"estimate":331660.49797476514,"lower_bound":70657.20644037612,"upper_bound":679948.7618545373,"unit":"ns"},"slope":{"estimate":7762697.069047619,"lower_bound":7625959.777375202,"upper_bound":8024809.032662842,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_gt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_gt_100_10000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[91147625.0,174587875.0,279637250.0,380408750.0,468631500.0,569653292.0,607398084.0,719780458.0,784326625.0,898850792.0],"unit":"ns","throughput":[],"typical":{"estimate":44960292.43376623,"lower_bound":44154843.19801017,"upper_bound":46174734.40606342,"unit":"ns"},"mean":{"estimate":45460043.80424603,"lower_bound":44513523.803134926,"upper_bound":46403308.75458334,"unit":"ns"},"median":{"estimate":45280045.5625,"lower_bound":43646968.75,"upper_bound":47038658.0,"unit":"ns"},"median_abs_dev":{"estimate":2384155.1182977855,"lower_bound":193769.38313491366,"upper_bound":2634164.7040042253,"unit":"ns"},"slope":{"estimate":44960292.43376623,"lower_bound":44154843.19801017,"upper_bound":46174734.40606342,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_10_10000000","iteration_count":[53,106,159,212,265,318,371,424,477,530],"measured_values":[91341417.0,173814000.0,284170208.0,340511625.0,468945334.0,497362042.0,718874542.0,756935416.0,856484667.0,865935667.0],"unit":"ns","throughput":[],"typical":{"estimate":1736718.9050722863,"lower_bound":1651671.621133631,"upper_bound":1826223.0865932778,"unit":"ns"},"mean":{"estimate":1724253.3702380955,"lower_bound":1659345.794865791,"upper_bound":1793033.6002740343,"unit":"ns"},"median":{"estimate":1746513.9981132075,"lower_bound":1622970.8136792453,"upper_bound":1790395.1886792453,"unit":"ns"},"median_abs_dev":{"estimate":115502.41251357319,"lower_bound":9154.518677097281,"upper_bound":220842.54132077063,"unit":"ns"},"slope":{"estimate":1736718.9050722863,"lower_bound":1651671.621133631,"upper_bound":1826223.0865932778,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_10_10000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[115474250.0,271331125.0,363523792.0,457022417.0,664515291.0,688702167.0,855987208.0,911828167.0,1066335500.0,1171321916.0],"unit":"ns","throughput":[],"typical":{"estimate":29628806.138311688,"lower_bound":29019604.57091346,"upper_bound":30605182.725256294,"unit":"ns"},"mean":{"estimate":30153327.208442457,"lower_bound":29121307.90136607,"upper_bound":31382991.72645387,"unit":"ns"},"median":{"estimate":29451739.22777778,"lower_bound":28695923.625,"upper_bound":31759706.941666666,"unit":"ns"},"median_abs_dev":{"estimate":1282262.3704040414,"lower_bound":200569.27496418357,"upper_bound":2877814.571664826,"unit":"ns"},"slope":{"estimate":29628806.138311688,"lower_bound":29019604.57091346,"upper_bound":30605182.725256294,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_100_10000000","iteration_count":[12,24,36,48,60,72,84,96,108,120],"measured_values":[95358709.0,188094917.0,276502667.0,363790584.0,444271750.0,549582708.0,609320042.0,712530833.0,839051041.0,873359541.0],"unit":"ns","throughput":[],"typical":{"estimate":7473076.972943723,"lower_bound":7331756.154326846,"upper_bound":7660201.289910502,"unit":"ns"},"mean":{"estimate":7580406.326015212,"lower_bound":7444099.5998139875,"upper_bound":7719219.102380951,"unit":"ns"},"median":{"estimate":7606031.833333334,"lower_bound":7350096.176041666,"upper_bound":7768991.12037037,"unit":"ns"},"median_abs_dev":{"estimate":285651.2937068017,"lower_bound":70477.57246543933,"upper_bound":401806.7700915034,"unit":"ns"},"slope":{"estimate":7473076.972943723,"lower_bound":7331756.154326846,"upper_bound":7660201.289910502,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_100_10000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[92703791.0,182043167.0,281122125.0,353354041.0,476627958.0,557310833.0,639168208.0,738276500.0,788475166.0,859725750.0],"unit":"ns","throughput":[],"typical":{"estimate":44824027.14545455,"lower_bound":43780324.625,"upper_bound":46317471.69082125,"unit":"ns"},"mean":{"estimate":45557861.17305556,"lower_bound":44674609.75777778,"upper_bound":46388271.48083334,"unit":"ns"},"median":{"estimate":45898576.625,"lower_bound":44169255.125,"upper_bound":46602791.5,"unit":"ns"},"median_abs_dev":{"estimate":1111285.5283707362,"lower_bound":222603.61399799402,"upper_bound":2530228.630762797,"unit":"ns"},"slope":{"estimate":44824027.14545455,"lower_bound":43780324.625,"upper_bound":46317471.69082125,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_100_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[2111511167.0,1841440125.0,2560291750.0,2381896791.0,2277419625.0,2041403583.0,2026093209.0,1930882042.0,1883390208.0,1864092583.0],"unit":"ns","throughput":[],"typical":{"estimate":2091842108.3,"lower_bound":1959393287.5,"upper_bound":2242165233.1,"unit":"ns"},"mean":{"estimate":2091842108.3,"lower_bound":1959393287.5,"upper_bound":2242165233.1,"unit":"ns"},"median":{"estimate":2033748396.0,"lower_bound":1883390208.0,"upper_bound":2277419625.0,"unit":"ns"},"median_abs_dev":{"estimate":237226374.72968996,"lower_bound":45402925.13433695,"upper_bound":388328947.68368304,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_selective_gt_100/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_selective_gt_100_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[1922757000.0,2279840458.0,2150662625.0,2229580792.0,2208985000.0,2336464042.0,2601741708.0,2368519625.0,2010920042.0,2512332667.0],"unit":"ns","throughput":[],"typical":{"estimate":2262180395.9,"lower_bound":2141246013.9275,"upper_bound":2384100131.9049997,"unit":"ns"},"mean":{"estimate":2262180395.9,"lower_bound":2141246013.9275,"upper_bound":2384100131.9049997,"unit":"ns"},"median":{"estimate":2254710625.0,"lower_bound":2109952521.0,"upper_bound":2424398354.5,"unit":"ns"},"median_abs_dev":{"estimate":161497391.23284817,"lower_bound":52525150.08289218,"upper_bound":371697172.3135561,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_10_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[1820407250.0,3009618375.0,2454596375.0,3010202417.0,2283721292.0,4754456625.0,4016999875.0,962799667.0,4547285833.0,4709597500.0],"unit":"ns","throughput":[],"typical":{"estimate":3156968520.9,"lower_bound":2375757263.6025,"upper_bound":3915364707.5,"unit":"ns"},"mean":{"estimate":3156968520.9,"lower_bound":2375757263.6025,"upper_bound":3915364707.5,"unit":"ns"},"median":{"estimate":3009910396.0,"lower_bound":2137501812.5,"upper_bound":4547285833.0,"unit":"ns"},"median_abs_dev":{"estimate":1628334084.0037913,"lower_bound":186829774.15520847,"upper_bound":2279312782.4303093,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_highly_selective_gt_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_highly_selective_gt_10_10000000","iteration_count":[1,1,1,1,1,1,1,1,1,1],"measured_values":[2807847583.0,3798393042.0,2388451208.0,3799219166.0,3711645583.0,4156906000.0,4565057250.0,3412567500.0,5064609291.0,2344069042.0],"unit":"ns","throughput":[],"typical":{"estimate":3604876566.5,"lower_bound":3081406063.59,"upper_bound":4131321937.4,"unit":"ns"},"mean":{"estimate":3604876566.5,"lower_bound":3081406063.59,"upper_bound":4131321937.4,"unit":"ns"},"median":{"estimate":3755019312.5,"lower_bound":2807847583.0,"upper_bound":4182138208.0,"unit":"ns"},"median_abs_dev":{"estimate":898399708.5627168,"lower_bound":65530701.635697484,"upper_bound":1646418529.3606281,"unit":"ns"},"slope":null,"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_lt_hybrid_ordered_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_lt_hybrid_ordered_10_10000000","iteration_count":[66,132,198,264,330,396,462,528,594,660],"measured_values":[79786875.0,147537084.0,221373542.0,315569417.0,410205334.0,431873167.0,537113584.0,591033166.0,698785458.0,795200250.0],"unit":"ns","throughput":[],"typical":{"estimate":1167755.0982683983,"lower_bound":1132217.7189620081,"upper_bound":1195508.742483894,"unit":"ns"},"mean":{"estimate":1163683.9262121213,"lower_bound":1134435.340909091,"upper_bound":1192944.4170202021,"unit":"ns"},"median":{"estimate":1169495.005050505,"lower_bound":1118048.191919192,"upper_bound":1204848.8636363635,"unit":"ns"},"median_abs_dev":{"estimate":66354.53962538058,"lower_bound":1496.5545715365954,"upper_bound":84955.3791758787,"unit":"ns"},"slope":{"estimate":1167755.0982683983,"lower_bound":1132217.7189620081,"upper_bound":1195508.742483894,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_decrypt_range_lt_hybrid_ordered_10_10000000","iteration_count":[4,8,12,16,20,24,28,32,36,40],"measured_values":[128719584.0,230962208.0,329641000.0,453561625.0,563130125.0,704986417.0,801608875.0,903600666.0,1038219833.0,1225348167.0],"unit":"ns","throughput":[],"typical":{"estimate":29140850.80974026,"lower_bound":28378693.423144877,"upper_bound":29931902.453125,"unit":"ns"},"mean":{"estimate":29073835.037341267,"lower_bound":28353901.998313494,"upper_bound":29961249.32271329,"unit":"ns"},"median":{"estimate":28734164.09920635,"lower_bound":28237520.8125,"upper_bound":29751990.0875,"unit":"ns"},"median_abs_dev":{"estimate":796379.4179135247,"lower_bound":141658.95264130086,"upper_bound":2062199.4067573976,"unit":"ns"},"slope":{"estimate":29140850.80974026,"lower_bound":28378693.423144877,"upper_bound":29931902.453125,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_selective_gt_count/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_selective_gt_count_10000000","iteration_count":[2,4,6,8,10,12,14,16,18,20],"measured_values":[160411542.0,315877584.0,467738709.0,589828084.0,749899959.0,943382000.0,1038747041.0,1241360000.0,1394522250.0,1561269834.0],"unit":"ns","throughput":[],"typical":{"estimate":77051941.35714285,"lower_bound":75657608.97458544,"upper_bound":77874986.93681319,"unit":"ns"},"mean":{"estimate":77178345.88142857,"lower_bound":75858400.98952381,"upper_bound":78395702.45666666,"unit":"ns"},"median":{"estimate":77770725.75,"lower_bound":74989995.9,"upper_bound":78615166.66666667,"unit":"ns"},"median_abs_dev":{"estimate":1514558.2809612192,"lower_bound":354705.89091271383,"upper_bound":3681981.338291748,"unit":"ns"},"slope":{"estimate":77051941.35714285,"lower_bound":75657608.97458544,"upper_bound":77874986.93681319,"unit":"ns"},"change":null} +{"reason":"benchmark-complete","id":"ORE/ore/range_highly_selective_gt_count/10000000","report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE/ore_range_highly_selective_gt_count_10000000","iteration_count":[5,10,15,20,25,30,35,40,45,50],"measured_values":[96660458.0,207527750.0,297730625.0,408573333.0,500416708.0,594895791.0,678116083.0,823991709.0,881741042.0,993468250.0],"unit":"ns","throughput":[],"typical":{"estimate":19906367.575064935,"lower_bound":19642440.148337595,"upper_bound":20257100.48291443,"unit":"ns"},"mean":{"estimate":19964691.793468256,"lower_bound":19684818.395492066,"upper_bound":20258406.643410716,"unit":"ns"},"median":{"estimate":19859036.666666664,"lower_bound":19594245.377777778,"upper_bound":20428666.65,"unit":"ns"},"median_abs_dev":{"estimate":555295.0156548716,"lower_bound":30625.573456289225,"upper_bound":842519.2092782924,"unit":"ns"},"slope":{"estimate":19906367.575064935,"lower_bound":19642440.148337595,"upper_bound":20257100.48291443,"unit":"ns"},"change":null} +{"reason":"group-complete","group_name":"ORE","benchmarks":["ORE/ore/range_gt_10/10000000","ORE/ore_decrypt/range_gt_10/10000000","ORE/ore/range_gt_100/10000000","ORE/ore_decrypt/range_gt_100/10000000","ORE/ore/range_lt_10/10000000","ORE/ore_decrypt/range_lt_10/10000000","ORE/ore/range_lt_100/10000000","ORE/ore_decrypt/range_lt_100/10000000","ORE/ore/range_selective_gt_100/10000000","ORE/ore_decrypt/range_selective_gt_100/10000000","ORE/ore/range_highly_selective_gt_10/10000000","ORE/ore_decrypt/range_highly_selective_gt_10/10000000","ORE/ore/range_lt_hybrid_ordered_10/10000000","ORE/ore_decrypt/range_lt_hybrid_ordered_10/10000000","ORE/ore/range_selective_gt_count/10000000","ORE/ore/range_highly_selective_gt_count/10000000"],"report_directory":"/Users/dan/Projects/CipherStash/benches/target/criterion/reports/ORE"} diff --git a/sql/indexes/category_encrypted_10000000_down.sql b/sql/indexes/category_encrypted_10000000_down.sql new file mode 100644 index 0000000..865c7e1 --- /dev/null +++ b/sql/indexes/category_encrypted_10000000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS category_encrypted_10000000_hash_index; diff --git a/sql/indexes/category_encrypted_10000000_up.sql b/sql/indexes/category_encrypted_10000000_up.sql new file mode 100644 index 0000000..6931b2a --- /dev/null +++ b/sql/indexes/category_encrypted_10000000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +category_encrypted_10000000_hash_index +ON category_encrypted_10000000 using hash ( + eql_v2.hmac_256(value) +); diff --git a/sql/indexes/category_encrypted_1000000_down.sql b/sql/indexes/category_encrypted_1000000_down.sql new file mode 100644 index 0000000..fe3e097 --- /dev/null +++ b/sql/indexes/category_encrypted_1000000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS category_encrypted_1000000_hash_index; diff --git a/sql/indexes/category_encrypted_1000000_up.sql b/sql/indexes/category_encrypted_1000000_up.sql new file mode 100644 index 0000000..45da055 --- /dev/null +++ b/sql/indexes/category_encrypted_1000000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +category_encrypted_1000000_hash_index +ON category_encrypted_1000000 using hash ( + eql_v2.hmac_256(value) +); diff --git a/sql/indexes/category_encrypted_100000_down.sql b/sql/indexes/category_encrypted_100000_down.sql new file mode 100644 index 0000000..7d8452b --- /dev/null +++ b/sql/indexes/category_encrypted_100000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS category_encrypted_100000_hash_index; diff --git a/sql/indexes/category_encrypted_100000_up.sql b/sql/indexes/category_encrypted_100000_up.sql new file mode 100644 index 0000000..9fa9081 --- /dev/null +++ b/sql/indexes/category_encrypted_100000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +category_encrypted_100000_hash_index +ON category_encrypted_100000 using hash ( + eql_v2.hmac_256(value) +); diff --git a/sql/indexes/category_encrypted_10000_down.sql b/sql/indexes/category_encrypted_10000_down.sql new file mode 100644 index 0000000..5eadf4a --- /dev/null +++ b/sql/indexes/category_encrypted_10000_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS category_encrypted_10000_hash_index; diff --git a/sql/indexes/category_encrypted_10000_up.sql b/sql/indexes/category_encrypted_10000_up.sql new file mode 100644 index 0000000..49e884c --- /dev/null +++ b/sql/indexes/category_encrypted_10000_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +category_encrypted_10000_hash_index +ON category_encrypted_10000 using hash ( + eql_v2.hmac_256(value) +); diff --git a/sql/indexes/combo_encrypted_10000000_down.sql b/sql/indexes/combo_encrypted_10000000_down.sql new file mode 100644 index 0000000..745895c --- /dev/null +++ b/sql/indexes/combo_encrypted_10000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS combo_encrypted_10000000_name_gin_index; +DROP INDEX IF EXISTS combo_encrypted_10000000_age_ore_index; +DROP INDEX IF EXISTS combo_encrypted_10000000_category_hash_index; diff --git a/sql/indexes/combo_encrypted_10000000_up.sql b/sql/indexes/combo_encrypted_10000000_up.sql new file mode 100644 index 0000000..bea494b --- /dev/null +++ b/sql/indexes/combo_encrypted_10000000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +combo_encrypted_10000000_name_gin_index +ON combo_encrypted_10000000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_10000000_age_ore_index +ON combo_encrypted_10000000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_10000000_category_hash_index +ON combo_encrypted_10000000 USING hash ( + eql_v2.hmac_256(category) +); diff --git a/sql/indexes/combo_encrypted_1000000_down.sql b/sql/indexes/combo_encrypted_1000000_down.sql new file mode 100644 index 0000000..db5cd85 --- /dev/null +++ b/sql/indexes/combo_encrypted_1000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS combo_encrypted_1000000_name_gin_index; +DROP INDEX IF EXISTS combo_encrypted_1000000_age_ore_index; +DROP INDEX IF EXISTS combo_encrypted_1000000_category_hash_index; diff --git a/sql/indexes/combo_encrypted_1000000_up.sql b/sql/indexes/combo_encrypted_1000000_up.sql new file mode 100644 index 0000000..cd81ec3 --- /dev/null +++ b/sql/indexes/combo_encrypted_1000000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +combo_encrypted_1000000_name_gin_index +ON combo_encrypted_1000000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_1000000_age_ore_index +ON combo_encrypted_1000000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_1000000_category_hash_index +ON combo_encrypted_1000000 USING hash ( + eql_v2.hmac_256(category) +); diff --git a/sql/indexes/combo_encrypted_100000_down.sql b/sql/indexes/combo_encrypted_100000_down.sql new file mode 100644 index 0000000..94ea6c0 --- /dev/null +++ b/sql/indexes/combo_encrypted_100000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS combo_encrypted_100000_name_gin_index; +DROP INDEX IF EXISTS combo_encrypted_100000_age_ore_index; +DROP INDEX IF EXISTS combo_encrypted_100000_category_hash_index; diff --git a/sql/indexes/combo_encrypted_100000_up.sql b/sql/indexes/combo_encrypted_100000_up.sql new file mode 100644 index 0000000..7c803fa --- /dev/null +++ b/sql/indexes/combo_encrypted_100000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +combo_encrypted_100000_name_gin_index +ON combo_encrypted_100000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_100000_age_ore_index +ON combo_encrypted_100000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_100000_category_hash_index +ON combo_encrypted_100000 USING hash ( + eql_v2.hmac_256(category) +); diff --git a/sql/indexes/combo_encrypted_10000_down.sql b/sql/indexes/combo_encrypted_10000_down.sql new file mode 100644 index 0000000..e4f13c2 --- /dev/null +++ b/sql/indexes/combo_encrypted_10000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS combo_encrypted_10000_name_gin_index; +DROP INDEX IF EXISTS combo_encrypted_10000_age_ore_index; +DROP INDEX IF EXISTS combo_encrypted_10000_category_hash_index; diff --git a/sql/indexes/combo_encrypted_10000_up.sql b/sql/indexes/combo_encrypted_10000_up.sql new file mode 100644 index 0000000..d74eb69 --- /dev/null +++ b/sql/indexes/combo_encrypted_10000_up.sql @@ -0,0 +1,17 @@ +CREATE INDEX +combo_encrypted_10000_name_gin_index +ON combo_encrypted_10000 USING GIN ( + eql_v2.bloom_filter(name) +); + +CREATE INDEX +combo_encrypted_10000_age_ore_index +ON combo_encrypted_10000 ( + eql_v2.ore_block_u64_8_256(age) +); + +CREATE INDEX +combo_encrypted_10000_category_hash_index +ON combo_encrypted_10000 USING hash ( + eql_v2.hmac_256(category) +); diff --git a/sql/indexes/json_ste_vec_small_encrypted_10000000_down.sql b/sql/indexes/json_ste_vec_small_encrypted_10000000_down.sql new file mode 100644 index 0000000..2135bd8 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_10000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000000_ste_vec_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000000_hmac_terms_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000000_eql_index; diff --git a/sql/indexes/json_ste_vec_small_encrypted_10000000_up.sql b/sql/indexes/json_ste_vec_small_encrypted_10000000_up.sql new file mode 100644 index 0000000..aba4b0b --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_10000000_up.sql @@ -0,0 +1,11 @@ +CREATE INDEX +json_ste_vec_small_encrypted_10000000_ste_vec_index +ON json_ste_vec_small_encrypted_10000000 USING GIN ( + eql_v2.ste_vec(value) +); + +CREATE INDEX +json_ste_vec_small_encrypted_10000000_hmac_terms_index +ON json_ste_vec_small_encrypted_10000000 USING GIN ( + eql_v2.hmac_256_terms(value) +); diff --git a/sql/indexes/json_ste_vec_small_encrypted_1000000_down.sql b/sql/indexes/json_ste_vec_small_encrypted_1000000_down.sql new file mode 100644 index 0000000..3e41a5d --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_1000000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_1000000_ste_vec_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_1000000_hmac_terms_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_1000000_eql_index; diff --git a/sql/indexes/json_ste_vec_small_encrypted_1000000_up.sql b/sql/indexes/json_ste_vec_small_encrypted_1000000_up.sql new file mode 100644 index 0000000..7e2dbd8 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_1000000_up.sql @@ -0,0 +1,11 @@ +CREATE INDEX +json_ste_vec_small_encrypted_1000000_ste_vec_index +ON json_ste_vec_small_encrypted_1000000 USING GIN ( + eql_v2.ste_vec(value) +); + +CREATE INDEX +json_ste_vec_small_encrypted_1000000_hmac_terms_index +ON json_ste_vec_small_encrypted_1000000 USING GIN ( + eql_v2.hmac_256_terms(value) +); diff --git a/sql/indexes/json_ste_vec_small_encrypted_100000_down.sql b/sql/indexes/json_ste_vec_small_encrypted_100000_down.sql new file mode 100644 index 0000000..e9e4471 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_100000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_100000_ste_vec_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_100000_hmac_terms_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_100000_eql_index; diff --git a/sql/indexes/json_ste_vec_small_encrypted_100000_up.sql b/sql/indexes/json_ste_vec_small_encrypted_100000_up.sql new file mode 100644 index 0000000..4fb6308 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_100000_up.sql @@ -0,0 +1,11 @@ +CREATE INDEX +json_ste_vec_small_encrypted_100000_ste_vec_index +ON json_ste_vec_small_encrypted_100000 USING GIN ( + eql_v2.ste_vec(value) +); + +CREATE INDEX +json_ste_vec_small_encrypted_100000_hmac_terms_index +ON json_ste_vec_small_encrypted_100000 USING GIN ( + eql_v2.hmac_256_terms(value) +); diff --git a/sql/indexes/json_ste_vec_small_encrypted_10000_down.sql b/sql/indexes/json_ste_vec_small_encrypted_10000_down.sql new file mode 100644 index 0000000..12cc459 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_10000_down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000_ste_vec_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000_hmac_terms_index; +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_10000_eql_index; diff --git a/sql/indexes/json_ste_vec_small_encrypted_10000_up.sql b/sql/indexes/json_ste_vec_small_encrypted_10000_up.sql new file mode 100644 index 0000000..2d575ab --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_10000_up.sql @@ -0,0 +1,11 @@ +CREATE INDEX +json_ste_vec_small_encrypted_10000_ste_vec_index +ON json_ste_vec_small_encrypted_10000 USING GIN ( + eql_v2.ste_vec(value) +); + +CREATE INDEX +json_ste_vec_small_encrypted_10000_hmac_terms_index +ON json_ste_vec_small_encrypted_10000 USING GIN ( + eql_v2.hmac_256_terms(value) +); diff --git a/sql/indexes/json_ste_vec_small_encrypted_down.sql b/sql/indexes/json_ste_vec_small_encrypted_down.sql new file mode 100644 index 0000000..169783e --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_down.sql @@ -0,0 +1 @@ +DROP INDEX IF EXISTS json_ste_vec_small_encrypted_ste_vec_index; diff --git a/sql/indexes/json_ste_vec_small_encrypted_up.sql b/sql/indexes/json_ste_vec_small_encrypted_up.sql new file mode 100644 index 0000000..9e14ab4 --- /dev/null +++ b/sql/indexes/json_ste_vec_small_encrypted_up.sql @@ -0,0 +1,5 @@ +CREATE INDEX +json_ste_vec_small_encrypted_ste_vec_index +ON json_ste_vec_small_encrypted USING GIN ( + eql_v2.ste_vec(value) +); diff --git a/sql/schema.sql b/sql/schema.sql index 1df34b5..bd0fa43 100644 --- a/sql/schema.sql +++ b/sql/schema.sql @@ -33,6 +33,107 @@ CREATE TABLE IF NOT EXISTS string_plaintext ( value TEXT NOT NULL ); +-- Sized plaintext variants for the GROUP BY plaintext-baseline bench. +-- Populated via SQL (`md5(random()::text)`) by `prepare:string_plaintext`; +-- no encryption-client dependency so they're cheap to populate. +CREATE TABLE IF NOT EXISTS string_plaintext_10000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_plaintext_100000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_plaintext_1000000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS string_plaintext_10000000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +-- Low-cardinality categorical data (~250 distinct buckets, uniform random) +-- for "realistic GROUP BY" scenarios. The encrypted variant carries an `hm` +-- HMAC term so `GROUP BY eql_v2.hmac_256(value)` and `WHERE eql_v2.hmac_256(value) = ...` +-- both engage their respective indexes. The plaintext variant is a baseline +-- for the same query shape against an unindexed TEXT column. +CREATE TABLE IF NOT EXISTS category_encrypted_10000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_encrypted_100000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_plaintext_10000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_plaintext_100000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_plaintext_1000000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +CREATE TABLE IF NOT EXISTS category_plaintext_10000000 ( + id SERIAL PRIMARY KEY, + value TEXT NOT NULL +); + +-- Combo: a single row carries three encrypted columns — `name` (match + hmac +-- via the unique search index), `age` (ORE), `category` (hmac for equality +-- and GROUP BY). Used by `benches/combo.rs` to exercise composite-predicate +-- shapes the EQL query-performance guide §6 describes (bloom + ORE order + +-- limit, filtered GROUP BY, top-N filtered GROUP BY). +CREATE TABLE IF NOT EXISTS combo_encrypted_10000 ( + id SERIAL PRIMARY KEY, + name eql_v2_encrypted NOT NULL, + age eql_v2_encrypted NOT NULL, + category eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS combo_encrypted_100000 ( + id SERIAL PRIMARY KEY, + name eql_v2_encrypted NOT NULL, + age eql_v2_encrypted NOT NULL, + category eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS combo_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + name eql_v2_encrypted NOT NULL, + age eql_v2_encrypted NOT NULL, + category eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS combo_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + name eql_v2_encrypted NOT NULL, + age eql_v2_encrypted NOT NULL, + category eql_v2_encrypted NOT NULL +); + CREATE TABLE IF NOT EXISTS string_encrypted ( id SERIAL PRIMARY KEY, value eql_v2_encrypted NOT NULL @@ -63,11 +164,56 @@ CREATE TABLE IF NOT EXISTS json_small_plaintext ( value JSONB NOT NULL ); +CREATE TABLE IF NOT EXISTS json_ste_vec_small_encrypted ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_ste_vec_small_encrypted_10000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_ste_vec_small_encrypted_100000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_ste_vec_small_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_ste_vec_small_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + CREATE TABLE IF NOT EXISTS json_small_encrypted ( id SERIAL PRIMARY KEY, value eql_v2_encrypted NOT NULL ); +CREATE TABLE IF NOT EXISTS json_small_encrypted_10000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_small_encrypted_100000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_small_encrypted_1000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + +CREATE TABLE IF NOT EXISTS json_small_encrypted_10000000 ( + id SERIAL PRIMARY KEY, + value eql_v2_encrypted NOT NULL +); + CREATE TABLE IF NOT EXISTS json_large_plaintext ( id SERIAL PRIMARY KEY, value JSONB NOT NULL diff --git a/src/bin/encrypt_category.rs b/src/bin/encrypt_category.rs new file mode 100644 index 0000000..3d2f087 --- /dev/null +++ b/src/bin/encrypt_category.rs @@ -0,0 +1,43 @@ +//! Encrypt low-cardinality categorical data (`CAT_001`..`CAT_250`) into the +//! `category_encrypted_*` tables. Used by the realistic-GROUP-BY scenarios in +//! `benches/group_by.rs` — see `dbbenches::FakeCategory` for the generator. +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) +//! - CS_CLIENT_ID / CS_CLIENT_KEY / CS_WORKSPACE_CRN: CipherStash credentials + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use dbbenches::{FakeCategory, IngestOptionsBuilder}; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("category_encrypted{}", table_suffix); + + IngestOptionsBuilder::new("encrypt_category") + .num_records(num_records) + .batch_size(1000) + .identifier(Identifier::new(&table_name, "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()), + ) + .build()? + .ingest::(FakeCategory) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_combo.rs b/src/bin/encrypt_combo.rs new file mode 100644 index 0000000..990e4ae --- /dev/null +++ b/src/bin/encrypt_combo.rs @@ -0,0 +1,141 @@ +//! Encrypt three-column combo rows (`name`, `age`, `category`) into the +//! `combo_encrypted_*` tables. Used by `benches/combo.rs` for composite +//! predicate scenarios — bloom + ORE order + LIMIT, filtered GROUP BY, +//! top-N filtered GROUP BY. +//! +//! Per row we generate: +//! * `name` — `fake::Name` (random English name, ~unique) +//! * `age` — uniform 18..=90 (low-cardinality numeric, ORE-indexable) +//! * `category` — `dbbenches::FakeCategory` (CAT_001..CAT_250, 250 buckets) +//! +//! Each row produces three `PreparedPlaintext` entries which we encrypt in +//! one `encrypt_eql` call per batch, then split back into 3-tuples for the +//! `INSERT INTO ... (name, age, category)` statement. +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) +//! - CS_CLIENT_ID / CS_CLIENT_KEY / CS_WORKSPACE_CRN: CipherStash credentials + +use anyhow::{Context, Result}; +use cipherstash_client::{ + encryption::Plaintext, + eql::{encrypt_eql, EqlOperation, Identifier, PreparedPlaintext}, + schema::{column::Index, ColumnConfig, ColumnType}, +}; +use dbbenches::{init_scoped_cipher, FakeCategory}; +use fake::{faker::name::raw::Name, locales::EN, Fake}; +use sqlx::{postgres::PgPoolOptions, types::Json, QueryBuilder}; +use std::borrow::Cow; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + // Honour RUST_LOG for cipherstash-client / zerokms-protocol trace! + // emissions. The cipherstash-client traces the full ViturRequestError + // (kind + message + underlying transport error) at the failure point + // in vitur_client::generate_keys; without a subscriber that line is a + // no-op. The try_init is a no-op if a subscriber was already installed + // upstream — keeps it safe to leave in. + let _ = tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")), + ) + .with_writer(std::io::stderr) + .try_init(); + + let database_url = + env::var("DATABASE_URL").context("DATABASE_URL environment variable must be set")?; + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("combo_encrypted{}", table_suffix); + let batch_size: usize = 1000; + + let pool = PgPoolOptions::new() + .max_connections(5) + .connect(&database_url) + .await?; + + // Init once and reuse for the binary lifetime — see lib.rs::ingest + // for the rationale. + let scoped_cipher = init_scoped_cipher().await?; + + let name_config = ColumnConfig::build("name") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()) + .add_index(Index::new_match()); + let age_config = ColumnConfig::build("age") + .casts_as(ColumnType::Int) + .add_index(Index::new_ore()); + let category_config = ColumnConfig::build("category") + .casts_as(ColumnType::Utf8Str) + .add_index(Index::new_unique()); + + let name_ident = Identifier::new(&table_name, "name"); + let age_ident = Identifier::new(&table_name, "age"); + let category_ident = Identifier::new(&table_name, "category"); + + for batch_start in (0..num_records).step_by(batch_size) { + let batch_end = (batch_start + batch_size as i32).min(num_records); + let batch_count = batch_end - batch_start; + + let mut prepared = Vec::with_capacity((batch_count * 3) as usize); + for _ in 0..batch_count { + let name: String = Name(EN).fake(); + // Realistic age range — uniform 18..=90 gives ~72 distinct + // buckets, low enough cardinality that a HashAggregate over the + // ORE-block extractor would group meaningfully but high enough + // that range predicates like `age > 30` are selective. + let age: i32 = (18..=90).fake(); + let category: String = FakeCategory.fake(); + + prepared.push(PreparedPlaintext::new( + Cow::Borrowed(&name_config), + name_ident.clone(), + Plaintext::new(name), + EqlOperation::Store, + )); + prepared.push(PreparedPlaintext::new( + Cow::Borrowed(&age_config), + age_ident.clone(), + Plaintext::new(age), + EqlOperation::Store, + )); + prepared.push(PreparedPlaintext::new( + Cow::Borrowed(&category_config), + category_ident.clone(), + Plaintext::new(category), + EqlOperation::Store, + )); + } + + let out = encrypt_eql(scoped_cipher.clone(), prepared, &Default::default()).await?; + + // encrypt_eql preserves input order; chunks of 3 reassemble per-row + // (name, age, category) tuples for the multi-column INSERT. + let rows: Vec<(_, _, _)> = out + .chunks_exact(3) + .map(|c| (c[0].clone(), c[1].clone(), c[2].clone())) + .collect(); + + QueryBuilder::new(format!( + "INSERT INTO {} (name, age, category) ", + table_name + )) + .push_values(rows, |mut b, (name, age, category)| { + b.push_bind(Json(name)); + b.push_bind(Json(age)); + b.push_bind(Json(category)); + }) + .build() + .execute(&pool) + .await?; + } + + Ok(()) +} diff --git a/src/bin/encrypt_json_large.rs b/src/bin/encrypt_json_large.rs index 6f3da6d..d8e6dff 100644 --- a/src/bin/encrypt_json_large.rs +++ b/src/bin/encrypt_json_large.rs @@ -2,135 +2,26 @@ //! //! This binary generates large, complex JSON objects containing user information, company //! details, addresses, and order history using the fake crate. The objects are encrypted -//! using the cipherstash-client library with SteVec indexing and stored in the -//! json_large_encrypted table. -//! -//! The encrypted JSON objects support: -//! - Searchable encrypted vectors (SteVec) for term-based searches +//! using the cipherstash-client library WITHOUT any searchable indexes. It is the baseline +//! that pairs with `encrypt_ste_vec_large` to quantify the ingest cost of SteVec indexing +//! on large payloads. //! //! Environment variables: //! - DATABASE_URL: PostgreSQL connection string //! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - BATCH_SIZE: Number of records per batch insert (default: 1000) //! - CS_CLIENT_ID: CipherStash client ID -//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_CLIENT_KEY: CipherStash client key //! - CS_WORKSPACE_CRN: CipherStash workspace CRN use anyhow::Result; use cipherstash_client::{ eql::Identifier, - schema::{ - column::{ArrayIndexMode, Index, IndexType}, - ColumnConfig, ColumnType, - }, -}; -use dbbenches::{IngestOptionsBuilder, WrappedJson}; -use fake::{ - faker::{address, chrono, company, internet, name, phone_number}, - Dummy, Fake, Rng, + schema::{ColumnConfig, ColumnType}, }; -use serde_json::json; +use dbbenches::{FakeJsonLarge, IngestOptionsBuilder, WrappedJson}; use std::env; -struct FakeJsonLarge; - -// FIXME: cipherstash-client doesn't have a From for Plaintext impl yet, so we use String here -impl Dummy for WrappedJson { - fn dummy_with_rng(_config: &FakeJsonLarge, _: &mut R) -> Self { - let department = [ - "Engineering", - "Sales", - "Marketing", - "HR", - "Finance", - "Operations", - ] - .iter() - .take((1..6).fake()) - .last() - .unwrap() - .to_string(); - let type_ = ["Home", "Work", "Billing", "Shipping"] - .iter() - .take((1..4).fake()) - .last() - .unwrap() - .to_string(); - let status = [ - "Pending", - "Processing", - "Shipped", - "Delivered", - "Cancelled", - "Returned", - ] - .iter() - .take((1..6).fake()) - .last() - .unwrap() - .to_string(); - let relationship = ["Spouse", "Parent", "Sibling", "Friend", "Other"] - .iter() - .take((1..5).fake()) - .last() - .unwrap() - .to_string(); - - let value = json!({ - "user": { - "first_name": name::en::FirstName().fake::(), - "last_name": name::en::LastName().fake::(), - "age": (18..=99).fake::(), - "email": internet::en::FreeEmail().fake::(), - "username": internet::en::Username().fake::(), - "contact": { - "phone": phone_number::en::PhoneNumber().fake::(), - "mobile": phone_number::en::CellNumber().fake::(), - "emergency_contact": { - "name": name::en::Name().fake::(), - "phone": phone_number::en::PhoneNumber().fake::(), - "relationship": relationship - } - } - }, - "company": { - "name": company::en::CompanyName().fake::(), - "industry": company::en::Industry().fake::(), - "position": company::en::Profession().fake::(), - "department": department, - "salary": (40000..=300000).fake::(), - "start_date": chrono::en::Date().fake::() - }, - "addresses": (0..(1..4).fake::()).map(|_| { - json!({ - "type": type_, - "street": address::en::StreetName().fake::(), - "city": address::en::CityName().fake::(), - "state": address::en::StateName().fake::(), - "zip": address::en::ZipCode().fake::(), - "country": "United States" - }) - }).collect::>(), - "orders": (0..(5..=20).fake::()).map(|_| { - json!({ - "order_id": format!("ORD-{}", (100000..=999999).fake::()), - "date": chrono::en::Date().fake::(), - "total": (10.0..=5000.0).fake::(), - "status": status, - "items": (0..(1..=8).fake::()).map(|_| { - json!({ - "product": company::en::Buzzword().fake::(), - "quantity": (1..=10).fake::(), - "price": (5.0..=500.0).fake::() - }) - }).collect::>() - }) - }).collect::>() - }); - - WrappedJson(value) - } -} - #[tokio::main] async fn main() -> Result<()> { let num_records: i32 = env::var("NUM_RECORDS") @@ -138,19 +29,18 @@ async fn main() -> Result<()> { .parse() .expect("NUM_RECORDS must be a valid integer"); + let batch_size: usize = env::var("BATCH_SIZE") + .unwrap_or_else(|_| "1000".to_string()) + .parse() + .expect("BATCH_SIZE must be a valid integer"); + IngestOptionsBuilder::new("encrypt_json_large") .num_records(num_records) - .batch_size(1000) + .batch_size(batch_size) .identifier(Identifier::new("json_large_encrypted", "value")) .column_config( - ColumnConfig::build("value") - .casts_as(ColumnType::Json) - // FIXME: There is no convenience method for SteVec yet on Index - .add_index(Index::new(IndexType::SteVec { - prefix: "value".to_string(), - term_filters: Default::default(), - array_index_mode: ArrayIndexMode::default(), - })), + // No searchable indexes — pure encryption-and-ingest baseline. + ColumnConfig::build("value").casts_as(ColumnType::JsonB), ) .build()? .ingest::(FakeJsonLarge) diff --git a/src/bin/encrypt_json_small.rs b/src/bin/encrypt_json_small.rs index 164fc94..5a42a0d 100644 --- a/src/bin/encrypt_json_small.rs +++ b/src/bin/encrypt_json_small.rs @@ -1,50 +1,27 @@ //! Encrypt small JSON data binary - encrypts generated JSON objects using CipherStash //! //! This binary generates small JSON objects (first_name, last_name, age, email) using -//! the fake crate and encrypts them using the cipherstash-client library with SteVec -//! indexing, storing the encrypted values in the json_small_encrypted table. -//! -//! The encrypted JSON objects support: -//! - Searchable encrypted vectors (SteVec) for term-based searches +//! the fake crate and encrypts them using the cipherstash-client library WITHOUT any +//! searchable indexes. It is the baseline that pairs with `encrypt_ste_vec_small` to +//! quantify the ingest cost of SteVec indexing. //! //! Environment variables: //! - DATABASE_URL: PostgreSQL connection string //! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - BATCH_SIZE: Number of records per batch insert (default: 1000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) //! - CS_CLIENT_ID: CipherStash client ID -//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_CLIENT_KEY: CipherStash client key //! - CS_WORKSPACE_CRN: CipherStash workspace CRN use anyhow::Result; use cipherstash_client::{ eql::Identifier, - schema::{ - column::{ArrayIndexMode, Index, IndexType}, - ColumnConfig, ColumnType, - }, -}; -use dbbenches::{IngestOptionsBuilder, WrappedJson}; -use fake::{ - faker::{internet, name}, - Dummy, Fake, Rng, + schema::{ColumnConfig, ColumnType}, }; -use serde_json::json; +use dbbenches::{FakeJsonSmall, IngestOptionsBuilder, WrappedJson}; use std::env; -struct FakeJsonSmall; - -// FIXME: cipherstash-client doesn't have a From for Plaintext impl yet, so we use String here -impl Dummy for WrappedJson { - fn dummy_with_rng(_config: &FakeJsonSmall, _: &mut R) -> Self { - let value = json!({ - "first_name": name::en::FirstName().fake::(), - "last_name": name::en::LastName().fake::(), - "age": (18..=99).fake::(), - "email": internet::en::FreeEmail().fake::(), - }); - WrappedJson(value) - } -} - #[tokio::main] async fn main() -> Result<()> { let num_records: i32 = env::var("NUM_RECORDS") @@ -52,19 +29,21 @@ async fn main() -> Result<()> { .parse() .expect("NUM_RECORDS must be a valid integer"); + let batch_size: usize = env::var("BATCH_SIZE") + .unwrap_or_else(|_| "1000".to_string()) + .parse() + .expect("BATCH_SIZE must be a valid integer"); + + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("json_small_encrypted{}", table_suffix); + IngestOptionsBuilder::new("encrypt_json_small") .num_records(num_records) - .batch_size(1000) - .identifier(Identifier::new("json_small_encrypted", "value")) + .batch_size(batch_size) + .identifier(Identifier::new(&table_name, "value")) .column_config( - ColumnConfig::build("value") - .casts_as(ColumnType::Json) - // FIXME: There is no convenience method for SteVec yet on Index - .add_index(Index::new(IndexType::SteVec { - prefix: "value".to_string(), - term_filters: Default::default(), - array_index_mode: ArrayIndexMode::default(), - })), + // No searchable indexes — pure encryption-and-ingest baseline. + ColumnConfig::build("value").casts_as(ColumnType::JsonB), ) .build()? .ingest::(FakeJsonSmall) diff --git a/src/bin/encrypt_ste_vec_large.rs b/src/bin/encrypt_ste_vec_large.rs new file mode 100644 index 0000000..fcdb91d --- /dev/null +++ b/src/bin/encrypt_ste_vec_large.rs @@ -0,0 +1,61 @@ +//! Encrypt large JSON data binary - encrypts generated complex JSON objects using CipherStash +//! +//! This binary generates large, complex JSON objects containing user information, company +//! details, addresses, and order history using the fake crate. The objects are encrypted +//! using the cipherstash-client library with SteVec indexing and stored in the +//! json_large_encrypted table. +//! +//! The encrypted JSON objects support: +//! - Searchable encrypted vectors (SteVec) for term-based searches +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - BATCH_SIZE: Number of records per batch insert (default: 1000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{ + column::{ArrayIndexMode, Index, IndexType}, + ColumnConfig, ColumnType, + }, +}; +use dbbenches::{FakeJsonLarge, IngestOptionsBuilder, WrappedJson}; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let batch_size: usize = env::var("BATCH_SIZE") + .unwrap_or_else(|_| "1000".to_string()) + .parse() + .expect("BATCH_SIZE must be a valid integer"); + + IngestOptionsBuilder::new("encrypt_ste_vec_large") + .num_records(num_records) + .batch_size(batch_size) + .identifier(Identifier::new("json_large_encrypted", "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::JsonB) + // FIXME: There is no convenience method for SteVec yet on Index + .add_index(Index::new(IndexType::SteVec { + prefix: "value".to_string(), + term_filters: Default::default(), + array_index_mode: ArrayIndexMode::default(), + })), + ) + .build()? + .ingest::(FakeJsonLarge) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_ste_vec_small.rs b/src/bin/encrypt_ste_vec_small.rs new file mode 100644 index 0000000..36b5a4b --- /dev/null +++ b/src/bin/encrypt_ste_vec_small.rs @@ -0,0 +1,64 @@ +//! Encrypt small JSON data binary - encrypts generated JSON objects using CipherStash +//! +//! This binary generates small JSON objects (first_name, last_name, age, email) using +//! the fake crate and encrypts them using the cipherstash-client library with SteVec +//! indexing, storing the encrypted values in the json_small_encrypted table. +//! +//! The encrypted JSON objects support: +//! - Searchable encrypted vectors (SteVec) for term-based searches +//! +//! Environment variables: +//! - DATABASE_URL: PostgreSQL connection string +//! - NUM_RECORDS: Number of records to generate (default: 10000) +//! - BATCH_SIZE: Number of records per batch insert (default: 1000) +//! - TABLE_SUFFIX: Optional suffix for table name (e.g., _10000) +//! - CS_CLIENT_ID: CipherStash client ID +//! - CS_CLIENT_KEY: CipherStash client key +//! - CS_WORKSPACE_CRN: CipherStash workspace CRN + +use anyhow::Result; +use cipherstash_client::{ + eql::Identifier, + schema::{ + column::{ArrayIndexMode, Index, IndexType}, + ColumnConfig, ColumnType, + }, +}; +use dbbenches::{FakeJsonSmall, IngestOptionsBuilder, WrappedJson}; +use std::env; + +#[tokio::main] +async fn main() -> Result<()> { + let num_records: i32 = env::var("NUM_RECORDS") + .unwrap_or_else(|_| "10000".to_string()) + .parse() + .expect("NUM_RECORDS must be a valid integer"); + + let batch_size: usize = env::var("BATCH_SIZE") + .unwrap_or_else(|_| "1000".to_string()) + .parse() + .expect("BATCH_SIZE must be a valid integer"); + + let table_suffix = env::var("TABLE_SUFFIX").unwrap_or_default(); + let table_name = format!("json_ste_vec_small_encrypted{}", table_suffix); + + IngestOptionsBuilder::new("encrypt_ste_vec_small") + .num_records(num_records) + .batch_size(batch_size) + .identifier(Identifier::new(&table_name, "value")) + .column_config( + ColumnConfig::build("value") + .casts_as(ColumnType::JsonB) + // FIXME: There is no convenience method for SteVec yet on Index + .add_index(Index::new(IndexType::SteVec { + prefix: "value".to_string(), + term_filters: Default::default(), + array_index_mode: ArrayIndexMode::default(), + })), + ) + .build()? + .ingest::(FakeJsonSmall) + .await?; + + Ok(()) +} diff --git a/src/bin/encrypt_string.rs b/src/bin/encrypt_string.rs index 4d41059..c27afe5 100644 --- a/src/bin/encrypt_string.rs +++ b/src/bin/encrypt_string.rs @@ -41,7 +41,7 @@ async fn main() -> Result<()> { .identifier(Identifier::new(&table_name, "value")) .column_config( ColumnConfig::build("value") - .casts_as(ColumnType::Text) + .casts_as(ColumnType::Utf8Str) .add_index(Index::new_unique()) .add_index(Index::new_match()), ) diff --git a/src/lib.rs b/src/lib.rs index eb15355..2ddcc0d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,9 +15,105 @@ use std::env; use std::fmt::Debug; use std::sync::Arc; +/// Generator for low-cardinality categorical strings of the form `CAT_001` +/// .. `CAT_250`, uniform random over 250 distinct values. Used by the +/// `category_encrypted_*` and `category_plaintext_*` tables that drive the +/// realistic-GROUP-BY scenarios in `benches/group_by.rs`. 250 groups was +/// chosen to roughly match the ISO 3166-1 country-code cardinality (~250) — +/// large enough that the hash-aggregate table is interesting, small enough +/// that the result-set emission cost is negligible compared with the +/// per-row HMAC. +pub struct FakeCategory; + +impl Dummy for String { + fn dummy_with_rng(_: &FakeCategory, rng: &mut R) -> String { + let n: u32 = (1u32..=250u32).fake_with_rng(rng); + format!("CAT_{:03}", n) + } +} + +/// Sample a single plaintext string from an encrypted table by decrypting +/// the first row. Used by `benches/exact.rs` to derive a search term that's +/// guaranteed to match at least one record — the previous hardcoded +/// `"Bob Johnson"` returned zero rows at every tier because `fake::Name` +/// doesn't generate that exact combination, so the EXACT bench was secretly +/// measuring "hash-index lookup + nothing found + LIMIT 1 early exit" +/// rather than realistic equality-query cost. +pub async fn sample_plaintext_string( + pool: &sqlx::PgPool, + cipher: Arc>, + table_name: &str, +) -> Result { + // `value::jsonb` cast is needed because the column type is the custom + // `eql_v2_encrypted` Postgres type — sqlx's JSONB decoder doesn't know + // how to read that directly. Every other bench file does the same cast + // in its SELECT shape (e.g. `SELECT id, value::jsonb FROM ...`). + let row: (Json,) = + sqlx::query_as(&format!("SELECT value::jsonb FROM {} LIMIT 1", table_name)) + .fetch_one(pool) + .await + .with_context(|| format!("sample query failed against {}", table_name))?; + + let decrypted = decrypt_eql(cipher, vec![row.0 .0], &Default::default()) + .await + .context("sample decrypt failed")?; + + // `Plaintext` implements `Drop` (for zeroizing on drop), so we can't + // move the inner String out via pattern match — borrow + clone instead. + let pt = decrypted + .into_iter() + .next() + .ok_or_else(|| anyhow::anyhow!("decrypt_eql returned empty Vec for {}", table_name))?; + match &pt { + Plaintext::Utf8Str(Some(s)) => Ok(s.clone()), + other => anyhow::bail!( + "expected Utf8Str sample from {}, got {:?}", + table_name, + other + ), + } +} + +/// Install a tracing subscriber honouring `RUST_LOG` (defaults to `warn` if +/// unset). Idempotent — calling twice is a no-op. Lets cipherstash-client +/// / zerokms-protocol trace! emissions reach stderr, including the rich +/// internal failure traces in `vitur_client::generate_keys` / +/// `decrypt` / `retrieve_keys`. +pub fn init_tracing() { + let _ = tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("warn")), + ) + .with_writer(std::io::stderr) + .try_init(); +} + pub async fn init_scoped_cipher() -> Result>> { + // Tuning for the bulk-ingest path. See the "Tuning for bulk ingest" + // section on `ZeroKMSBuilder` (cipherstash-suite#1960) for the + // rationale; the short version: + // + // - `connect_timeout(5)`: fast-fail if TCP+TLS to ZeroKMS can't open + // in 5 s. Real broken-network signal. + // - `request_timeout(60)`: generous total budget. The default (10 s) + // trips at scale because cold-pool `generate-data-key` calls can + // plausibly exceed it under variable AWS Sydney latency. + // - `pool_idle_timeout(600)`: keep warm TLS connections alive across + // the bench's idle gaps between batches (default closes after 90 + // s). + // - `max_keys_per_req(100)`: smaller per-request server work → + // lower per-call latency → lower chance of any one request + // timing out. Trades request count for predictability. + // - `max_concurrent_reqs(20)`: more parallelism to compensate for + // the smaller batches. let zerokms = ZeroKMSBuilder::auto() .context("failed to build ZeroKMS client")? + .with_connect_timeout(5) + .with_request_timeout(60) + .with_pool_idle_timeout(600) + .with_max_keys_per_req(100) + .with_max_concurrent_reqs(20) .with_key_provider(FallbackKeyProvider::new( EnvKeyProvider, ProfileStore::default(), @@ -114,6 +210,13 @@ impl IngestOptions { .connect(&database_url) .await?; + // Init once and reuse for the binary lifetime. The previous + // "refresh every 200k rows" loop discarded the warm reqwest + // connection pool and forced cold-start TLS handshakes — which, + // with the cipherstash-client default 10s request_timeout, + // reliably tripped `SendRequest: operation timed out`. Auth + // tokens auto-refresh through stack-auth's AutoRefresh under the + // same client; no manual rotation needed. let scoped_cipher = init_scoped_cipher().await?; let column_config = Cow::Borrowed(&self.column_config); @@ -166,7 +269,130 @@ pub struct WrappedJson(pub serde_json::Value); impl From for Plaintext { fn from(WrappedJson(value): WrappedJson) -> Self { - Plaintext::Json(Some(value)) + // cipherstash-client renamed `Plaintext::Json` → `Plaintext::JsonB` + // between alpha.4 (crates.io) and the suite-1 main branch we're + // currently pinned to. Use the new name here; revert if/when we + // move back to a published cipherstash-client. + Plaintext::JsonB(Some(value)) + } +} + +/// Generator config for small JSON payloads (4 flat fields). +pub struct FakeJsonSmall; + +impl Dummy for WrappedJson { + fn dummy_with_rng(_config: &FakeJsonSmall, _: &mut R) -> Self { + use fake::faker::{internet, name}; + + let value = json!({ + "first_name": name::en::FirstName().fake::(), + "last_name": name::en::LastName().fake::(), + "age": (18..=99).fake::(), + "email": internet::en::FreeEmail().fake::(), + }); + WrappedJson(value) + } +} + +/// Generator config for large nested JSON payloads (users / company / addresses / orders). +pub struct FakeJsonLarge; + +impl Dummy for WrappedJson { + fn dummy_with_rng(_config: &FakeJsonLarge, _: &mut R) -> Self { + use fake::faker::{address, chrono, company, internet, name, phone_number}; + + let department = [ + "Engineering", + "Sales", + "Marketing", + "HR", + "Finance", + "Operations", + ] + .iter() + .take((1..6).fake()) + .last() + .unwrap() + .to_string(); + let type_ = ["Home", "Work", "Billing", "Shipping"] + .iter() + .take((1..4).fake()) + .last() + .unwrap() + .to_string(); + let status = [ + "Pending", + "Processing", + "Shipped", + "Delivered", + "Cancelled", + "Returned", + ] + .iter() + .take((1..6).fake()) + .last() + .unwrap() + .to_string(); + let relationship = ["Spouse", "Parent", "Sibling", "Friend", "Other"] + .iter() + .take((1..5).fake()) + .last() + .unwrap() + .to_string(); + + let value = json!({ + "user": { + "first_name": name::en::FirstName().fake::(), + "last_name": name::en::LastName().fake::(), + "age": (18..=99).fake::(), + "email": internet::en::FreeEmail().fake::(), + "username": internet::en::Username().fake::(), + "contact": { + "phone": phone_number::en::PhoneNumber().fake::(), + "mobile": phone_number::en::CellNumber().fake::(), + "emergency_contact": { + "name": name::en::Name().fake::(), + "phone": phone_number::en::PhoneNumber().fake::(), + "relationship": relationship + } + } + }, + "company": { + "name": company::en::CompanyName().fake::(), + "industry": company::en::Industry().fake::(), + "position": company::en::Profession().fake::(), + "department": department, + "salary": (40000..=300000).fake::(), + "start_date": chrono::en::Date().fake::() + }, + "addresses": (0..(1..4).fake::()).map(|_| { + json!({ + "type": type_, + "street": address::en::StreetName().fake::(), + "city": address::en::CityName().fake::(), + "state": address::en::StateName().fake::(), + "zip": address::en::ZipCode().fake::(), + "country": "United States" + }) + }).collect::>(), + "orders": (0..(5..=20).fake::()).map(|_| { + json!({ + "order_id": format!("ORD-{}", (100000..=999999).fake::()), + "date": chrono::en::Date().fake::(), + "total": (10.0..=5000.0).fake::(), + "status": status, + "items": (0..(1..=8).fake::()).map(|_| { + json!({ + "product": company::en::Buzzword().fake::(), + "quantity": (1..=10).fake::(), + "price": (5.0..=500.0).fake::() + }) + }).collect::>() + }) + }).collect::>() + }); + + WrappedJson(value) } } @@ -261,4 +487,193 @@ impl EncryptedQuery { Ok(decrypted) } + + /// Run `EXPLAIN (FORMAT JSON)` on the bound query and return the parsed + /// plan as `serde_json::Value`. Used by each bench's startup pass to + /// record what the planner did with the canonical scenario shape — see + /// `ScenarioMetadata` / `write_metadata_file` for the captured fields. + pub async fn explain(&self, pool: &sqlx::PgPool) -> Result { + let explain_sql = format!("EXPLAIN (FORMAT JSON) {}", self.statement); + let row: (Json,) = sqlx::query_as(&explain_sql) + .bind(Json(&self.eql)) + .fetch_one(pool) + .await?; + Ok(row.0 .0) + } + + /// Serialise the bound parameter as a JSON value for metadata logging. + pub fn parameter_json(&self) -> Result { + Ok(serde_json::to_value(&self.eql)?) + } +} + +// --- Bench metadata sidecar ---------------------------------------------- +// +// Each query bench writes a `results/query/_metadata_.json` +// sidecar alongside the criterion-generated `*_rows_*.json` file. The +// sidecar captures, per scenario: +// +// * `id` — same string as criterion's benchmark id, so the +// two files can be joined by id. +// * `query` — the exact SQL the bench ran (template with $1 +// placeholders intact; placeholders are filled by +// sqlx at execute time). +// * `parameters` — list of bound values, serialised as JSON. For +// the encrypted benches the parameter is the +// EqlCiphertext payload; for plaintext / json the +// list is typically empty. +// * `explain` — output of `EXPLAIN (FORMAT JSON)` against the +// bound query, captured once at startup before +// the criterion loop runs. +// * `indexes_used` — flat sorted list of every `Index Name` value +// found anywhere in the EXPLAIN tree. Useful for +// downstream analysis without re-parsing the +// whole plan. + +#[derive(serde::Serialize)] +pub struct ScenarioMetadata { + pub id: String, + pub query: String, + pub parameters: Vec, + pub explain: serde_json::Value, + pub indexes_used: Vec, + /// Actual row count returned by a single pre-bench execution of the + /// query. The cost (one extra round-trip per scenario at startup) is + /// trivial relative to criterion's warmup phase, and gives us a real + /// number rather than the planner's estimate from `Plan Rows`. + pub rows_returned: u64, +} + +/// Walk an `EXPLAIN (FORMAT JSON)` tree and collect every `Index Name`. +/// +/// PG's plan emits `"Index Name": ""` on Index Scan, Bitmap Index +/// Scan, and Index Only Scan nodes. We don't need to interpret which kind +/// of scan it is here — just surface the names so the report (and a human +/// debugging a slow bench) can see what the planner picked. Deduplicated +/// and sorted for stable output. +pub fn extract_indexes_used(explain: &serde_json::Value) -> Vec { + let mut out = Vec::new(); + collect_index_names(explain, &mut out); + out.sort(); + out.dedup(); + out +} + +fn collect_index_names(node: &serde_json::Value, out: &mut Vec) { + match node { + serde_json::Value::Object(map) => { + if let Some(serde_json::Value::String(name)) = map.get("Index Name") { + out.push(name.clone()); + } + for v in map.values() { + collect_index_names(v, out); + } + } + serde_json::Value::Array(arr) => { + for v in arr { + collect_index_names(v, out); + } + } + _ => {} + } +} + +/// Diagnostic wrapper for inner-loop bench failures. Prints a structured +/// error block before panicking, including the scenario id, the error's +/// `Display` *and* `Debug` forms (so the anyhow chain shows up), and a +/// hint about the common failure modes we've seen. +/// +/// Replaces bare `.unwrap()` / `.expect("...")` in criterion `iter` +/// closures — when a bench fails an hour into a 10M run, the +/// difference between "called unwrap on Err" and "ORE/ore_decrypt/.../1M +/// — ZeroKMS decrypt failure, here's what to do" matters. +pub fn bench_assert(result: Result, scenario: &str) -> T +where + E: std::fmt::Display + std::fmt::Debug, +{ + match result { + Ok(v) => v, + Err(e) => { + print_bench_failure(scenario, &e); + panic!("bench failed in `{}`: {}", scenario, e); + } + } +} + +fn print_bench_failure(scenario: &str, e: &E) +where + E: std::fmt::Display + std::fmt::Debug, +{ + let msg = format!("{}", e); + eprintln!(); + eprintln!("==== BENCH FAILURE ===="); + eprintln!("scenario: {}", scenario); + eprintln!("error: {}", e); + eprintln!("debug: {:?}", e); + + // The most common failure on long bench runs is the ZeroKMS scoped + // cipher's TTL expiring mid-iteration. We've hit this several times; + // the underlying message is the bit after "Could not decrypt data + // using keyset", which on its own doesn't tell a fresh reader what + // to do next. + if msg.contains("Could not decrypt") || msg.contains("keyset") { + eprintln!(); + eprintln!("hint: ZeroKMS decrypt failure. Most likely the scoped-cipher TTL"); + eprintln!(" expired mid-run — ScopedCipher::init_default binds the"); + eprintln!(" session to a fixed lifetime (~10-15 minutes on ZeroKMS) and"); + eprintln!(" criterion's full sample sweep at 1M/10M can outlive it."); + eprintln!(" Re-running the bench picks up fresh credentials."); + eprintln!(" If the failure persists across a fresh run:"); + eprintln!(" 1. `mise run truncate` to drop rows that may have been"); + eprintln!(" encrypted under an earlier generation."); + eprintln!(" 2. Re-populate via the relevant `prepare:*` task."); + eprintln!(" 3. Re-run the bench."); + eprintln!(" If still failing, verify CS_CLIENT_ID / CS_CLIENT_KEY /"); + eprintln!(" CS_WORKSPACE_CRN are valid and check the CipherStash"); + eprintln!(" console for rate limits / quota."); + } else if msg.contains("Unexpected error") { + eprintln!(); + eprintln!("hint: opaque cipherstash-client error. The message itself is"); + eprintln!(" unhelpful but the underlying cause is often a ZeroKMS"); + eprintln!(" authentication issue (TTL expiry, rate limit, expired"); + eprintln!(" credential). Same recovery as the decrypt-failure hint:"); + eprintln!(" re-run; if persistent, check the CipherStash console."); + } else if msg.contains("Connection refused") || msg.contains("Connection reset") { + eprintln!(); + eprintln!("hint: database connection error. The postgres container may have"); + eprintln!(" stopped — try `mise run postgres` to start it."); + } else if msg.contains("relation") && msg.contains("does not exist") { + eprintln!(); + eprintln!("hint: missing table. The schema isn't set up — run `mise run"); + eprintln!(" setup-db` or, for query benches, the `prepare:*` task"); + eprintln!(" that creates the target row-count variant table."); + } else if msg.contains("query failed") || msg.contains("syntax error") { + eprintln!(); + eprintln!("hint: SQL execution error. Inspect the recorded query in the"); + eprintln!(" `*_metadata_.json` sidecar for the scenario above"); + eprintln!(" and try running it against the bench database directly."); + } + eprintln!("==== END BENCH FAILURE ===="); + eprintln!(); +} + +/// Write the scenario metadata sidecar to +/// `results/query/_metadata_.json` (path relative to the +/// bench process's current working directory, which `cargo criterion` +/// sets to the package root). +pub fn write_metadata_file( + prefix: &str, + target_rows: &str, + scenarios: Vec, +) -> Result<()> { + let dir = std::path::PathBuf::from("results/query"); + std::fs::create_dir_all(&dir)?; + let path = dir.join(format!("{}_metadata_{}.json", prefix, target_rows)); + let payload = serde_json::json!({ + "target_rows": target_rows, + "scenarios": scenarios, + }); + std::fs::write(&path, serde_json::to_string_pretty(&payload)?)?; + eprintln!("bench metadata written to {}", path.display()); + Ok(()) }