运行 SQLite 的几点心得
原文由 Julia Evans 于 发布,订阅该博客
大家好!最近我在做一个 Django 网站,决定用 SQLite 作为数据库。刚开始决定把 SQLite 用在网站上时,我看了一堆博客文章,都说小网站在生产环境用 SQLite 完全没问题——我也觉得确实没问题,但我当时没有充分意识到,SQLite 终究也是数据库,数据库都很复杂,而我对数据库运维其实了解得很少。
所以,这里分享一下我在运行 SQLite 过程中学到的几个小经验。这已经是我第 4 个使用 SQLite 的网站了,我觉得这次要更棘手一些,因为借助 Django ORM 的强大功能,我让数据库承担了比以前不用 Django 时更多的工作。
一开始,我就像所有博客文章说的那样开启了 WAL 模式,然后就听天由命了。
ANALYZE 原来很重要
今天我在一张只有 4000 行的表上执行了一条查询(用SQLite 的 FTS5做全文搜索),结果居然花了 5 秒。在我看来这很不正常:电脑应该很快才对!
结果发现,解决办法竟然是执行一下ANALYZE!执行之后,原本要 5 秒的查询立刻降到了 0.05 秒左右(或者某个小到我懒得再去细究的数字)。查询计划到底哪里出了问题,我到现在也不太清楚,猜测可能是某种意外二次方的问题。
ANALYZE 会生成“统计信息”(我猜是关于每张表有多少行之类的,应该还有其他信息吧?),这样查询规划器就能做出更优的选择。
也许哪天我会学会怎么看查询计划。
清理数据库很棘手
有时候我会不小心往数据库里写入大量本不该存在的数据(比如来自django-tasks-db的已完成任务),然后就想把它们清理掉。
这种情况下,我经常会遇到这样的情形:
- 我执行某种命令来清理这些数据
- 命令执行超过 5 秒,因为数据量很大(老实说,我到现在也不太明白为什么这些 DELETE 语句会这么慢,可能是事务里跑了大量 Python 代码吧,不太确定)
- 就在这期间,另一个 worker 尝试写入数据库,5 秒后超时(我设置的超时时间就是 5 秒)
- 这个 worker 因为无法写入数据库而崩溃,虚拟机也随之关闭
所以目前我的做法是把清理操作拆成小批量执行,这样就不会出现执行时间超过 5 秒的数据库查询。经历了这些,我也更能理解为什么有人会想用 Postgres 这种“真正的”数据库——它可以同时支持多个写入者。
也许以后再遇到这种事,我会直接让网站停机进行计划内维护,但我还没想好具体该怎么操作。
关于 ORM 查询性能暂时没什么可说的
到目前为止,除了 ANALYZE 那件事,我一直都是用 Django 的 ORM 想查什么就查什么,完全没考虑过查询性能,总体来说还算顺利。数据库现在很小(大概也就 10000 行?),而且我估计以后也会一直保持很小,所以希望这种做法能一直管用。
备份 SQLite
我试过两种备份 SQLite 的方式。我好像还没真正测试过从备份中恢复,不过通常我会用“死亡开关”来监控备份是否正常。
方式一:restic
sqlite3 /data/calendar.db "VACUUM INTO '/tmp/calendar.sqlite'"
gzip /tmp/calendar.sqlite
# Upload backup to S3
# Sometimes the backup gets OOM killed and so it stays locked, do an unlock
restic -r s3://s3.amazonaws.com/some_bucket/ unlock
# Do the backup & prune old backups
restic -r s3://s3.amazonaws.com/some_bucket/ backup /tmp/calendar.sqlite.gz
restic -r s3://s3.amazonaws.com/some_bucket/ snapshots
restic -r s3://s3.amazonaws.com/some_bucket/ forget -l 1 -H 6 -d 2 -w 2 -m 2 -y 2
restic -r s3://s3.amazonaws.com/some_bucket/ prune
方式二:litestream
最近我开始尝试 Litestream,因为我觉得增量备份可能会更高效:用 restic 备份时有时会因为内存不足被系统杀掉,我有点厌烦了。基本上只需要写个配置文件,然后执行:
litestream replicate -config litestream.yml
我在配置文件里设置了 retention: 400h,想尽量保留一部分数据库的历史记录,但到底有没有生效我也不清楚。
我一直备份到 AWS,这件事总是很麻烦,因为在 AWS 控制台里找来找去生成凭证实在让人头疼。也许哪天我会换成其他兼容 S3 的服务。
可以使用多个数据库
我现在的项目只有一个数据库,不过之前在Mess with DNS这个项目里,我用过一个小技巧:把不同的表拆到三个独立的数据库文件里,因为这些表本来就不需要放在同一个库里。我觉得这样挺有用的。
Mess with DNS 用 SQLite 已经跑了 4 年了(从 2022 年开始),一直很稳定,我觉得当初从 Postgres 迁过来对这个项目来说是非常正确的选择。
就这些了!
每次回头看自己花了多久才学会所用技术的一些基础知识,都觉得挺有意思的。我想我第一次在 Web 项目里用 SQLite 还是在 2022 年,而直到今天才知道有 ANALYZE 这个东西!估计过个一两年,我又会学到别的什么非常基础的功能。
一些参考资料
除了官方文档,我还看过这些博客文章:
随机一篇博客
评论
登录后参与讨论