最近的项目中,出现数据库搜索很慢,本地确没有问题,上去分析发现,数据库文件碎片化了。由于数据库是放在磁盘上的,碎片化之后,遍历数据库就相当于随机访问磁盘,速度就很慢。
使用filefrag命令查看碎片化:
$ filefrag u3049499598-7cb394645c881238-v0.db
u3049499598-7cb394645c881238-v0.db: 76452 extents found
读取文件:
dd if=u3049499598-7cb394645c881238-v0.db of=/dev/null iflag=direct status=progress
20206080 字节 (20 MB, 19 MiB) 已复制,4 s,5.0 MB/s
发现速度只有5MB/S,这就是碎片化了。执行数据库搜索需要3分钟。
$ btrfs filesystem defragment u2232476592-f8a433997316e97b-v0.db
$ sqlite3 u2232476592-f8a433997316e97b-v0.db VACUUM
执行这两条命令后,数据库搜索时间从3分钟下降到1.7s。
mozilla也碰到了同样的问题:
https://sqlite-users.sqlite.narkive.com/IfUGkoqR/coping-with-database-growth-fragmentation
可以通过设置chunk size为1M来减少碎片化。
int sz = 1024 * 1024;
sqlite3_file_control(db, "main", SQLITE_FCNTL_CHUNK_SIZE, &sz);
个人理解。如果同时写多个文件。比如A/B/C
那么A/B/C依次拿到连续的block,但是对于单个文件block就不连续了。
比如有block 1-10,A/B/C同时写,那分配的block可能是:
A 1 4 7
B 2 5 8
C 3 6 9
参考:
https://btrfs.readthedocs.io/en/latest/Defragmentation.html
https://stackoverflow.com/questions/13393866/sqlite-wal-performance-improvement