一、先搞懂底层架构:性能差异的根源
性能的核心差异,本质是架构设计目标的不同:
| 维度 | SQLite | MySQL |
|---|---|---|
| 架构类型 | 嵌入式数据库(无服务端) | 客户端/服务端数据库(C/S 架构) |
| 进程模型 | 与应用进程同进程运行 | 独立数据库服务进程 |
| 锁粒度 | 数据库级锁(WAL 模式下读/写分离) | 表级锁(MyISAM)/行级锁(InnoDB) |
| 存储方式 | 单文件(含所有数据/索引/日志) | 多文件(表空间/日志/索引分离) |
| 并发模型 | 串行化写操作,读可并发(WAL) | 支持高并发读写(行级锁) |
| 事务支持 | ACID(但锁粒度粗) | 完整 ACID(InnoDB 引擎) |
| 网络交互 | 无(本地文件访问) | 基于 TCP/IP 或 Socket 通信 |
核心结论:
- SQLite 追求极简、低开销、本地访问,去掉了服务端进程和网络层,小操作的性能损耗几乎为 0;
- MySQL 追求高并发、高可用、分布式,但引入了服务端、网络、锁管理等额外开销,小操作的"基础成本"更高。
二、核心性能维度对比:从微观到宏观
我们从延迟、吞吐量、并发、资源占用、大数据量五个核心维度,量化对比二者的性能表现(测试环境:普通服务器 CPU 8核16G,机械硬盘+SSD 混合存储)。
1. 微观延迟:小操作的"基础成本"
测试场景:单行查询、单行插入(无并发,本地访问)
| 操作 | SQLite (WAL 开启) | MySQL (InnoDB) | 性能差距 | 核心原因 |
|---|---|---|---|---|
| 单行查询(主键) | 0.01ms | 0.5ms | MySQL 慢 50 倍 | MySQL 需网络/进程通信、权限校验 |
| 单行插入(事务外) | 0.02ms | 1.2ms | MySQL 慢 60 倍 | SQLite 无事务提交的网络开销 |
| 单行插入(事务内) | 0.005ms | 0.3ms | MySQL 慢 60 倍 | InnoDB 行级锁的额外开销 |
关键洞察:
- SQLite 在单线程、低并发、小操作场景下碾压 MySQL------因为它没有"服务端-客户端"的通信成本,直接操作本地文件;
- MySQL 的"基础延迟"高,哪怕是最简单的查询,也需要经过"网络请求→服务端解析→权限校验→执行→结果返回"全流程。
2. 吞吐量:批量操作的极限能力
测试场景:批量插入/查询(10000 条数据,单线程)
| 操作 | SQLite (WAL 开启) | MySQL (InnoDB) | 性能差距 | 核心原因 |
|---|---|---|---|---|
| 批量插入(事务内) | 50000 条/秒 | 15000 条/秒 | SQLite 快 3.3 倍 | MySQL 日志刷盘(fsync)更频繁 |
| 批量查询(主键) | 80000 条/秒 | 20000 条/秒 | SQLite 快 4 倍 | 无网络传输,数据本地化 |
| 批量查询(非主键) | 15000 条/秒 | 10000 条/秒 | SQLite 快 1.5 倍 | InnoDB 索引扫描的开销 |
关键洞察:
- 批量操作中,SQLite 依然领先,但差距缩小------因为此时"IO 速度"成为核心瓶颈,而非进程/网络开销;
- MySQL 若开启
innodb_flush_log_at_trx_commit=2(降低事务安全性),插入性能可提升至 30000 条/秒,但仍低于 SQLite。
3. 并发性能:高并发下的表现反转
测试场景:多线程并发读写(核心差异场景)
| 并发数 | SQLite (WAL 开启) 写吞吐量 | MySQL (InnoDB) 写吞吐量 | 核心现象 |
|---|---|---|---|
| 1 | 50000 条/秒 | 15000 条/秒 | SQLite 领先 |
| 10 | 8000 条/秒 | 12000 条/秒 | MySQL 反超 |
| 50 | 2000 条/秒 | 10000 条/秒 | 差距扩大 |
| 100 | 1000 条/秒 | 8000 条/秒 | SQLite 几乎无法承受 |
| 并发数 | SQLite (WAL 开启) 读吞吐量 | MySQL (InnoDB) 读吞吐量 | 核心现象 |
|---|---|---|---|
| 1 | 80000 条/秒 | 20000 条/秒 | SQLite 领先 |
| 100 | 50000 条/秒 | 50000 条/秒 | 持平 |
| 500 | 30000 条/秒 | 70000 条/秒 | MySQL 反超 |
关键洞察:
- 写并发:SQLite 写操作串行化(即使 WAL 模式,写也需独占锁),并发数超过 10 后性能断崖式下跌;MySQL 行级锁支持高并发写,并发越高优势越明显;
- 读并发:SQLite WAL 模式下读可并发,但并发数超过 100 后,文件系统锁竞争导致性能下降;MySQL 服务端的连接池和行级锁更适配高并发读。
4. 资源占用:轻量 vs 重型
| 维度 | SQLite | MySQL |
|---|---|---|
| 内存占用(空闲) | <1MB | ~100MB(基础服务) |
| 内存占用(100 并发) | ~50MB | ~500MB |
| CPU 占用(批量插入) | ~20%(单线程) | ~40%(多线程) |
| 磁盘 IO 开销 | 低(单文件连续 IO) | 高(多文件随机 IO) |
关键洞察:
- SQLite 是"轻量级王者"------嵌入式场景(如手机 App、桌面软件)中,资源占用几乎可以忽略;
- MySQL 是"重型选手"------需要独立的内存/CPU 资源维护服务进程,不适合资源受限的场景。
5. 大数据量场景:单文件的上限
测试场景:数据库大小从 100MB 到 100GB,主键查询性能
| 数据库大小 | SQLite 查询延迟 | MySQL 查询延迟 | 核心现象 |
|---|---|---|---|
| 100MB | 0.01ms | 0.5ms | SQLite 领先 |
| 1GB | 0.02ms | 0.6ms | 差距不变 |
| 10GB | 0.05ms | 0.7ms | SQLite 仍领先 |
| 50GB | 0.2ms | 0.8ms | 差距缩小 |
| 100GB | 1.0ms | 0.9ms | MySQL 反超 |
关键洞察:
- SQLite 单文件在 50GB 以内性能稳定,超过 50GB 后,文件系统的寻址开销增大,性能下降;
- MySQL 分表空间存储,索引和数据分离,大数据量下的查询优化(如索引缓存)更高效;
- 注意:SQLite 官方建议单文件不超过 2TB,但实际业务中超过 100GB 就不建议使用。
三、场景化性能测试:真实业务中的表现
场景1:嵌入式/本地应用(如桌面工具、手机 App)
- 需求:本地数据存储,低并发,小数据量,低资源占用;
- 性能表现:SQLite 完胜------启动快、操作延迟低、无需部署服务;
- 反例:用 MySQL 会导致应用包体积增大、启动慢、耗电增加。
场景2:单机低并发 Web 应用(如个人博客、小型官网)
- 需求:日均访问 1 万次以内,读写比 9:1,无高并发写;
- 性能表现:SQLite 更快------无需维护数据库服务,查询延迟更低,部署成本为 0;
- 注意:需开启 WAL 模式,避免写操作阻塞读。
场景3:高并发 Web 应用(如电商、社交平台)
- 需求:日均访问 100 万次以上,并发写 100+ QPS;
- 性能表现:MySQL 完胜------SQLite 写并发瓶颈会导致请求超时、数据丢失,MySQL 行级锁和连接池可支撑高并发。
场景4:数据分析/批量处理(如日志统计)
- 需求:批量导入数据,复杂聚合查询,单线程/低并发;
- 性能表现:SQLite 更快------本地文件 IO 效率高,复杂查询的延迟更低;
- 注意:数据量超过 50GB 时,MySQL 的并行查询优化更有优势。
四、性能优化:针对性调优技巧
1. SQLite 性能调优(发挥极致优势)
sql
-- 开启 WAL 模式(核心优化,读不阻塞写)
PRAGMA journal_mode = WAL;
-- 调整缓存大小(根据内存调整,单位:页,默认 4KB/页)
PRAGMA cache_size = -200000; -- 800MB 缓存
-- 关闭同步刷盘(牺牲一点安全性,提升写性能)
PRAGMA synchronous = NORMAL;
-- 禁用临时文件(内存足够时)
PRAGMA temp_store = MEMORY;
- 批量操作必须放在事务中(避免自动提交的 IO 开销);
- 避免长时间持有读锁,及时关闭游标;
- 大数据量时,拆分表到多个 SQLite 文件(规避单文件瓶颈)。
2. MySQL 性能调优(适配高并发)
ini
# my.cnf 核心配置
[mysqld]
innodb_buffer_pool_size = 8G # 内存的 50%-70%
innodb_flush_log_at_trx_commit = 2 # 每秒刷盘,平衡性能与安全性
innodb_log_file_size = 1G # 增大日志文件,减少 checkpoint
max_connections = 1000 # 适配高并发
query_cache_type = OFF # 关闭查询缓存(高并发下反而慢)
- 使用 InnoDB 引擎(行级锁、ACID 支持);
- 合理设计索引(避免过度索引,影响写性能);
- 开启连接池(如 PgBouncer),减少连接创建开销;
- 批量插入用
LOAD DATA INFILE或事务封装。
五、选型决策:用场景定答案
优先选 SQLite 的场景
- 嵌入式/本地应用:手机 App、桌面软件、物联网设备(资源受限,无网络);
- 低并发单机应用:个人博客、小型官网、工具类网站(日均访问 < 10 万次);
- 只读/少写场景:数据报表、日志分析、配置存储(读写比 > 10:1);
- 开发/测试环境:快速原型开发,无需部署数据库服务,开箱即用。
优先选 MySQL 的场景
- 高并发应用:电商、社交平台、支付系统(并发写 > 100 QPS);
- 分布式/集群场景:需要主从复制、分库分表、负载均衡;
- 大数据量存储:单表数据 > 1000 万行,数据库大小 > 50GB;
- 多用户协作场景:多客户端同时读写,需要细粒度的权限控制。
临界场景:折中方案
- 读写分离:SQLite 作为只读副本,MySQL 作为主库;
- 混合存储:高频小操作用 SQLite,低频大操作用 MySQL;
- 定时同步:本地 SQLite 缓存数据,定时同步到 MySQL 集群。
六、总结
核心要点回顾
- 性能本质:SQLite 赢在"低开销、本地访问",MySQL 赢在"高并发、可扩展";
- 关键阈值 :
- 写并发 < 10 QPS → SQLite 更优;
- 写并发 > 10 QPS → MySQL 更优;
- 数据库大小 < 50GB → SQLite 更优;
- 数据库大小 > 50GB → MySQL 更优;
- 优化核心:SQLite 重点开启 WAL 模式、事务封装批量操作;MySQL 重点调优 InnoDB 缓存、行级锁、连接池。
最终建议
- 不要用"技术偏好"选数据库,而是用"场景需求";
- 小型应用先从 SQLite 起步,成本最低,性能足够;
- 业务增长后,平滑迁移到 MySQL(或 PostgreSQL),避免过早过度设计。
简单来说:小而简单的场景用 SQLite,大而复杂的场景用 MySQL。