Go语言插入Sqlite3数据库最快的方法

Go语言使用各库插入最快的方法和查询最快的方法见:https://github.com/cvilsmeier/go-sqlite-bench

按照此测评项目,最快的插入方法是使用"github.com/cvilsmeier/sqinn-go/sqinn",通过调用其提供的辅助程序sqinn来进行插入。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
package main

import (
	"fmt"
	"math/rand"
	"time"

	"github.com/cvilsmeier/sqinn-go/sqinn"
)

type User struct {
	ID   int
	Name string
	Sex  string
	Age  int
}

func main() {
	sqinnpath := "path\\of\\sqinn.exe" // 下载地址https://github.com/cvilsmeier/sqinn/releases
	dbname := "mydb.sqlite" // 实际的文件路径

	// 启动 sqinn
	sq := sqinn.MustLaunch(sqinn.Options{
		SqinnPath: sqinnpath,
	})
	defer sq.Terminate()

	// 打开数据库
	sq.MustOpen(dbname)
	defer sq.Close()

	// 创建表
	sq.MustExecOne("CREATE TABLE users (id INTEGER PRIMARY KEY NOT NULL, name VARCHAR, sex VARCHAR, age INT)")

	// 随机生成用户信息
	rand.Seed(time.Now().UnixNano())
	totalRecords := 10000000  // 总用户数
	cols := 4 // 每个用户的参数数量
	Records := make([]any, cols*totalRecords)

	for i := 0; i < totalRecords; i++ {
		id := i + 1
		name := fmt.Sprintf("User%d", id)
		sex := []string{"Male", "Female"}[rand.Intn(2)]
		age := rand.Intn(100) // 0-99 随机年龄
		base := i * cols
		Records[base] = id
		Records[base+1] = name
		Records[base+2] = sex
		Records[base+3] = age
	}
	start := time.Now()
	// 使用事务批量插入数据
	sq.MustExecOne("BEGIN")
	sq.MustExec("INSERT INTO users (id, name, sex, age) VALUES (?, ?, ?, ?)", totalRecords, cols, Records)
	sq.MustExecOne("COMMIT")
	duration := time.Since(start)
	fmt.Println(duration, 10000000/int(duration.Seconds()))
    // i5-12600K 上的输出为:
    // Inser Cost Time: 7.3262848s 
    // Number Per Second: 1250000
    // Number Per Second: 1428571 // 无主键的情况
}

SqinnSQLite C API 的替代方案。 Sqinn 读取来自 stdin 的请求, 将请求转发到 SQLite,并将响应写入 stdout。 它用于不允许调用 C API 函数的编程环境。 SQLite 数据库 是用C语言编写的,提供了在 C/C++ 中使用它的 API,它有许多语言绑定, 如果你不能或不想使用可用的语言绑定之一,并且您的编程语言允许创建子进程(fork/exec),一个选项可能是使用Sqinn通过 stdin/stdoutSQLite 进行通信。

一个例子是 Go :存在一堆 Go 库 用于读取和写入 SQLite 数据库, 他们大多数都使用 cgo 打电话给 SQLite C API 函数, 虽然这很有效(确实非常好),但它也有缺点

  1. 您必须在开发系统上安装 gcc。
  2. cgo 减慢 Go 编译过程。
  3. 交叉编译cgo程序 另一个平台(比如从 Linux 到 MacOS)很难设置。

Sqinn 提供映射到 SQLite 函数的函数,例如 sqlite3_open(), sqlite3_prepare(), sqlite3_bind(), 等等。 如果您还没有阅读 SQLite C/C++ 简介接口 ,现在正是好时机。 花 5 分钟阅读并了解 SQLite 的基本工作原理。

在进程边界之间来回编组请求和响应当然很慢,为了提高性能,Sqinn 提供了一些函数,让您可以在一个请求 / 响应周期中调用多个 SQLite 函数。

所有函数调用和用于编组请求的二进制 IO 协议中描述 响应数据在 io_protocol.md

对于Go语言绑定,请参见 https://github.com/cvilsmeier/sqinn-go , 有关基准测试,请参见 https://github.com/cvilsmeier/sqinn-go-bench

https://turriate.com/articles/making-sqlite-faster-in-go