New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

performances vs PgSQL #23061

Closed
Fale opened this Issue Feb 25, 2018 · 5 comments

Comments

Projects
None yet
5 participants
@Fale
Copy link

Fale commented Feb 25, 2018

I've written the following code snippet:

package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	_ "github.com/lib/pq"
)

const (
	iterations = 500
)

type conn struct {
	db   *sql.DB
	name string
}

func main() {
	p := connection("host=127.0.0.1 port=5432 user=fale password=fale sslmode=disable", "PgSQL")
	defer p.db.Close()
	c := connection("host=127.0.0.1 port=26257 user=root sslmode=disable", "CockroachDB")
	defer c.db.Close()

	// Schemas and DB
	p.schema()
	c.database()
	// Table
	p.table()
	c.table()
	// Insert
	p.inserts()
	c.inserts()
	// Select
	p.selects()
	c.selects()
	// Deletes
	p.deletes()
	c.deletes()
}

func connection(dbinfo string, name string) conn {
	var err error
	c := conn{name: name}
	c.db, err = sql.Open("postgres", dbinfo)
	if err != nil {
		log.Fatalln(err)
	}
	return c
}

func (c *conn) schema() {
	log.Printf("# Ensure schema is present - %s", c.name)
	_, err := c.db.Exec("CREATE SCHEMA IF NOT EXISTS test")
	if err != nil {
		log.Fatalln(err)
	}
}

func (c *conn) database() {
	log.Printf("# Ensure database is present - %s", c.name)
	_, err := c.db.Exec("CREATE DATABASE IF NOT EXISTS test")
	if err != nil {
		log.Fatalln(err)
	}
}

func (c *conn) table() {
	log.Printf("# Ensure table is present and empty - %s", c.name)
	_, err := c.db.Exec("CREATE TABLE IF NOT EXISTS test.accounts (id INT PRIMARY KEY, balance DECIMAL);")
	if err != nil {
		log.Fatalln(err)
	}
	_, err = c.db.Exec("TRUNCATE test.accounts;")
	if err != nil {
		log.Fatalln(err)
	}
}

func (c *conn) inserts() {
	exec(c, "inserts", "INSERT INTO test.accounts VALUES(%[1]d,%[1]d);")
}

func (c *conn) selects() {
	exec(c, "selects", "SELECT * FROM test.accounts WHERE id = %d;")
}

func (c *conn) deletes() {
	exec(c, "deletes", "DELETE FROM test.accounts WHERE id = %d;")
}

func exec(c *conn, name string, query string) {
	start := time.Now()

	var i int64
	for i = 0; i < iterations; i++ {
		stmt := fmt.Sprintf(query, i)
		_, err := c.db.Exec(stmt)
		if err != nil {
			panic(err)
		}
	}
	elapsed := time.Since(start)
	log.Printf("%d %s in %s took %s, with an average of %dns/op", i, name, c.name, elapsed, int64(elapsed/time.Nanosecond)/i)
}

I installed PgSQL from my distro (Fedora 27).

$ psql --version
psql (PostgreSQL) 9.6.6

I installed cockroach following https://www.cockroachlabs.com/docs/stable/start-a-local-cluster.html (v1.1.5) and I tried to perform some benchmarks.

2018/02/25 09:25:40 # Ensure schema is present - PgSQL
2018/02/25 09:25:40 # Ensure database is present - CockroachDB
2018/02/25 09:25:40 # Ensure table is present and empty - PgSQL
2018/02/25 09:25:40 # Ensure table is present and empty - CockroachDB
2018/02/25 09:25:42 1000 inserts in PgSQL took 1.287776052s, with an average of 1287776ns/op
2018/02/25 09:25:48 1000 inserts in CockroachDB took 5.860344296s, with an average of 5860344ns/op
2018/02/25 09:25:48 1000 selects in PgSQL took 81.824155ms, with an average of 81824ns/op
2018/02/25 09:25:49 1000 selects in CockroachDB took 933.020106ms, with an average of 933020ns/op
2018/02/25 09:25:50 1000 deletes in PgSQL took 1.325356857s, with an average of 1325356ns/op
2018/02/25 09:25:56 1000 deletes in CockroachDB took 5.810851181s, with an average of 5810851ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ go build && ./pg-benchmark 
2018/02/25 09:30:08 # Ensure schema is present - PgSQL
2018/02/25 09:30:08 # Ensure database is present - CockroachDB
2018/02/25 09:30:08 # Ensure table is present and empty - PgSQL
2018/02/25 09:30:08 # Ensure table is present and empty - CockroachDB
2018/02/25 09:30:09 1000 inserts in PgSQL took 1.31913866s, with an average of 1319138ns/op
2018/02/25 09:30:15 1000 inserts in CockroachDB took 5.720786054s, with an average of 5720786ns/op
2018/02/25 09:30:15 1000 selects in PgSQL took 78.829973ms, with an average of 78829ns/op
2018/02/25 09:30:16 1000 selects in CockroachDB took 878.112876ms, with an average of 878112ns/op
2018/02/25 09:30:18 1000 delete in PgSQL took 2.113067103s, with an average of 2113067ns/op
2018/02/25 09:30:23 1000 delete in CockroachDB took 5.10793473s, with an average of 5107934ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ go build && ./pg-benchmark 
2018/02/25 09:36:20 # Ensure schema is present - PgSQL
2018/02/25 09:36:20 # Ensure database is present - CockroachDB
2018/02/25 09:36:20 # Ensure table is present and empty - PgSQL
2018/02/25 09:36:20 # Ensure table is present and empty - CockroachDB
2018/02/25 09:36:21 500 inserts in PgSQL took 645.701328ms, with an average of 1291402ns/op
2018/02/25 09:36:24 500 inserts in CockroachDB took 3.277119748s, with an average of 6554239ns/op
2018/02/25 09:36:25 500 selects in PgSQL took 42.114179ms, with an average of 84228ns/op
2018/02/25 09:36:25 500 selects in CockroachDB took 422.683737ms, with an average of 845367ns/op
2018/02/25 09:36:26 500 deletes in PgSQL took 650.923468ms, with an average of 1301846ns/op
2018/02/25 09:36:28 500 deletes in CockroachDB took 2.545088971s, with an average of 5090177ns/op

I then tried to change the cockroach execution by adding --cache=25% --max-sql-memory=25% to every instance but the results are better but still very far from pgsql ones:

fale@x250:~/go/src/github.com/fale/pg-benchmark $ go build && ./pg-benchmark 
2018/02/25 09:47:22 # Ensure schema is present - PgSQL
2018/02/25 09:47:22 # Ensure database is present - CockroachDB
2018/02/25 09:47:22 # Ensure table is present and empty - PgSQL
2018/02/25 09:47:22 # Ensure table is present and empty - CockroachDB
2018/02/25 09:47:50 500 inserts in PgSQL took 750.454098ms, with an average of 1500908ns/op
2018/02/25 09:47:53 500 inserts in CockroachDB took 2.250529374s, with an average of 4501058ns/op
2018/02/25 09:47:53 500 selects in PgSQL took 61.181155ms, with an average of 122362ns/op
2018/02/25 09:47:53 500 selects in CockroachDB took 190.542076ms, with an average of 381084ns/op
2018/02/25 09:47:54 500 deletes in PgSQL took 686.743754ms, with an average of 1373487ns/op
2018/02/25 09:47:57 500 deletes in CockroachDB took 3.095964455s, with an average of 6191928ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ go build && ./pg-benchmark 
2018/02/25 09:48:16 # Ensure schema is present - PgSQL
2018/02/25 09:48:16 # Ensure database is present - CockroachDB
2018/02/25 09:48:16 # Ensure table is present and empty - PgSQL
2018/02/25 09:48:16 # Ensure table is present and empty - CockroachDB
2018/02/25 09:48:17 500 inserts in PgSQL took 650.64161ms, with an average of 1301283ns/op
2018/02/25 09:48:20 500 inserts in CockroachDB took 3.058602056s, with an average of 6117204ns/op
2018/02/25 09:48:20 500 selects in PgSQL took 42.282658ms, with an average of 84565ns/op
2018/02/25 09:48:21 500 selects in CockroachDB took 175.840808ms, with an average of 351681ns/op
2018/02/25 09:48:21 500 deletes in PgSQL took 662.712318ms, with an average of 1325424ns/op
2018/02/25 09:48:23 500 deletes in CockroachDB took 2.2847881s, with an average of 4569576ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ go build && ./pg-benchmark 
2018/02/25 09:48:39 # Ensure schema is present - PgSQL
2018/02/25 09:48:39 # Ensure database is present - CockroachDB
2018/02/25 09:48:39 # Ensure table is present and empty - PgSQL
2018/02/25 09:48:39 # Ensure table is present and empty - CockroachDB
2018/02/25 09:48:40 500 inserts in PgSQL took 662.140623ms, with an average of 1324281ns/op
2018/02/25 09:48:43 500 inserts in CockroachDB took 3.056347724s, with an average of 6112695ns/op
2018/02/25 09:48:43 500 selects in PgSQL took 48.732729ms, with an average of 97465ns/op
2018/02/25 09:48:43 500 selects in CockroachDB took 185.466359ms, with an average of 370932ns/op
2018/02/25 09:48:44 500 deletes in PgSQL took 655.312292ms, with an average of 1310624ns/op
2018/02/25 09:48:46 500 deletes in CockroachDB took 2.282639324s, with an average of 4565278ns/op

Surely my test is not a perfect match with a real workload (I write first, read second, delete third without mixed ops, for instance), also I would expect some kind of performance differences (since cockroach is distributed/multinode) mainly on inserts/deletes, but I was not expecting such performance gap. I wonder if I did something that makes the test "wrong" or if this performance gap is known and is probably the same I could expect on a real workload.

@knz

This comment has been minimized.

Copy link
Member

knz commented Feb 25, 2018

Hi @Fale!

Thanks for your interest in CockroachDB.
With version 1.1 your numbers are not completely surprising as that release was not focused on performance. Several of the limitations you observe are being lifted in the upcoming 2.0 release and the one after that (2.1).

Meanwhile, you are doing two 'something that make the test "wrong"':

  • running a performance test with 3 cockroach nodes running on the same computer is nonsensical. You're essentially dividing the performance of your computer by 3, plus adding overhead of process scheduling between the instances.
  • comparing a single node postgres cluster with a 3-node cockroach cluster. to make a fair comparison you need to use either a 3-node postgres cluster or a single node cockroach

Finally, note the following:

  • you are running all the queries over a single client connection. This is not the mode of operation that cockroachdb is optimized for. Instead we recommend benchmark tests that issue queries over many client connections simultaneously. (ideally, simulatenously over multiple nodes in a cluster, spread over multiple servers. Again to be fair, relative to the point above, to be fair you'd compare that against the same with postgres)
  • your insert statements use identifiers for the primary key that are very close to each other. This is bound to cause some moderate contention on the range holding the table's data. Again CockroachDB is not well optimized for this case. But it's also not a very realistic workload -- in a real-world app we'd recommend the primary keys to be more randomly distributed (e.g. using our SERIAL type), which would yield better write distribution and less contention.
@Fale

This comment has been minimized.

Copy link

Fale commented Feb 25, 2018

Thanks :).

I've done more benchmarks, using version 2.0-alpha.20180212:

The first one still with the three nodes on the same machine:

fale@x250:~/go/src/github.com/fale/pg-benchmark $ ./pg-benchmark 
2018/02/25 18:59:42 # Ensure schema is present - PgSQL
2018/02/25 18:59:42 # Ensure database is present - CockroachDB
2018/02/25 18:59:42 # Ensure table is present and empty - PgSQL
2018/02/25 18:59:42 # Ensure table is present and empty - CockroachDB
2018/02/25 18:59:43 500 inserts in PgSQL took 665.159742ms, with an average of 1330319ns/op
2018/02/25 18:59:45 500 inserts in CockroachDB took 2.444064827s, with an average of 4888129ns/op
2018/02/25 18:59:45 500 selects in PgSQL took 65.529611ms, with an average of 131059ns/op
2018/02/25 18:59:45 500 selects in CockroachDB took 219.302259ms, with an average of 438604ns/op
2018/02/25 18:59:46 500 deletes in PgSQL took 651.94164ms, with an average of 1303883ns/op
2018/02/25 18:59:48 500 deletes in CockroachDB took 2.407759236s, with an average of 4815518ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ ./pg-benchmark 
2018/02/25 19:00:24 # Ensure schema is present - PgSQL
2018/02/25 19:00:24 # Ensure database is present - CockroachDB
2018/02/25 19:00:24 # Ensure table is present and empty - PgSQL
2018/02/25 19:00:24 # Ensure table is present and empty - CockroachDB
2018/02/25 19:00:24 500 inserts in PgSQL took 676.834742ms, with an average of 1353669ns/op
2018/02/25 19:00:27 500 inserts in CockroachDB took 2.516174991s, with an average of 5032349ns/op
2018/02/25 19:00:27 500 selects in PgSQL took 48.130063ms, with an average of 96260ns/op
2018/02/25 19:00:27 500 selects in CockroachDB took 227.892005ms, with an average of 455784ns/op
2018/02/25 19:00:28 500 deletes in PgSQL took 661.885943ms, with an average of 1323771ns/op
2018/02/25 19:00:30 500 deletes in CockroachDB took 2.494310242s, with an average of 4988620ns/op

Speed is very similar to version 1.1.5, at least in those tests.

Then I moved to a single node cluster and I got:

@x250:~/go/src/github.com/fale/pg-benchmark $ ./pg-benchmark 
2018/02/25 19:09:06 # Ensure schema is present - PgSQL
2018/02/25 19:09:06 # Ensure database is present - CockroachDB
2018/02/25 19:09:06 # Ensure table is present and empty - PgSQL
2018/02/25 19:09:06 # Ensure table is present and empty - CockroachDB
2018/02/25 19:09:06 500 inserts in PgSQL took 646.523211ms, with an average of 1293046ns/op
2018/02/25 19:09:08 500 inserts in CockroachDB took 1.547001224s, with an average of 3094002ns/op
2018/02/25 19:09:08 500 selects in PgSQL took 51.706685ms, with an average of 103413ns/op
2018/02/25 19:09:08 500 selects in CockroachDB took 151.971039ms, with an average of 303942ns/op
2018/02/25 19:09:09 500 deletes in PgSQL took 668.726909ms, with an average of 1337453ns/op
2018/02/25 19:09:10 500 deletes in CockroachDB took 1.646481992s, with an average of 3292963ns/op
fale@x250:~/go/src/github.com/fale/pg-benchmark $ ./pg-benchmark 
2018/02/25 19:15:07 # Ensure schema is present - PgSQL
2018/02/25 19:15:07 # Ensure database is present - CockroachDB
2018/02/25 19:15:07 # Ensure table is present and empty - PgSQL
2018/02/25 19:15:07 # Ensure table is present and empty - CockroachDB
2018/02/25 19:15:08 500 inserts in PgSQL took 652.285039ms, with an average of 1304570ns/op
2018/02/25 19:15:10 500 inserts in CockroachDB took 1.585498223s, with an average of 3170996ns/op
2018/02/25 19:15:10 500 selects in PgSQL took 53.059632ms, with an average of 106119ns/op
2018/02/25 19:15:10 500 selects in CockroachDB took 135.993407ms, with an average of 271986ns/op
2018/02/25 19:15:10 500 deletes in PgSQL took 675.890494ms, with an average of 1351780ns/op
2018/02/25 19:15:12 500 deletes in CockroachDB took 1.776926316s, with an average of 3553852ns/op

Performances are better, but stil 2.5~3x PgSQL.
I'll try in the next few days to expand the tests to accommodate your comments :)

@arjunravinarayan

This comment has been minimized.

Copy link
Collaborator

arjunravinarayan commented Feb 26, 2018

Hi @Fale, one thing you might want to try is parallelizing your requests over multiple client connections. One thing that we do know is that we have worse latencies that PG, but are able to keep up in throughput. In this setup, the higher latencies are causing a throughput decrease as well.

@Wulfklaue

This comment has been minimized.

Copy link

Wulfklaue commented Mar 1, 2018

@Fale

Those results are not surprising...

Your comparing a database ( PostgreSQL) that has had 21 years of development and is highly optimized for single system performance. If you go back 8 years in time, PostgreSQL lost hard to even MySql in every benchmark. They did a great job at fixing postgresql its performance issues.

Compare this to CockroachDB that is barely 3 year old. And has a totally different design philosophy.

CockroachDB is power is not speed. Its the ability to get a replicating, sharding database up and running with minimal effort. CockroachDB has lots of nifty features. Its the same reason why a lot of people started using PostgreSQL in the past. Because PostgreSQL was able to do things, that Mysql did not do ( or did not follow the standards ).

I doubt that CockroachDB will ever get the same performance in single system performance compared to PostgreSQL / Mysql. The real gain is again the ability to easily scale with more databases horizontally and still have a secure system for your data.

Try clustering on PostgreSQL vs CockroachDB and your results will be much more interesting. That is after you spend a few hours setting up clustering on PostgreSQL. Watch what happens when a PostgreSQL master or a slave drops. Or try having Master - Master on PostgreSQL. 👎

Think of it like this: What is more valuable. The money you spend on a extra server or the money you spend on a database engineer. The extra server is maybe 100 a 200$ per month, where as the database engineer is going to be way more.

If your planning on running a single server website, then stick with MySQL / PostgreSQL / ... as they are heavily optimized the last 20 years for that task. If your goal is to expand your hosting horizontally, then MySQL / PostgreSQL / ... are really not the best choice.

@knz knz added the C-performance label Apr 24, 2018

@knz knz added this to Backlog in SQL execution via automation Apr 24, 2018

@jordanlewis jordanlewis removed this from Backlog in SQL execution May 24, 2018

@tim-o

This comment has been minimized.

Copy link
Contributor

tim-o commented May 24, 2018

@Fale, thanks for bringing this to our attention, and thanks to @wuflklaue for the context and recommendation! @Fale, there are some recommendations above that could be used to improve the test case:

If you have access to AWS, you could also follow our example of deploying a test cluster (https://www.cockroachlabs.com/docs/stable/deploy-a-test-cluster.html). This is closer to a true deployment of CRDB, with multiple nodes running on multiple machines.

Wulfklaue's summary of the relative benefits of CRDB vs. Postgres is on the money. That said, we're continuously looking to improve performance on specific queries, so if you have some real life examples where CRDB is not performant, feel free to let us know. In the meantime, I'll mark this as "closed - will not fix".

@tim-o tim-o closed this May 24, 2018

@tim-o tim-o added the X-wontfix label May 24, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment