Skip to content

Terrible insert performance

package main

import (
	"database/sql"
	"fmt"
	"github.com/google/uuid"
	"log"
	_ "github.com/mattn/go-sqlite3"
	_ "modernc.org/sqlite"
	"os"
	"time"
)

func main() {
	const dbName = "test.db"

	if err := os.Remove(dbName); err != nil && !os.IsNotExist(err) {
		log.Fatal(err)
	}

	db, err := sql.Open("sqlite", dbName)

	if err != nil {
		log.Fatal(err)
	}

	defer db.Close()

	sqlText := "create table test(c1 text, c2 text, c3 text)"

	if _, err := db.Exec(sqlText); err != nil {
		log.Fatal(err)
	}

	n := 1000000
	bulkSize := 10_000

	log.Printf("inserting %d records (bulk size = %d)...", n, bulkSize)
	start := time.Now()

	for i := 0; i < n; i += bulkSize {
		log.Printf("bulk #%d/%d...", i/bulkSize, n/bulkSize)

		tx, err := db.Begin()

		if err != nil {
			log.Fatal(err)
		}

		stmt, err := tx.Prepare("insert into test(c1, c2, c3) values (?, ?, ?)")

		if err != nil {
			log.Fatal(err)
		}

		for j := 0; j < bulkSize; j++ {
			c1, _ := uuid.NewRandom()
			c2, _ := uuid.NewRandom()
			c3, _ := uuid.NewRandom()

			_, err = stmt.Exec(c1, c2, c3)

			if err != nil {
				log.Fatal(err)
			}
		}

		if err := stmt.Close(); err != nil {
			log.Fatal(err)
		}

		if err := tx.Commit(); err != nil {
			log.Fatal(err)
		}
	}

	fmt.Println("creating the index...")

	sqlText = `create unique index test__c1_index on test (c1)`

	if _, err := db.Exec(sqlText); err != nil {
		log.Fatal(err)
	}

	log.Printf("done in %v", time.Now().Sub(start))
}

output:

2021/01/08 19:38:35 inserting 1000000 records (bulk size = 10000)...
2021/01/08 19:38:35 bulk #0/100...
2021/01/08 19:38:35 bulk #1/100...
[...skipped...]
2021/01/08 19:39:34 bulk #98/100...
2021/01/08 19:39:35 bulk #99/100...
creating the index...
2021/01/08 19:39:38 done in 1m3.066270399s

Now change the driver name to "sqlite3" and run again:

GOROOT=/Users/vaskir/sdk/go1.15.6 #gosetup
GOPATH=/Users/vaskir/go #gosetup
/Users/vaskir/sdk/go1.15.6/bin/go build -o /private/var/folders/zl/ysbq7y390ts6ydtdzpbpv02m0000gn/T/___go_build_project1_cgofreesqlitetest project1/cgofreesqlitetest #gosetup
/private/var/folders/zl/ysbq7y390ts6ydtdzpbpv02m0000gn/T/___go_build_project1_cgofreesqlitetest #gosetup
2021/01/08 19:41:26 inserting 1000000 records (bulk size = 10000)...
2021/01/08 19:41:26 bulk #0/100...
2021/01/08 19:41:26 bulk #1/100...
[...skipped...]
2021/01/08 19:41:29 bulk #98/100...
2021/01/08 19:41:29 bulk #99/100...
creating the index...
2021/01/08 19:41:30 done in 4.117596388s

So, sqlite3 package is about 15 times faster.

$ go version
go version go1.15.6 darwin/amd64
Edited by Vasily Kirichenko