-
Notifications
You must be signed in to change notification settings - Fork 11
Performance testing for UUIDv7 #128
Comments
Here are some tests based on Fabio Telles' article (in Portuguese): UUID insert tests. Result of Test 1 (generate each UUID while inserting):
Result of Test 2 (generate all UUIDs before inserting):
NOTES:
|
fabiolimace, could you please, for comparability with other implementations, express the generation rate (writing) and the rate of search of generated UUIDv7 (selective reading) in units per millisecond? Please highlight these two values among other values. |
Sure! Done. |
(I wasn't sure how all the columns were defined, so I took a best guess.)
Test codevar stopwatch = Stopwatch.StartNew();
const int guidCount = 100_000_000;
for (var i = 0; i < guidCount; i++)
GuidHelpers.CreateVersion7();
stopwatch.Stop();
$"{guidCount:n0} v7 GUIDs in {stopwatch.ElapsedMilliseconds:n0}ms; {((double) guidCount / stopwatch.ElapsedMilliseconds):f1}/ms".Dump();
Intel Core i7-10875H @ 2.30 GHz |
Thank you @bgrainger! You have achieved high performance! Sorry for the lack of detailed instructions. I meant the following:
|
I tried to follow @bgrainger example as close as possible. Since my code does both UUIDv7 and UUIDv4 generation, I expanded both table and code a bit.
Test Codeusing Medo; using System.Diagnostics;
Intel Core i5-1135G7 @ 2.40 GHz |
It seems like it is impossible to test UUID generation since that is more or less just testing the underlying RNG and how fast it is to get a timestamp. Wall time is still a useful metric, but the underlying cause is potentially a bit misleading. Also, what is "parsing"? Just checking string length minus hyphens? Extracting version classifier? Testing https://docs.rs/uuid/latest/uuid using the default RNG:
Enabling the crate's feature
The difference between the two is pretty telling about the impact the RNG has. v1 and v6 also show that they more or less evaluate the speed of getting a system timestamp.If I remove the Run on an AMD Ryzen 9 5900X Library: Test sourceuse std::{hint::black_box, time::SystemTime};
use uuid::{NoContext, Uuid};
const WARMUP: u32 = 10_000;
const COUNT: u32 = 5_000_000;
const PARSE: &str = "a1a2a3a4b1b2c1c2d1d2d3d4d5d6d7d8";
const PARSE_HYPHENATED: &str = "a1a2a3a4-b1b2-c1c2-d1d2-d3d4d5d6d7d8";
fn main() {
let ts_stored = uuid::Timestamp::now(NoContext);
run_bench("uuidv1 new now", || {
Uuid::now_v1(black_box(&[0; 6]));
});
run_bench("uuidv1 new fixed timestamp", || {
Uuid::new_v1(black_box(ts_stored), black_box(&[0; 6]));
});
run_bench("uuidv4 new", || {
Uuid::new_v4();
});
run_bench("uuidv6 new now", || {
Uuid::now_v6(black_box(&[0; 6]));
});
run_bench("uuidv6 new fixed timestamp", || {
Uuid::new_v6(black_box(ts_stored), black_box(&[0; 6]));
});
run_bench("uuidv7 new now", || {
Uuid::now_v7();
});
run_bench("uuidv7 new fixed timestamp", || {
Uuid::new_v7(black_box(ts_stored));
});
run_bench("uuidv7 parse", || {
Uuid::parse_str(PARSE).unwrap();
});
run_bench("uuidv7 parse hyphenated", || {
Uuid::parse_str(PARSE_HYPHENATED).unwrap();
});
}
fn run_bench(name: &str, func: impl Fn()) {
for _ in 0..WARMUP {
black_box(func());
}
let start = SystemTime::now();
for _ in 0..COUNT {
black_box(func());
}
let duration = start.elapsed().unwrap().as_secs_f64();
let t = duration / f64::from(COUNT);
let t_ns = t / 1e-9;
let f = 1.0 / t;
let f_mhz = f / 1e6;
println!("test '{name}' completed with period {t_ns:.3} ns and frequency {f_mhz:.3} MHz");
} |
It seems to me that you are testing UUID generation rate, but instead you need to test rate of insertion and indexing of table records containing UUIDs generated on the fly. Above this is called Write frequency (kHz). It depends not only on the generation rate, but also on the DBMS, on the structure of the UUID and possible deviations from monotonicity. It is also necessary to test Read frequency (kHz) for these inserted records in accordance with the Performance testing programmig code for the "Read frequency" column, as described:
Attribute t.id contains 100,000,000 different values of UUIDv7 format generated at full rate |
The above C# examples seem to be generation tests and not db tests, no? Or was that not the intent? |
Everyone is interested in the final result (database performance with UUIDv7 for writing with indexing, as well as for searching), but not the intermediate result (generation rate). Database performance depends not only on the generation rate, but also on the successful choice of the UUIDv7 structure from many possible options and on the algorithms for calculating and buffering UUIDv7 segments. For different DBMSs and different settings of a certain DBMS, the optimal UUIDv7 structure and algorithms may be different. It is important to remember that UUIDv7 implementations compete not only with each other, but also with autoincrement. The goal of performance testing is ultimately to find a UUIDv7 implementation that can compete with autoincrement. No one is interested in the performance of a timestamp source or random number generator per se. |
Test source
|
@Zer0x00 Thanks for the effort. Is there any way to use Python |
I've updated the code and the values in the original post to use the |
I encourage you to publish here performance testing programmig code, test cases (initial data) and performance testing results both for generation and seach, attaching or indicating UUIDv7 generators, UUIDv7's exact structure, technical spec sheets, generation algorithms, programming langueges, hardware, libraries and DBMS or other platforms. Performance should be expressed, respectively, in UUIDv7's generated or found per millisecond. It would be great if performance tests were universal, and allowed to compare different implementations of UUIDv7 generators
It would be great if you use this pattern:
Designations:
Performance testing programmig code for the "Read frequency" column:
Attribute t.id contains 100,000,000 different values of UUIDv7 format generated at full rate
The text was updated successfully, but these errors were encountered: