SQLite DB
2026-08-26
在 Dr. Raphael A. Bauer 发表《PostgreSQL for Everything》之后,JoeCode 发表了一篇《SQLite for Everything》调侃式回应(作者强调自己同样喜欢 PostgreSQL,但认为 SQLite 被严重低估)。
参考:PostgreSQL 适用一切场景
作者的核心观点:很多团队为了"看起来像生产系统"而引入的一整排基础设施(搜索、队列、缓存、向量库、图库、微服务……),在大多数项目里其实一个 SQLite 单文件就能顶替。
开发新项目的时候,先判断"它能跑在单机+单文件上吗"——能就先上 SQLite,真撞到写并发或分布式天花板再换重的。大多数业务比开发者以为的更晚才会撞墙,而期间你省掉的是大量运维工作。
SQLite 三大底层优势
- 坚如磐石:2000 年发布,公有领域(public domain,不是普通开源),MC/DC 100% 分支覆盖、测试代码是库代码的约 500 倍,官方支持承诺到 2050 年;手机/浏览器/汽车/飞机里都在跑,部署量超过其他数据库总和。
- 零运行成本:没有 daemon、没有端口、没有 Docker。已绑定在 Linux/Python/Go/Rust/.NET/Android/iOS 里;测试用
:memory: 微秒级拉起,和生产同库同二进制。
- 极大简化 IT 拓扑:它不止是 RDBMS,还能当全文搜索引擎、文档库、队列、时序库、向量索引、缓存、文件格式、图存储——"少装一个服务"就是少一个要监控/升级/背锅的系统。
"SQLite 替代 X" 对照表
| 原本的组件 |
SQLite 怎么顶 |
关键机制 |
| Solr / Elastic |
全文搜索 |
FTS5(BM25、短语、NEAR、高亮),索引与数据同事务,不会"索引是旧的" |
| MongoDB |
JSON 文档存 |
jsonb、生成列、严格表 |
| Kafka / RabbitMQ |
任务队列 |
一张表 + BEGIN IMMEDIATE + UPDATE…RETURNING 抢单条作业,WAL 下读写不互锁 |
| ClickHouse |
时序数据 |
按时间分区单文件,中等体量够用 |
| 向量数据库 |
AI 检索 |
sqlite-vec 扩展做 embedding 相似度 |
| Redis |
非持久/高性能缓存 |
进程内点查 ~1µs,比 localhost 跑 Redis 的 ~100µs 快约 100 倍 |
| 文件系统 |
存小文件/BLOB |
官方基准:<100KB blob 比裸文件系统更快、省空间 |
| 图数据库 |
关系遍历 |
递归 CTE |
| 微服务 |
跨函数调用 |
直接同进程函数调用 + 本地事务 |
| (彩蛋)PlayStation 5 |
— |
纯玩笑章节 |
SQLite 的天花板
- 不支持并发写入:高并发写入(每秒几万条以上)会卡在写锁;多机多写、跨机房分布式写不适合原生 SQLite。
- 规模边界:超 TB 级数据、百万点/秒时序、需要用户/角色级 ACL 的多租户 SaaS,应换 Postgres/MySQL/ClickHouse 等。
- 扩展方案:Litestream(WAL 流式备份到 S3)、LiteFS(分布式读)、Turso / Cloudflare D1 / rqlite(托管 SQLite)可缓解部分限制,但不改变单写本质。
PostgreSQL DB
2026-08-26
这篇文章(Dr. Raphael A. Bauer 的《PostgreSQL for Everything》)的核心论点是:PostgreSQL 不是万能答案,但能覆盖你想象中多得多的场景;在中小规模下,先用 PG 统一数据层,遇到真实瓶颈再换专用系统,是更省维护成本、更快交付的架构选择。
PostgreSQL 凭借“老牌稳定 + 现代特性 + 插件生态”,在初创和中型业务里可以一个数据库顶住搜索、文档、队列、时序、向量、缓存、层级数据等多套中间件;它的真正价值不是性能碾压专用库,而是用更低的运维与认知成本,让你把时间花在业务功能上。
一、为什么选 PostgreSQL:三个底层优势
- 成熟且持续进化:1996 年至今,bug 被长期打磨;社区向后兼容地加现代特性(CTE、分区、JSONB、逻辑复制等)。
- 部署与生态极简:本地 brew/apt/docker、Testcontainers 测生产一致性、云厂商一键托管,维护成本极低。
- 可扩展性强:原生能力 + 插件(TimescaleDB、pgvector、pgai、LTREE 等)把多种数据模型收进同一个 ACID 库。
二、PG 能“单库替多中间件”的场景清单
作者用自己 CTO 生涯的实战说明,以下场景不必急着引入专用组件:
| 原本的专用系统 |
PostgreSQL 方案 |
关键机制 |
| MySQL + Lucene/Solr |
原生全文检索 |
tsvector + GIN 索引(Contentful、Instacart 实践) |
| MongoDB |
文档存储 |
jsonb + GIN,支持 JSONPath 查询 |
| Kafka / RabbitMQ / SQS |
表即队列 |
FOR UPDATE SKIP LOCKED、递归/游标消费,先 PG 后换 MQ |
| ClickHouse / InfluxDB |
时序数据 |
TimescaleDB 超表 + 连续聚合 |
| Pinecone / 专用向量库 |
向量检索 |
pgvector,pgai 做 embedding 同步与 RAG |
| Redis 缓存 |
内存级缓存 |
UNLOGGED 表 + 触发器模拟 TTL,多数用例够快 |
| 文件系统存小二进制 |
Blob 列 |
Flatbuffers 序列化入 bytea,缓存策略下比裸文件 IO 更快 |
| 树形/层级数据 |
LTREE 类型 |
比递归 CTE 更易维护 |
| 微服务中间层 |
直接出 JSON |
查询里拼 JSON 返回,省一层应用中间层 |
作者强调:这些都是“先 PG 起步”的策略,不是否认专用系统——当吞吐/并发/规模真正打满时,再切 Kafka、ClickHouse、Redis 不迟。
三、架构哲学:用“无聊”换速度
- 少零件 = 少同步 = 少漂移:避免 ES 与 PG 双写、Mongo 与 PG 对账这类管道腐烂。
- 团队认知负担下降:一套 SQL 技能覆盖关系、文档、搜索、队列、时序、向量。
- 决策顺序建议:新需求来了先问“PG 能不能做”→ 能做就用 → 压测出真实瓶颈再引入新技术,而不是反过来为“技术新鲜感”买单。
这篇文章带来很好的启发:PostgreSQL拥有多模型存储能力,原生支持文档(jsonb)、轻量缓存、全文检索、向量检索、队列表等场景。在不少业务场景下,可以优先基于PG实现相关能力,避免盲目引入新的中间件,降低系统复杂度。
但我不认同将其作为一套可直接落地的生产级通用方案,存在明显边界约束(架构收敛不能牺牲稳定性):
- 把缓存、海量文档等旁路能力并入同一套业务主库,存在严重稳定性风险。
业务主库承载核心交易、用户等核心数据,属于不可丢失的Source of Truth。缓存、高频半结构化读写具备流量大、允许降级、可丢失的特征,二者共用数据库会造成资源互相抢占、故障域合并;缓存流量抖动、jsonb频繁更新引发的膨胀与IO压力,会直接拖慢核心业务SQL,极端场景导致全站故障。
- 如果为了替代Redis、MongoDB等而新部署一套PostgreSQL,无法降低架构成本,反而是牺牲性能、增加运维负担。
新增独立PG集群会带来额外的机器、运维、监控、高可用成本,相比直接引入轻量专用组件,总体成本更高,违背“简化架构”初衷。
适用场景:
- 新项目、初创项目、MVP阶段:快速迭代优先,减少中间件维护成本,等业务出现真实瓶颈后再拆分专用组件;
- 内部系统、后台管理平台、低频运营系统:无C端高并发压力,可用性要求适中;
- 边缘业务、工具类、小型独立服务:规模有限,无需搭建复杂中间件体系。
DB MySQL PostgreSQL
2026-01-19
DB
2025-05-22
DB 开发工具 macOS
2024-06-24
今天,办公电脑出了故障(电源坏了),我切换到 MacBook 工作。
用了很多年的 HeidiSQL 没有 Mac 版本,只能用跨平台的 DBeaver 社区版了。
brew install --cask dbeaver-community
-
安装目录:
Windows: C:\Users\nosch\AppData\Local\DBeaver
MacOS: /Applications/DBeaver.app/
-
配置文件目录:
Windows: C:\Users\nosch\AppData\Roaming\DBeaverData
Ubuntu: ~/snap/dbeaver-ce/current/.local/share/DBeaverData
MacOS: ~/Library/Application Support/DBeaverData
$ tree -a
.
├── .workspaces
├── drivers // 驱动相关,忽略
├── secure
│ └── secure_storage
├── settings
│ └── global-settings.ini
└── workspace6
├── .metadata // 忽略
└── General
├── .dbeaver
│ ├── credentials-config.json
│ ├── data-sources.json
│ └── project-settings.json
├── .project
└── .settings
└── org.eclipse.core.resources.prefs
PS: 默认给我创建的工作区叫做:workspace6
PS:用户配置在 workspace6/General/.dbeaver/ 目录,连接信息在 data-sources.json 中,但是密码是加密的,保存在 credentials-config.json 中。
-
创建第一个 MySQL 数据库连接时,需要下载 MySQL 驱动。
DBeaver 支持几十种不同的库,包括 NoSQL,例如 MongoDB 和 Redis,不过 NoSQL 功能需要付费,每个月几十刀。
从 HeidiSQL 导出配置文件到 DBeaver
我之前有一个脚本导出 HeidiSQL 数据库配置到 JSON 文件中。
这次直接写一个脚本来从 JSON 同步到 DBeaver 配置文件。
配置文件同步
ln -sf ~/Documents/Mine/Sync/DBeaver ~/Library/DBeaverData/workspace6/General
DB MySQL
2023-04-01
sort limit 中有一个相同 sort 项随机选择的逻辑,比如:
我们 sort 之后得到的结果是 a, b, c, d
加上 limit 3 之后,可能返回的是 b, a, d(a、b 的排序列相同,c、d 的排序列相同)
和预期的不一定是吻合的,这个可能需要注意一下。
官方文档的描述:
If you combine LIMIT row_count with ORDER BY, MySQL stops sorting as soon as it has found the first row_count rows of the sorted result, rather than sorting the entire result.
如果将 LIMIT row_count 和 ORDER BY 结合使用,MySQL 会在找到排序结果的前 row_count 行后立即停止排序,而不是对整个结果进行排序。
CREATE TABLE `testSortLimit` (
`id` INT(10) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`sort` INT(10) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`) USING BTREE
)
ENGINE=InnoDB;
INSERT INTO testSortLimit (name, sort) VALUES
("aaa", 0), ("eee", 1), ("iii", 1), ("mmm", 1),
("bbb", 0), ("fff", 1), ("jjj", 1), ("nnn", 1),
("ccc", 0), ("ggg", 1), ("kkk", 1), ("ooo", 1),
("ddd", 0), ("hhh", 1), ("lll", 1), ("ppp", 1);
SELECT * FROM testSortLimit;
SELECT * FROM testSortLimit ORDER BY sort ASC;
SELECT * FROM testSortLimit ORDER BY sort ASC LIMIT 6;
| id |
name |
sort |
| 1 |
aaa |
0 |
| 5 |
bbb |
0 |
| 9 |
ccc |
0 |
| 13 |
ddd |
0 |
| 2 |
eee |
1 |
| 3 |
iii |
1 |
| 4 |
mmm |
1 |
| 6 |
fff |
1 |
| 7 |
jjj |
1 |
| 8 |
nnn |
1 |
| 10 |
ggg |
1 |
| 11 |
kkk |
1 |
| 12 |
ooo |
1 |
| 14 |
hhh |
1 |
| 15 |
lll |
1 |
| 16 |
ppp |
1 |
| id |
name |
sort |
| 5 |
bbb |
0 |
| 9 |
ccc |
0 |
| 13 |
ddd |
0 |
| 1 |
aaa |
0 |
| 12 |
ooo |
1 |
| 11 |
kkk |
1 |
参考资料与拓展阅读
DB
2022-06-13
之前的 KeyDB 宣称是 Redis 的 5 倍性能,这次可好,DragonflyDB 说是 25 倍。
相对于 Redis 服务,主要的改进是自带集群,可以利用多核,接口层面完全兼容 Redis (还支持 Memcached API,只是默认关闭)。
而 Redis 需要利用好多核就必须要有丰富的经验、额外的配置,以及更复杂的集群管理。
所以我觉得这个 DragonflyDB 是非常有意义的。
https://github.com/dragonflydb/dragonfly
https://dragonflydb.io/
docker run --network=host --ulimit memlock=-1 docker.dragonflydb.io/dragonflydb/dragonfly
https://zhuanlan.zhihu.com/p/554409312
是什么让Redis“气急败坏”回击:13年来,总有人想替Redis换套新架构
DB
2022-02-15
https://db-engines.com/en/ranking
https://db-engines.com/en/ranking_trend
关系型 Relational
https://db-engines.com/en/ranking/relational+dbms
- Oracle
- Microsoft SQL Server
- IBM Db2
- Microsoft Azure SQL Database,应该就是 SQL Server 的云版
- Snowflake
- Microsoft Access
- FileMaker 类似 Access 的数据库产品
这几种大型商用数据库就不提了,除了 Access 和 SQL Server 稍微熟悉一点点之外,其他几个碰都没碰过。
开源:
- MySQL
- PostgreSQL
- MariaDB 排 RDBMS 第 8 名
- Percona Server for MySQL 排 RDBMS 第 56 名
- SQLite
- Firebird
文档型 Document
MongoDB 遥遥领先。
键值型 Key-Value
- Redis
- Memcached
- etcd
搜索引擎 Search Engine
排除两个商业服务 Splunk, Algolia。
- Elasticsearch
- Apache Solr
- Sphinx
Elasticsearch 和 Solr 都基于 Apache Lucene
列式存储 Wide Column
熟悉的 RDB 基本上都是行式存储。
Cassandra 遥遥领先, 第二是 HBase。
图 Graph
- Neo4j
- Microsoft Azure Cosmos DB
时序型 Time Series
- InfluxDB
- Kdb+
- Prometheus
- Graphite
- TimescaleDB
- Apache Druid
- RRDtool
- OpenTSDB
参考资料与拓展阅读
DB 设计规范 编码风格
2021-09-18
随手写的,以命名为主(原来想写的是命名规范,结果写超了纲)。
Golang DB MySQL
2021-06-04
测试表:
CREATE TABLE `users` (
`id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_unicode_ci',
`password` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_unicode_ci',
`nickname` VARCHAR(50) NOT NULL COLLATE 'utf8mb4_unicode_ci',
`email` VARCHAR(100) NOT NULL DEFAULT '' COLLATE 'utf8mb4_unicode_ci',
`birthday` VARCHAR(10) NOT NULL DEFAULT '0000-00-00' COLLATE 'utf8mb4_unicode_ci',
`age` TINYINT(3) UNSIGNED NOT NULL DEFAULT '0',
`level` TINYINT(3) NOT NULL DEFAULT '0',
`disabled` TINYINT(1) NOT NULL DEFAULT '0',
`created_at` DATETIME NOT NULL DEFAULT current_timestamp(),
`updated_at` DATETIME NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `username` (`username`) USING BTREE
)
COLLATE='utf8mb4_unicode_ci'
ENGINE=InnoDB;
连接
package main
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql"
)
var db *sql.DB //全局变量client
func initMySQL() (err error) {
dsn := "root:123456@tcp(127.0.0.1:3306)/test"
db, err = sql.Open("mysql", dsn)
if err != nil {
panic(err)
}
err = db.Ping() //检测是否连接成功
if err != nil {
return
}
db.SetMaxOpenConns(200) //最大连接数
db.SetMaxIdleConns(10) //连接池里最大空闲连接数。必须要比maxOpenConns小
db.SetConnMaxLifetime(time.Second * 10) //最大存活保持时间
db.SetConnMaxIdleTime(time.Second * 10) //最大空闲保持时间
return
}
func main() {
if err := initMySQL(); err != nil {
fmt.Printf("connect to db failed,err:%v\n", err)
} else {
fmt.Println("connect to db success")
}
sqlStr := "SELECT id, name FROM sys_user WHERE id=?"
var u user
//非常重要:确保QueryRow之后调用Scan方法,否则持有的数据库链接不会被释放
err := db.QueryRow(sqlStr, 1).Scan(&u.id, &u.name)
if err != nil {
fmt.Printf("scan failed, err: %v\n", err)
return
}
fmt.Printf("id:%d,name:%s,age:%d\n", u.id, u.name)
defer db.Close()
}
//user结构体
type user struct {
id int
name string
}
Insert 增
Update 改
Delete 删
Select 查