Our extensive experience at MGateway Ltd has proven to us that Global Storage Databases are the fastest databases technologies available today.
We're keen to allow others to experience this performance for themselves, which is one of the reasons we've created this repository: making it quick and easy for you to try out these database technologies which many/most of you will have never even heard of!
Let's start with a very simple and basic test: we're going to create a set of simple persistent key/value pairs of the form:
keyvalue[n] = 'hello world'
where n is an integer starting from 1
We'll run a simple JavaScript loop and, by default, we'll create 10 million such key/value pair records in the database and time how long it takes to create them.
We'll then run the loop again and time how long it takes to read back the key/value pairs from the database.
The benchmark demonstration uses our ultra-high performance mg-dbx-napi JavaScript interface.
You'll also be able to test for any performance differences between Node.js and Bun.js, running the exact same script.
All three of our mg-showcase Containers includes a version of this benchmark demonstration. You'll find the source file as follows:
- YottaDB Container: /opt/mgateway/bm_mgdbxnapi.mjs
- IRIS Containers: /home/irisowner/bm_mgdbxnapi.mjs
Feel free to examine its source code to see how the benchmark works.
Consult the mg-dbx-napi documentation which explains the syntax used for creating and reading Global Storage key/value pairs via the mg-dbx-napi interface.
-
Start your mg-showcase Container if it isn't already running
-
Shell into the Container from another process. You should be in the default directory:
- YottaDB Container: /opt/mgateway
- IRIS Containers: /home/irisowner
-
Now run the benchmark demonstration script. We'll start by creating just 1000 key/value pairs:
- Node.js:
node bm_mgdbxnapi.mjs 1000
- Bun.js:
bun bm_mgdbxnapi.mjs 1000
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
-
Node.js
root@c353f95cfb7a:/opt/mgateway# node bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000 inserts in 0 seconds rate: 52,631 /sec ------ finished 1000 gets in 0 seconds rate: 125,000 /sec
-
Bun.js
root@c353f95cfb7a:/opt/mgateway# bun bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000 inserts in 0 seconds rate: 50,000 /sec ------ finished 1000 gets in 0 seconds rate: 166,666 /sec
-
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
-
Node.js
root@fa5bdd7f4f7e:/opt/mgateway# node bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000 inserts in 0 seconds rate: 142,857 /sec ------ finished 1000 gets in 0 seconds rate: 500,000 /sec
-
Bun.js
root@fa5bdd7f4f7e:/opt/mgateway# bun bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000 inserts in 0 seconds rate: 250,000 /sec ------ finished 1000 gets in 0 seconds rate: 500,000 /sec
-
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
-
Node.js
irisowner@c49319fa143f:~$ node bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000 inserts in 0 seconds rate: 38,461 /sec ------ finished 1000 gets in 0 seconds rate: 142,857 /sec
-
Bun.js
irisowner@c49319fa143f:~$ bun bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000 inserts in 0 seconds rate: 58,823 /sec ------ finished 1000 gets in 0 seconds rate: 166,666 /sec
-
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
-
Node.js
irisowner@57adf75db712:~$ node bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000 inserts in 0 seconds rate: 142,857 /sec ------ finished 1000 gets in 0 seconds rate: 500,000 /sec
-
Bun.js
irisowner@57adf75db712:~$ bun bm_mgdbxnapi.mjs 1000 mg-dbx-napi performance test Insert and read back 1000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000 inserts in 0 seconds rate: 333,333 /sec ------ finished 1000 gets in 0 seconds rate: 1,000,000 /sec
-
Let's summarise these results in two tables:
X64 | YottaDB | IRIS |
---|---|---|
Node.js Write | 52,631 | 38,461 |
Bun.js Write | 50,000 | 58,823 |
Node.js Read | 125,000 | 142,857 |
Bun.js Read | 166,666 | 166,666 |
ARM64 | YottaDB | IRIS |
---|---|---|
Node.js Write | 142,857 | 142,857 |
Bun.js Write | 250,000 | 333,000 |
Node.js Read | 500,000 | 500,000 |
Bun.js Read | 500,000 | 1,000,000 |
Although we've only created a relatively small number of key/value pairs in this initial benchmark test, we can already see a number of interesting patterns emerging:
-
Clearly the X64 machine used here is, not surprisingly a lot slower than the M1 Mac Mini, but you can see that regardless of Operating System and database, everything else works identically. The only difference is that for clarity, the Global or Document Name we've used for each database is different:
- YottaDB: ydbtest
- IRIS: iristest
-
Generally, Bun.js appears to provide better performance, except when writing key/value pairs to YottaDB on the X64 machine.
-
YottaDB appears to outperform IRIS when writing key/value pairs on the X64 machine, but for this test there's otherwise not much between them.
-
IRIS read and write performance on the M1 Mac is impressively high when using Bun.js
Next we'll increase the number of key/value pairs generated and read and see if these patterns persist.
-
Re-run the benchmark demonstration script, but this time specifying 1,000,000 key/value pairs:
- Node.js:
node bm_mgdbxnapi.mjs 1000000
- Bun.js:
bun bm_mgdbxnapi.mjs 1000000
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
-
Node.js
root@c353f95cfb7a:/opt/mgateway# node bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 3 seconds rate: 251,319 /sec ------ finished 1000000 gets in 2 seconds rate: 417,536 /sec
-
Bun.js
root@c353f95cfb7a:/opt/mgateway# bun bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 3 seconds rate: 262,950 /sec ------ finished 1000000 gets in 2 seconds rate: 423,011 /sec
-
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
-
Node.js
root@b438c148a44e:/opt/mgateway# node bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 0 seconds rate: 1,510,574 /sec ------ finished 1000000 gets in 0 seconds rate: 2,309,468 /sec
-
Bun.js
root@b438c148a44e:/opt/mgateway# bun bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 0 seconds rate: 1,373,626 /sec ------ finished 1000000 gets in 0 seconds rate: 2,036,659 /sec
-
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
-
Node.js
irisowner@0190429c1c41:~$ node bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000000 inserts in 4 seconds rate: 245,579 /sec ------ finished 1000000 gets in 3 seconds rate: 326,904 /sec
-
Bun.js
irisowner@0190429c1c41:~$ bun bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000000 inserts in 3 seconds rate: 268,961 /sec ------ finished 1000000 gets in 2 seconds rate: 334,112 /sec
-
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
-
Node.js
irisowner@57adf75db712:~$ node bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000000 inserts in 0 seconds rate: 1,111,111 /sec ------ finished 1000000 gets in 0 seconds rate: 1,862,197 /sec
-
Bun.js
irisowner@57adf75db712:~$ bun bm_mgdbxnapi.mjs 1000000 mg-dbx-napi performance test Insert and read back 1000000 key/value pairs Global name used is ^iristest Please wait... ----- finished 1000000 inserts in 0 seconds rate: 1,145,475 /sec ------ finished 1000000 gets in 0 seconds rate: 1,675,041 /sec
-
Let's summarise these results in two tables:
X64 | YottaDB | IRIS |
---|---|---|
Node.js Write | 251,319 | 245,579 |
Bun.js Write | 262,950 | 268,961 |
Node.js Read | 417,536 | 326,904 |
Bun.js Read | 423,011 | 334,112 |
ARM64 | YottaDB | IRIS |
---|---|---|
Node.js Write | 1,510,574 | 1,111,111 |
Bun.js Write | 1,373,626 | 1,145,475 |
Node.js Read | 2,309,468 | 1,862,127 |
Bun.js Read | 2,036,659 | 1,675,041 |
Now we can begin to get a proper impression of just how fast these two databases are, and how fast a connection our mg-dbx-napi interface gives you.
Of the two databases, at least on the two platforms we've used for these tests, YottaDB appears to be the faster: impressive for a free Open Source database technology!
And take a look at the read performance in particular! These are near in-memory levels of performance, yet the test is genuinely reading the individual key/value pairs directly from the databases. In our experience, we have yet to find any other database technologies that come close to providing these levels of performance.
Now of course, this is a very simple test of a very simple key/value pair data structure.
In the next document we'll look at how you can test and measure the performance when writing and reading more complex data structures.
The most commonly-used database used with Node.js for high-performance storage and retrieval of key/value data is Redis. It's generally considered to be an extremely high-performance persistence store.
So how does it compare with YottaDB and IRIS?
To answer that, you'll find that the Container includes a pre-installed copy of Redis and the standard redis interface package for Node.js. We've also included a benchmark test that closely matches the key/value storage used in the YottaDB and IRIS benchmark tests. You can find the file here in the repo and you'll also find it in your running Container's default directory:
- YottaDB: /opt/mgateway/benchmark_redis.mjs
- IRIS: /home/irisowner/benchmark_redis.mjs
Here's our results when run on the exact same hardware as the mg-dbx-napi tests above:
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
root@db72cac4c3df:/opt/mgateway# node benchmark_redis.mjs Redis performance test Insert and read back 100,000 key/value pairs using HSET and HGET Please wait... ----- finished 100,000 inserts in 8 seconds rate: 11,293 /sec ------ finished 100,000 gets in 8 seconds rate: 11,499 /sec ----------- Redis performance test Insert and read back 100,000 key/value pairs using SET and GET Please wait... ----- finished 100,000 inserts in 8 seconds rate: 11,552 /sec ------ finished 100,000 gets in 8 seconds rate: 11,814 /sec
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
root@15b9ed4d53af:/opt/mgateway# node benchmark_redis.mjs Redis performance test Insert and read back 100,000 key/value pairs using HSET and HGET Please wait... ----- finished 100,000 inserts in 5 seconds rate: 17,056 /sec ------ finished 100,000 gets in 5 seconds rate: 17,079 /sec ----------- Redis performance test Insert and read back 100,000 key/value pairs using SET and GET Please wait... ----- finished 100,000 inserts in 5 seconds rate: 17,041 /sec ------ finished 100,000 gets in 5 seconds rate: 17,123 /sec
You can see that the performance of YottaDB and IRIS using our mg-dbx-napi interface is orders of magnitude higher than using Redis.
Redis, of course, uses a networked interface, and one trick it has up its sleeve is pipelining to improve performance. You'll find another test for Redis using a pipelined connection: look for:
- YottaDB: /opt/mgateway/benchmark_redis_pl.mjs
- IRIS: /home/irisowner/benchmark_redis_pl.mjs
Here's the results running in on our ARM64 M1 Mac Mini:
root@15b9ed4d53af:/opt/mgateway# node benchmark_redis_pl.mjs
Redis performance test: pipelined
Insert and read back 500,000 key/value pairs using HSET and HGET
Please wait...
-----
finished 500,000 inserts in 1 seconds
rate: 256,016 /sec
------
finished 500,000 gets in 1 seconds
rate: 264,970 /sec
-----------
So this is a definite improvement, but still a small fraction - under 20% - of the performance of YottaDB and IRIS using our mg-dbx-napi interface.
Our conclusion is clear: if you want to achieve a significant improvement in persistent key/value pair storage when using Node.js, you need to think about replacing Redis with YottaDB and IRIS!
IRIS installations include its vendor's own API for accessing the database from Node.js: it's known as the Native Node.js API. If you're already an IRIS user and using this API, you may be interested to know how it compares with our mg-dbx-napi interface.
In fact there's one big difference to be aware of immediately: the Native Node.js API can only make use of a network connection between Node.js and IRIS. This, in itself, is a significant limiting factor when it comes to performance. Whilst our mg-dbx-napi interface can also be configured to use a networked interface, the examples shown above make use of mg-dbx-napi's in-process API connection to IRIS.
You can see for yourself what kind of performance you get by comparison via the Native Node.js API for IRIS: we've included a script that runs the equivalent key/value pair test. You'll see it in the default directory when you shell into the container: iris_native_test.js.
You can run this using Node.js. Here's examples on our two test machines:
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
irisowner@0190429c1c41:~$ node iris_native_test.js 1000000 Platform name: lnxubuntux64 finished 1,000,000 inserts in 52 seconds rate: 19,196 /sec ------ finished 1,000,000 gets in 52 seconds rate: 18,953 /sec
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
irisowner@57adf75db712:~$ node iris_native_test.js 1000000 Platform name: lnxubuntuarm64 finished 1,000,000 inserts in 8 seconds rate: 111,383 /sec ------ finished 1,000,000 gets in 10 seconds rate: 95,584 /sec
You can see that, by comparison with the earlier results for our mg-dbx-napi's API-based interface, the vendor-provided Native Node.js API delivers 10% or less of the performance of mg-dbx-napi when using the exact same database instance on the exact same hardware, and when creating an almost identical set of persistent key/value pairs.
In the YottaDB documentation you will see that for Node.js access there is another interface package available that is known as NodeM. If you're already a YottaDB user and using this interface, you may be interested to know how it compares with our mg-dbx-napi interface.
Both interfaces have much in common: they each allow both network and in-process/API connections to be made between Node.js and YottaDB.
However, you'll find that not only does our mg-dbx-napi interface support Bun.js as well as Node.js, its performance is significantly higher than that of NodeM.
You can see for yourself what kind of performance you get by comparison via NodeM: we've included a script that runs the equivalent key/value pair test. You'll see it in the default directory when you shell into the container: benchmark_nodem.js.
You can run this using Node.js. Here's examples on our two test machines:
-
Processor: X64 - Intel(R) Celeron(R) 2955U @ 1.40GHz with 2 Cores
root@db72cac4c3df:/opt/mgateway# node benchmark_nodem.js 1000000 Node.js Adaptor for YottaDB: Version: 0.20.4 (ABI=115) [FWS]; YottaDB Version: 1.38 Nodem performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 11 seconds rate: 88,167 /sec ------ finished 1000000 gets in 13 seconds rate: 72,421 /sec
-
Processor: ARM64 - Standard M1 Apple Mac Mini with 8 CPU cores
root@15b9ed4d53af:/opt/mgateway# node benchmark_nodem.js 1000000 Node.js Adaptor for YottaDB: Version: 0.20.4 (ABI=115) [FWS]; YottaDB Version: 1.38 Nodem performance test Insert and read back 1000000 key/value pairs Global name used is ^ydbtest Please wait... ----- finished 1000000 inserts in 3 seconds rate: 286,697 /sec ------ finished 1000000 gets in 4 seconds rate: 244,319 /sec
You can see that, by comparison with the earlier results for our mg-dbx-napi's API-based interface, NodeM delivers significantly lower performance than mg-dbx-napi when using the exact same database instance on the exact same hardware, and when creating an almost identical set of persistent key/value pairs.