IT技术博客大学习 共学习 共进步

关于sqlite的事务的使用

PHPor 的Blog 2013-09-23 13:54:28 浏览 3,443 次

缘起

   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. 分布式系统的事务处理 (阅读 7,246)
  2. 在perl中连接和使用sqlite做数据存储 (阅读 5,703)
  3. 从Mysql到Sqlite的迁移 (阅读 5,342)
  4. MySQL数据库分布式事务XA优缺点与改进方案 (阅读 4,644)
  5. 分布式事务性能分析 (阅读 4,623)
  6. SQLIte这么娇小可爱,不多了解点都不行啊 (阅读 4,444)
  7. MySQL数据库分布式事务XA的实现原理分析 (阅读 3,505)
  8. 使用python将Sqlite中的数据直接输出为CVS (阅读 3,364)
  9. Google Megastore系统事务机制 (阅读 3,245)
  10. Storm入门教程 第五章 一致性事务 (阅读 2,764)