技能|SQLite连接复用与查询提速法
> 适用系统:HFMS(纯标准库 http.server + sqlite3)。同类"多线程 Web + SQLite"内网小系统通用。
> 版本:v1.0.0 归档日期:2026-10-03 形态:zip 内含单一 技能|SQLite连接复用与查询提速法.md
适用场景
- SQLite 后端跑在
ThreadingHTTPServer下,单页面/单接口一次请求要查库很多次(如首页仪表盘叠加 18+ 次查询),每次都sqlite3.connect()重开连接(约 70ms/次),累计成秒级卡顿。 - 症状:
/overview实测 ~2.77s,其中绝大部分耗在建连;功能没错,但体验像"卡死"。 - 不适用:单线程脚本、连接池已完善的 ORM 场景。
操作步骤
- 线程级连接缓存:在
db.py顶部建import threading; _local = threading.local()。 - 复用型
connect():函数内conn = getattr(_local, 'conn', None),为空才sqlite3.connect(DB_PATH, timeout=5, factory=_Conn),否则直接复用;首次建连时设好 PRAGMA 并写入_local.conn。 - 复用期保活:自定义
_Conn(sqlite3.Connection),重写close()为空操作(保活),__del__调父类真正close()(线程结束/GC 时释放句柄与 WAL 锁)。 - 固定 WAL 三件套:
PRAGMA busy_timeout=5000; PRAGMA journal_mode=WAL; PRAGMA synchronous=NORMAL。在connect()与init()两处都设,确保任意连接都生效。 - 统一入口:全部
db.*函数一律conn = connect(); c = conn.cursor(),不再各自sqlite3.connect()(本系统 90+ 处即此模式)。 - 首次建库竞争:
connect()开头os.makedirs(os.path.dirname(DB_PATH), exist_ok=True),防并发首次建库竞态。
注意边界
- 线程级复用 = 每条连接仅在其所属线程内使用,天然线程安全;严禁跨线程共享同一条连接(会报 sqlite 多线程错误)。
- 配
ThreadingHTTPServer:每请求在其线程内只建连一次,close()置空保活,真正释放在线程结束 GC 时。 - WAL 下读不阻塞写,但写-写仍串行,
busy_timeout=5000兜底等待而非立即报错。 - DB_PATH 必须绝对路径(跨模块一致)。
反例避雷
- 不要为"提速"关掉 WAL 或把
synchronous设 FULL:前者降并发、后者降崩溃恢复力。 - 不要每次请求手动
close():失去复用意义,回到"每查重开"。 - 不要全局单连接:多线程不安全,必崩。
- 不要把计时探针留生产代码:测完移除或置 DEBUG 开关。
关联笔记
- 纯标准库本地Web系统搭建(底座):ThreadingHTTPServer + WAL 是前置条件。
- 备份保留策略收紧与统一淘汰法:WAL 下做快照备份须先 checkpoint,否则可能只备到旧状态。
- Web端点性能剖面定位法:本技能是"DB 慢"那一段的精准修复手段。
实战战绩
/overview从 ~2.77s → 67ms(约 34×);仪表盘 18+ 次建连归并为每线程 1 次。- 代码锚点:
db.py的_local = threading.local()(L14)、class _Conn(L22)、def connect()(L35,含getattr(_local,'conn',None)复用 + WAL 三件套 L46-48)、init()(L55,PRAGMA 同设 L185-187)、90+ 处conn = connect(); c = conn.cursor()。
版本记录
- v1.0.0(2026-10-03):首版。从本次
/overview34× 提速实战提炼,含真实代码锚点(行号)可直接照做。