Redis vs Postgres

Oct 17, 2016 10:31 · 696 words · 4 minutes read Programming Redis Postgres Comparison

Hi guys!

This is a short article about comparing Redis and Postgres in terms of pure performance. The use case: I am writing a Bulgarian rhyming dictionary. I have a dictionary and I want to store it for fast access. In-memory is the obvious choice here, but just for illustrative pruposes I set up a Postgres table to hold these words as well.

The Setup

As part of preparing for a new project, I wanted to play around with in-memory databases. I am currently building a Rhyming dictionary app and was using Postgres as a backend database. My use-case is keeping a list of words in the Bulgarian language, so that I can query them for rhymes. I basically put Redis side-to-side with Postgres in my code, downloading a dictionary from OpenOffice, parsing it, saving it to the database and then requerying the database for all the words contained therein.

All measeurements below are in milliseconds.

Redis vs Postgres

The code we are running is the following

final Jedis jedis = new Jedis("localhost");

final StringBuilder redisRet = new StringBuilder();
final StringBuilder postgresRet = new StringBuilder();

long startTimeGet = System.nanoTime();
IntStream.range(0, 100).forEach(s -> jedis.smembers("words"));
long endTimeGet = System.nanoTime();

long startTimeStream = System.nanoTime();
jedis.smembers("words").stream().forEach(s -> redisRet.append(" ;; " + s));
long endTimeStream = System.nanoTime();

final long redisDurationGet = (endTimeGet - startTimeGet);  //divide by 1000000 to get milliseconds.
final long redisDurationStream = (endTimeStream - startTimeStream);  //divide by 1000000 to get milliseconds.


startTimeGet = System.nanoTime();
IntStream.range(0, 100).forEach(s -> wordRepository.findAll());
endTimeGet = System.nanoTime();

startTimeStream = System.nanoTime();
wordRepository.findAll().stream().forEach(s -> postgresRet.append(" ;; " + s));
endTimeStream = System.nanoTime();

final long dbDurationGet = (endTimeGet - startTimeGet);  //divide by 1000000 to get milliseconds.
final long dbDurationStream = (endTimeStream - startTimeStream);  //divide by 1000000 to get milliseconds.


System.out.println("Pure Redis get took: " + redisDurationGet*1E-8);
System.out.println("Redis get and Java text manipulation took: " + redisDurationStream*1E-6);

System.out.println("Pure Postgres get took: " + dbDurationGet*1E-8);
System.out.println("Postgres get and Java text manipulation took: " + dbDurationStream*1E-6);

System.out.println("Total word count: " + jedis.scard("words"));

jedis.close();

Comparing the database access for both we can get the following on a cold start

Pure Redis get took: 68.270477
Redis get and Java text manipulation took: 42.318915
Pure Postgres get took: 487.195526
Postgres get and Java text manipulation took: 66.469518
Total word count: 21097

on a cold start and for two subsequent calls after that

Pure Redis get took: 27.069855
Redis get and Java text manipulation took: 31.519133
Pure Postgres get took: 162.42595699999998
Postgres get and Java text manipulation took: 50.652564999999996
Total word count: 21097

=======================

Pure Redis get took: 26.985374999999998
Redis get and Java text manipulation took: 53.743337
Pure Postgres get took: 98.381185
Postgres get and Java text manipulation took: 45.024408
Total word count: 21097

As you can see, after the first call, Redis retains a constant access time. Postgres however keeps decreasing its access time as it (probably) caches the data. It levels out at about 45.249686999999994 milliseconds.

Redis keeps itself in the 20-30 miliseconds ballpark over multiple runs.

Also, StringBuilder is really really much faster than using plain strings. We know this from textbooks, however to give you an idea of the order of savings you could get:

Using a simple String

Redis get and Java text manipulation took: 900.9527889999999 (vs ~40 milliseconds)
Postgres get and Java text manipulation took: 775.160843 (vs ~50 milliseconds)

Redis StringSet

Now implementing Redis’ StringSet so not to use keys directly. (The Redis documentation advises the use of StringSet, over getting all keys stored in Redis using jedis.keys("*"))

The performance gains of this approach are… non-existent as it seems. The get operation takes the same amount of time.

BEFORE:

Pure Redis get took: 21.217271
Redis get and Java text manipulation took: 22.844576
Pure Postgres get took: 48.261527
Postgres get and Java text manipulation took: 28.660894
Total word count: 21097

AFTER:

Pure Redis get took: 30.149960999999998
Redis get and Java text manipulation took: 17.239033
Pure Postgres get took: 46.029207
Postgres get and Java text manipulation took: 22.428577
Total word count: 21097

MEAN TIME FOR 100 iterations:

Pure Redis get took: 13.13524347
Redis get and Java text manipulation took: 17.324793
Pure Postgres get took: 20.25542389
Postgres get and Java text manipulation took: 32.368626
Total word count: 21097

Happy coding!

Peace out!