UPDATE: The test methodology is flawed! PostgreSQL can be faster than nodejs. See the follow-up article.
Jonathan New wrote an interesting article on UUID creation in Postgres vs Node. In it, he described the performance tradeoff of generating a UUID in the database vs in the application. It's not very long, go read it!
I've used PostgreSQL to generate UUIDs before, but I hadn't seen the function
uuid_generate_v4()
. It turns out to come from the uuid-ossp
extension, which
also supports other UUID generation methods. Previously, I've used the
pgcrypto extension,
which provides the gen_random_uuid()
function.
How do they compare? On my machine, using the PostgreSQL package for Ubuntu (as opposed to the Ubuntu package for PostgreSQL...), the pgcrypto version is more than twice as fast than the uuid-ossp version.
How does this compare with nodejs? Using Jonathan's approach, nodejs is about 1.5 times as fast as PostgreSQL with pgcrypto!
uuid-ossp | pgcrypto | nodejs |
---|---|---|
10942.376 ms | 4173.924 ms | 2886.117 ms |
11235.807 ms | 4341.270 ms | 2822.078 ms |
10764.468 ms | 4265.632 ms | 2829.395 ms |
What does this mean? I argue: very little! The slowest method takes ~11 seconds to generate one million UUIDs, and the fastest takes ~3 seconds. That's 3 - 11 microseconds per UUID! If this is the bottleneck in your application, I think you've done a very good job of optimizing - and you might have a pretty unusual use case.
PS: the RETURNING
clause, not
mentioned in Jonathan's post, is really cool:
> CREATE TABLE example (
example_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
number INTEGER NOT NULL
);
CREATE TABLE
> INSERT INTO example (number)
VALUES (1)
RETURNING example_id;
example_id
--------------------------------------
045857b4-6125-4746-94b8-a2e58f342b86
(1 row)
INSERT 0 1
Methodology
This was a very unscientific benchmark! I'm not controlling for other programs running on my machine, and this is not a server, it's just a laptop.
In the interest of writing things down, here's how I came up with the numbers above.
Environment
According to /proc/cpuinfo
, I am running on a Intel(R) Core(TM) i7-3520M CPU
@ 2.90GHz. My operating system is Ubuntu 16.04.2.
> select version();
PostgreSQL 9.6.2 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu 5.3.1-14ubuntu2) 5.3.1 20160413, 64-bit
$ nodejs --version
v6.10.2
Tests
nodejs
$ cd /tmp
$ npm install uuid
/tmp
└── uuid@3.0.1
$ nodejs
const uuidV4 = require('uuid/v4');
test = function() {
console.time("uuid");
for (let i=0; i < 1000000; ++i) {
uuidV4();
}
console.timeEnd("uuid");
}
test()
test()
test()
pgcrypto
CREATE EXTENSION pgcrypto;
CREATE FUNCTION loop_gen_random_uuid() RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
FOR i IN 0..1000000 LOOP
PERFORM gen_random_uuid();
END LOOP;
RETURN;
END;
$$;
\timing on
SELECT loop_gen_random_uuid();
SELECT loop_gen_random_uuid();
SELECT loop_gen_random_uuid();
uuid-ossp
CREATE EXTENSION "uuid-ossp";
CREATE FUNCTION loop_uuid_generate_v4() RETURNS void
LANGUAGE plpgsql
AS $$
BEGIN
FOR i IN 0..1000000 LOOP
PERFORM uuid_generate_v4();
END LOOP;
RETURN;
END;
$$;
\timing on
SELECT loop_uuid_generate_v4();
SELECT loop_uuid_generate_v4();
SELECT loop_uuid_generate_v4();
Background on uuid-ossp
The uuid-ossp
extension
builds
upon some underlying library: libc
on BSDs, libuuid
from e2fs, or ossp
,
the original library from which the extension takes its name. It appears that
Postgres.app uses libuuid
, according to its
Makefile
(note the --with-uuid=e2fs
). The PostgreSQL package for
Ubuntu (as opposed to the Ubuntu
package for PostgreSQL...) uses
the same library:
$ ldd /usr/lib/postgresql/9.6/lib/uuid-ossp.so | grep uuid
libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007fa4de773000)
So, I think Jonathan and I are using the same underlying library, and while we have different machines, I think this is a reasonably apples-to-apples comparison.