IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

关于sqlite的事务的使用

PHPor 的Blog 2013-09-23 13:54:28 累计浏览 3,542 次
本机暂存

缘起

   sqlite写入500条不大的记录居然要花费20多秒的时间,太慢了!!!

分析

   sqlite是一个非常优秀的嵌入式数据库,读取性能非常好,写入性能就比较差一些,为什么写入性能差呢?下面做了一个测试。

   下面是对500+条记录些操作的系统调用的观察,发现时间基本花费在了fdatasync系统调用上,调用2064次;write系统调用虽然8049次,但是write并不保证逻辑,所以速度很快。

$ strace -c php test.php 
27.688107013702 (耗时27.6s)
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 88.73    0.073919          36      2064           fdatasync
  3.88    0.003231           0      8049           write
  3.77    0.003144           6       516           unlink
  1.12    0.000929           0      6730           fcntl64
  0.90    0.000751           0      9118         3 _llseek
  0.86    0.000720           1      1218        82 open
  0.24    0.000198           0      1143           close
  0.20    0.000167           0      1182           read
  0.16    0.000131           0       520       518 access
  0.05    0.000039           1        42         1 lstat64
  0.04    0.000033           0       194           mmap2
  0.03    0.000027           0        92           munmap
  0.03    0.000021           0        58        49 stat64
  0.00    0.000000           0         1           execve
  0.00    0.000000           0        20           time
  0.00    0.000000           0        21           brk
  0.00    0.000000           0         3         2 ioctl
  0.00    0.000000           0         3           gettimeofday
  0.00    0.000000           0         1           readlink
  0.00    0.000000           0         2           uname
  0.00    0.000000           0        28           mprotect
  0.00    0.000000           0         4           poll
  0.00    0.000000           0         5           rt_sigaction
  0.00    0.000000           0         2           rt_sigprocmask
  0.00    0.000000           0         2           getcwd
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0       648           fstat64
  0.00    0.000000           0         4           futex
  0.00    0.000000           0         1           sched_setaffinity
  0.00    0.000000           0         2           sched_getaffinity
  0.00    0.000000           0         1           set_thread_area
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         4           socket
  0.00    0.000000           0         4         2 connect
  0.00    0.000000           0         1           send
  0.00    0.000000           0         1           recvfrom
  0.00    0.000000           0         1           shutdown
  0.00    0.000000           0         5           setsockopt
------ ----------- ----------- --------- --------- ----------------
100.00    0.083310                 31693       657 total

查资料

   http://www.cnblogs.com/KimSky/archive/2011/05/31/2064028.html

   发现: 如果使用事务的方式批量插入数据,效果会有明显改善,因为默认情况下每次写入操作都会落地才返回的(更加安全靠谱),如果使用事务,则批量数据一次性落地。

   修改代码,分析系统调用如下:(发现fdatasync调用12次)

$ strace -c php test.php 
0.20949816703796 (耗时 209ms)
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 71.64    0.000998          83        12           fdatasync
  7.61    0.000106           1       155           read
  5.24    0.000073           0       194           mmap2
  4.16    0.000058           0       195           write
  2.58    0.000036           0       135           fstat64
  1.65    0.000023           0        92           munmap
  1.58    0.000022           1        28           mprotect
  1.51    0.000021           1        42         1 lstat64
  1.44    0.000020          20         1           readlink
  1.29    0.000018           0       238         3 _llseek
  1.29    0.000018           0        58        49 stat64
  0.00    0.000000           0       192        82 open
  0.00    0.000000           0       117           close
  0.00    0.000000           0         3           unlink
  0.00    0.000000           0         1           execve
  0.00    0.000000           0        20           time
  0.00    0.000000           0         7         5 access
  0.00    0.000000           0        21           brk
  0.00    0.000000           0         3         2 ioctl
  0.00    0.000000           0         3           gettimeofday
  0.00    0.000000           0         2           uname
  0.00    0.000000           0         4           poll
  0.00    0.000000           0         5           rt_sigaction
  0.00    0.000000           0         2           rt_sigprocmask
  0.00    0.000000           0         2           getcwd
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0        61           fcntl64
  0.00    0.000000           0         4           futex
  0.00    0.000000           0         1           sched_setaffinity
  0.00    0.000000           0         2           sched_getaffinity
  0.00    0.000000           0         1           set_thread_area
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
  0.00    0.000000           0         4           socket
  0.00    0.000000           0         4         2 connect
  0.00    0.000000           0         1           send
  0.00    0.000000           0         1           recvfrom
  0.00    0.000000           0         1           shutdown
  0.00    0.000000           0         5           setsockopt
------ ----------- ----------- --------- --------- ----------------
100.00    0.001393                  1620       144 total

结论:

   1. 借用事务采用批量写入的方式来加速写操作

   2. 如果业务上不能批量操作呢?似乎有一个nosync的sqlite版本(不知道为什么不是一个配置选项)

   参考资料: http://www.sqlite.org/speed.html

   3. 如果数据量太大,可以分多批提交事务,因为事务是需要内存的。(不过,sqlite一般不会存放N个G的数据的,几百MB已经算是比较大的了,这样的数据量内存还是吃的消的)

   参考资料:

   http://www.phpchina.com/archives/view-33876-1.html

   关于sqlite的系列分析文章(可以看看)

   http://www.cnblogs.com/hustcat/archive/2009/02/12/1389448.html

   SQLite的原子提交原理

   http://www.cnblogs.com/vagerent/archive/2008/11/05/1327247.html

同分类推荐文章

  1. 使用deepseek进行Oracle恢复,引起重大故障 (2026-06-22 10:56:00)
  2. 接手一个只差临门一脚的数据库恢复 (2026-06-18 00:13:09)
  3. 我做了一个 AI 版的 StarRocks 升级风险扫描工具,直接帮我定位到一个风险 (2026-06-15 01:00:00)

查看更多 数据库 文章 →

建议继续学习

  1. 记录一个软中断问题 (累计阅读 16,956)
  2. Go Reflect 性能 (累计阅读 14,156)
  3. 关于Apache调优点滴 (累计阅读 6,637)
  4. MYSQL分页limit速度太慢优化方法 (累计阅读 5,869)
  5. 在perl中连接和使用sqlite做数据存储 (累计阅读 5,814)
  6. 从Mysql到Sqlite的迁移 (累计阅读 5,458)
  7. Python操作Excel (累计阅读 5,029)
  8. 关于哈希map奇慢无比的原因定位 (累计阅读 4,903)
  9. 一线DBA总结:MySQL搭配XFS文件系统优势最大 (累计阅读 4,914)
  10. SQLIte这么娇小可爱,不多了解点都不行啊 (累计阅读 4,559)