me
Published on

SurrealDB first look

Authors
  • avatar
    Name
    Omer Atagun
    Twitter

Some developments ( inventions ) gets me excited. Yes, i am not talking about new javascript framework forget those.

What is SurrealDB ?

Well by the promises they have made, it is indeed SurrealDB and its up to us to test it out if those promises are actually true. We will be quick looking the features it promises, then do a basic for loop and force both surrealdb and mariadb to find out differences.

Installation

From their documentation in github repository. I came up with this docker command to fast skip all the setups that we need for testing the environment. So run

docker run --rm --name surrealdb -p 127.0.0.1:8002:8000 surrealdb/surrealdb:latest start --log trace --user root --pass root memory

We will be firing up a surrealdb on port 8002. Instance with memory option rather file this time. We will also test the file, no worries.

Lets get ourselves SDK/driver of surrealdb ( currently on node, deno, rust and golang ) for node.

Install driver via npm

Create a folder and run

npm install --save surrealdb.js
touch app.js

Now open your app.js


const Surreal = require('surrealdb.js');

const db = new Surreal('http://127.0.0.1:8002/rpc');

async function main() {

	try {

		// Signin as a namespace, database, or root user
		await db.signin({
			user: 'root',
			pass: 'root',
		});

		// Select a specific namespace / database
		await db.use('test', 'test');


        const insertRandomPersonGreedy = async () => {
            console.time("dbsave")
            for (let i = 0; i < 10000; i++) {
                await db.create("person", {
                    title: 'Founder & CEO',
                    name: {
                        first: 'Tobie',
                        last: 'Morgan Hitchcock',
                    },
                    marketing: true,
                    identifier: Math.random().toString(36).substr(2, 10),
                });
            }
        }
        await insertRandomPersonGreedy().then(r=>{
            console.timeEnd("dbsave")
        })

        let peeps = await db.select("person");

        console.log(peeps.length)

	} catch (e) {

		console.error('ERROR', e);

	}

}

main();

For the sake of the test, we set our loop to 10.000 records. So in one breath, we do be inserting 10.000 records. Greedy enough.

Run;

node app.js

Outcome

  • My environment at this very moment is
  Chip:	Apple M1 Pro
  Total Number of Cores:	10 (8 performance and 2 efficiency)
  Memory:	16 GB

Result for this instance following

Time elapsed: 7.413s
Record in DB: 10000

Its time to kill our instance, recreate as file driver.

Run;

docker run --rm --name surrealdb -p 127.0.0.1:8002:8000 surrealdb/surrealdb:latest start --log trace --user root --pass root file://.

## output

[2022-09-17 06:43:19] INFO  surrealdb::iam Root authentication is enabled
[2022-09-17 06:43:19] INFO  surrealdb::iam Root username is 'root'
[2022-09-17 06:43:19] INFO  surrealdb::dbs Database strict mode is disabled
[2022-09-17 06:43:19] INFO  surrealdb::kvs Starting kvs store at file://.
[2022-09-17 06:43:19] INFO  surrealdb::kvs Started kvs store at file://.
[2022-09-17 06:43:19] INFO  surrealdb::net Starting web server on 0.0.0.0:8000
[2022-09-17 06:43:19] INFO  surrealdb::net Started web server on 0.0.0.0:8000
[2022-09-17 06:43:20] INFO  surreal::web 172.17.0.1:64468 GET /rpc HTTP/1.1 101 "-" 66.875µs

Run again our app.js so we measure whats the time elapsed;

node app.js
Time elapsed: 7.919s
Record in DB: 10000

Almost no difference at this very moment.

Lets go with node and mariadb

For this test, we use mariadb 10.7 as docker container. To make our life easier, i am giving you compose file so we can quickly set our table and all that stuff which we did not need while using surrealdb :)

create a file in same folder `docker-compose.yaml

version: '2.3'

services:
  mysql:
    restart: always
    image: mariadb:10.7
    container_name: mariadb
    ports:
      - "3307:3306"
    volumes:
      - ./store/:/var/lib/mysql
    mem_limit: 5012m
    networks:
      - mysqlnetwork
    environment:
      - MYSQL_ROOT_PASSWORD=root
      - MYSQL_DATABASE=local
      - MYSQL_USER=root
      - MYSQL_PASSWORD=root
      - PMA_ARBITRARY=1
      - PMA_HOST=mysql
      - PMA_PORT=3306
      - PMA_USER=root
      - PMA_PASSWORD=root

  mysql-admin:
    restart: always
    image: phpmyadmin/phpmyadmin
    container_name: mariadb-phpmyadmin
    ports:
      - "8001:80"
    mem_limit: 5012m
    networks:
      - mysqlnetwork
    depends_on:
      - mysql
    environment:
      PMA_HOST: mysql
      PMA_PORT: 3306
      PMA_USER: root
      PMA_PASSWORD: root
      UPLOAD_LIMIT: 30000M

networks:
  mysqlnetwork:
    driver: bridge

Run;

docker compose up

Wait a while till images are pulled. Then visit http://localhost:8001

  • Create a database named with surreal

  • Create a table named with person

  • PhpMysql by default will ask 4 columns, lets fill them up

id - int - 11 auto_increment (AI)
name- varchar 255
surname - varchar 255
title - varchar 255

click save

Now we can get our node app

Go to the folder where we have app.js and create new file yapp.js

npm install mariadb --save

In our yapp.js

Note: by using same math random, we tried to keep the cost same.

const mariadb = require('mariadb');
const pool = mariadb.createPool({
     host: '127.0.0.1',
     database: 'surreal',
     port: 3307,
     user:'root',
     password: 'root',
});



async function main(){
    const conn = await pool.getConnection()
    try{

        const runGreedyQuery = async () => {
            console.time("dbsave")
            for(let i = 0; i<10000; i++){
                const randomMath = Math.random().toString(36).substr(2, 10)
               await conn.query(`INSERT INTO person (name,surname,title) values ('myname', 'mysurname', '${randomMath}')`);
              }
            }

        await runGreedyQuery().then(r=>{
            console.timeEnd("dbsave")
        })
    }catch(err){
        console.log(err)
    }

}

    main()

Run;

node yapp.js

Output;

Time elapsed: 11.012s
Record in DB: 10000

Second run;

Time elapsed: 9.474s
Record in DB: 20000

Conclusion

There are observable differences in between two insert operations on different databases. Today, under these circumstances SurrealDB won. But that's not just enough to decide whether to go with one.

As we have said, we used same environment yet official images of both might be different. May affect the result. Let's set ourselves a mood of healthy skeptical to figure why we could put ourselves into an adventure by migrating to a new technology.

  • Scaling Mysql or related forks of it as relational databases is hard to scale. We all know that already. To get yourself a single new column, You have to do your updates on database. Hell of a work and potential human errors. On this aspect, key-value storing like SurrealDB is great but not just it like other non-relation databases. SurrealDB provides a lot of features from relation-databases on its way. Some of those are;

Indexing

CREATE company:surrealdb SET name = 'SurrealDB', cofounders = [person:tobie, person:jaime];

This allows for records to be retrieved without any table scans or index scans, solely by the id. Beautiful.

NO JOINS but SurrealJoins :)

  SELECT ->purchased->product<-purchased<-person->(purchased WHERE created_at > time::now() - 3w)->product FROM person:tobie;
  • Transactions.
  • Functions
  • Statements
  • Operators

And many more...

Honestly, i am excited to use it and see all the problems alongside benefits. There are a lot of built-in helpers SurrealDB provides. I belive its worth to take a look at all those promises.

Give your 10 minutes into documentation

SurrealQL

Untill the next post, stay hydrated!