微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

SQLite3开启事务和关闭事务模式下,性能测试对比

最近学习了下sqlite数据库基本知识,想了解下这款小巧的数据库性能到底怎样,于是写个性能测试程序,对 sqlite3 最新发布版(3.7.13)在Linux平台进行了测试。最后发现在开启事务模式和关闭事务模式(认)下,性能测试结果相差近 1000 倍! 

在测试的过程中,得出如下一些结论:

1、对于批量数据操作,建议采用事务模式,批量提交操作。

2、在提交事务之前,若程序发生异常,则所有插入、更新、删除等操作,都不会成功。

3、在操作数据库时,程序发生异常而中断操作,不会对现有的数据库造成任何破坏(sqlite3 的可靠性还不错!)。

一、测试环境
操作系统类型:linux-suse11 2.6.34.10-0.6-desktop,x86-32
操作系统内核:2.6.34.10-0.6-desktop
编译器版本 : gcc (SUSE Linux) 4.5.0 20100604 [gcc-4_5-branch revision 160292]
数据库版本 : sqlite 3.7.13
cpu 配置 :AMD Athlon(tm) II X2 240 Processor, 2812.890 MHZ, 1024 KB cache size,dual core
内存配置 :1017812 kB

二、编译方法
1、开启事务模式编译: gcc -Wall -lpthread -ldl testsqlite3.c sqlite3.c -o main -DTRANSACTION_ON;
2、关闭事务模式编译: gcc -Wall -lpthread -ldl testsqlite3.c sqlite3.c -o main;

三、测试结果:

测试结果单位:微秒(μs), 1秒=1000毫秒=1000000微秒

1、关闭事务模式(认)

操作类型 CountsTotalTime(us)AverageTime(us)
插入 1000 31307617 31307.000000
查询 1000 944442 944.000000
更新1000 32264043 32264.000000
删除 1000 30638604 30638.000000

2、开启事务模式

操作类型 CountsTotalTime(us)AverageTime(us)
插入 1000 23326 23.000000
查询 1000 935739 935.000000
更新 1000 39197 39.000000
删除 1000 24394 24.000000

四、源代码

  1. /******************************************************************************
  2. copyrightbyJavacode007,Allrightsreserved!
  3. Filename:testsqlite3.c
  4. Author:Javacode007
  5. Date:2012-8-11
  6. Version:1.0
  7. Description:sqlite3基本功能性能测试
  8. ******************************************************************************/
  9. #include"sqlite3.h"
  10. #include<stdlib.h>
  11. #include<stdio.h>
  12. #include<string.h>
  13. #include<sys/time.h>
  14. #include<time.h>
  15. #definePRINT_TRACE(fmt,args...)do{\
  16. fprintf(stderr,fmt"File:%s,Line:%04d\r\n",##args,__FILE__,__LINE__);\
  17. \
  18. }while(0)
  19. #ifdefTRANSACTION_ON
  20. #definesTART_TRANSACTION()sqlite3_exec(db,"begintransaction;",NULL,NULL)
  21. #defineEND_TRANSACTION()sqlite3_exec(db,"committransaction;",NULL)
  22. #else
  23. #definesTART_TRANSACTION()
  24. #defineEND_TRANSACTION()
  25. #endif
  26. //性别枚举类型
  27. typedefenum
  28. {
  29. UNKNowN,
  30. MALE,
  31. FEMALE,
  32. }SEX_E;
  33. //sql操作枚举类型
  34. typedefenum
  35. {
  36. INSERT,
  37. SELECT,
  38. UPDATE,
  39. DELETE
  40. }sql_OPTYPE;
  41. typedefstructstemployee
  42. {
  43. unsignedintid;
  44. unsignedintage;
  45. SEX_Esex;
  46. charregistertime[26];
  47. charcellphone[12];
  48. charemail[128];
  49. charresume[512];
  50. floatsalary;
  51. }Employee_S;
  52. //全局雇员ID
  53. staticunsignedintg_employeeid;
  54. longdiff_timeval(structtimevaltv1,structtimevaltv2)
  55. {
  56. longtimecost=0;
  57. timecost=1000000*(tv2.tv_sec-tv1.tv_sec)+(tv2.tv_usec-tv1.tv_usec);
  58. returntimecost;
  59. }
  60. voidinit_employee(Employee_S*employee)
  61. {
  62. time_tttime;
  63. if(NULL==employee)
  64. {
  65. PRINT_TRACE("Invalidparameter:NULLpointer!");
  66. return;
  67. }
  68. memset(employee,sizeof(*employee));
  69. g_employeeid++;
  70. employee->id=g_employeeid;
  71. employee->age=0;
  72. employee->sex=UNKNowN;
  73. time(&ttime);
  74. sprintf(employee->registertime,"%s",ctime(&ttime));
  75. sprintf(employee->cellphone,"%0*d",sizeof(employee->cellphone)-1,0);
  76. sprintf(employee->email,"persion_%06d@sun.org",g_employeeid);
  77. sprintf(employee->resume,"Resume:");
  78. employee->salary=12345.78;
  79. }
  80. voidprint_employee(Employee_Semployee)
  81. {
  82. printf("id=%d,age=%d,sex=%d,regtime=%s",employee.id,employee.age,employee.sex,employee.registertime);
  83. printf("cellphone=%s,email=%s,resume=%s,salary=%6.2f\r\n",employee.cellphone,employee.email,employee.resume,employee.salary);
  84. }
  85. sqlite3*open_db(constchar*dbname)
  86. {
  87. intret=-1;
  88. sqlite3*db=NULL;
  89. if(NULL==dbname)
  90. {
  91. PRINT_TRACE("Invalidparameter:nulldatabasename!");
  92. returnNULL;
  93. }
  94. ret=sqlite3_open(dbname,&db);
  95. if(sqlITE_OK!=ret)
  96. {
  97. PRINT_TRACE("Opendatabase\"%s\"Failed:%s.",dbname,sqlite3_errmsg(db));
  98. sqlite3_close(db);
  99. returnNULL;
  100. }
  101. returndb;
  102. }
  103. intclose_db(sqlite3*db)
  104. {
  105. intret=-1;
  106. if(NULL!=db)
  107. {
  108. ret=sqlite3_close(db);
  109. }
  110. returnret;
  111. }
  112. intcreate_table(sqlite3*db,constchar*tablename)
  113. {
  114. intret=-1;
  115. intcmdlen=0;
  116. char*errmsg;
  117. char*sqlfmt="CREATETABLE%s(idINTEGERPRIMARYKEY,ageINTEGER,sex"
  118. "INTEGER,registertimeVARCHAR(26),cellphoneVARCHAR(12),"
  119. "emailTEXT,resumeTEXT,salaryREAL);";
  120. char*sqlcmd=NULL;
  121. if(NULL==db||NULL==tablename)
  122. {
  123. PRINT_TRACE("Invalidparameter:&db=%p,&tablename=%p.",db,tablename);
  124. returnret;
  125. }
  126. //必须用strlen获取字符长度,不能用sizeof,sizeof获取的是指针长度,为4.
  127. cmdlen=strlen(sqlfmt)+strlen(tablename)+1;
  128. sqlcmd=(char*)malloc(cmdlen);
  129. if(NULL==sqlcmd)
  130. {
  131. PRINT_TRACE("Notenoughmemoryforsqlcommand!");
  132. returnret;
  133. }
  134. memset(sqlcmd,cmdlen);
  135. sprintf(sqlcmd,sqlfmt,tablename);
  136. ret=sqlite3_exec(db,sqlcmd,&errmsg);
  137. if(sqlITE_OK!=ret)
  138. {
  139. PRINT_TRACE("Createtable\"%s\"Failed:%s.",tablename,errmsg);
  140. sqlite3_free(errmsg);
  141. free(sqlcmd);
  142. returnret;
  143. }
  144. free(sqlcmd);
  145. returnret;
  146. }
  147. char*get_sqlcmd(constchar*tablename,sql_OPTYPEoptype,Employee_Semployee)
  148. {
  149. char*insertfmt="INSERTINTO%svalues(%d,%d,'%s',%10.6f);";
  150. char*selectfmt="SELECT*FROM%swhereid<=%d;";
  151. char*updatefmt="UPDATE%ssetage=%d,registertime='%s',cellphone='%s',"\
  152. "email='%s',resume='%s',salary=%10.6fwhereid=%d;";
  153. char*deletefmt="DELETEFROM%swhereid=%d;";
  154. char*sqlcmd=NULL;
  155. intcmdlen=0;
  156. if(NULL==tablename)
  157. {
  158. PRINT_TRACE("Invalidparameter:NULLpointeroftablename!");
  159. returnNULL;
  160. }
  161. //为了简化,给sql语句申请最大空间
  162. cmdlen=strlen(updatefmt)+strlen(tablename)+sizeof(employee);
  163. sqlcmd=(char*)malloc(cmdlen);
  164. if(NULL==sqlcmd)
  165. {
  166. PRINT_TRACE("Notenoughmemoryforsqlcommand!");
  167. returnNULL;
  168. }
  169. switch(optype)
  170. {
  171. caseINSERT:
  172. sprintf(sqlcmd,insertfmt,\
  173. employee.sex,employee.registertime,\
  174. employee.email,employee.salary);
  175. break;
  176. caseSELECT:
  177. sprintf(sqlcmd,selectfmt,employee.id);
  178. break;
  179. caseUPDATE:
  180. sprintf(sqlcmd,updatefmt,\
  181. employee.registertime,\
  182. employee.resume,employee.salary,employee.id);
  183. break;
  184. caseDELETE:
  185. sprintf(sqlcmd,deletefmt,employee.id);
  186. break;
  187. default:
  188. PRINT_TRACE("UnkNownoperationtype:%d\r\n",optype);
  189. free(sqlcmd);
  190. returnNULL;
  191. }
  192. returnsqlcmd;
  193. }
  194. inttest(constchar*dbname,constchar*tablename,intcount,intistableexists)
  195. {
  196. intret=-1;
  197. inti=0;
  198. intfailcount=0;
  199. longcosttime=0;
  200. time_tttime;
  201. structtimevaltvstart;
  202. structtimevaltvend;
  203. sqlite3*db=NULL;
  204. Employee_Semployee;
  205. char*sqlcmd=NULL;
  206. char*errmsg=NULL;
  207. time(&ttime);
  208. printf("\r\nStart\"%s\"at:%s",__FUNCTION__,ctime(&ttime));
  209. if(NULL==dbname||NULL==tablename||0>=count)
  210. {
  211. PRINT_TRACE("InvalidParameter:dbname=%p,tablename=%p,count=%d.",count);
  212. returnret;
  213. }
  214. //打开数据库
  215. db=open_db(dbname);
  216. if(NULL==db)
  217. {
  218. returnret;
  219. }
  220. //判断是否需要创建表
  221. if(0==istableexists)
  222. {
  223. ret=create_table(db,tablename);
  224. if(sqlITE_OK!=ret)
  225. {
  226. close_db(db);
  227. returnret;
  228. }
  229. }
  230. //开启事务模式
  231. START_TRANSACTION();
  232. for(i=0;i<count;i++)
  233. {
  234. init_employee(&employee);
  235. sqlcmd=get_sqlcmd(tablename,optype,employee);
  236. if(NULL==sqlcmd)
  237. {
  238. failcount++;
  239. continue;
  240. }
  241. //开始计时
  242. gettimeofday(&tvstart,NULL);
  243. ret=sqlite3_exec(db,&errmsg);
  244. //结束计时
  245. gettimeofday(&tvend,NULL);
  246. costtime+=diff_timeval(tvstart,tvend);
  247. if(sqlITE_OK!=ret)
  248. {
  249. failcount++;
  250. PRINT_TRACE("Excecutesql:%sFailed!Errorinfo:%s.",errmsg);
  251. }
  252. if(NULL!=sqlcmd)
  253. {
  254. free(sqlcmd);
  255. }
  256. if(NULL!=errmsg)
  257. {
  258. sqlite3_free(errmsg);
  259. }
  260. }
  261. //关闭事务模式
  262. END_TRANSACTION();
  263. close_db(db);
  264. //打印结果
  265. printf("OperationType:%d,Databasename:%s,Tablename:%s.\r\n",tablename);
  266. printf("Counts\tTotalTime(us)\tAverageTime(us)\r\n");
  267. printf("%-8d%-10ld%-10.6f\r\n",count,costtime,(float)(costtime/count));
  268. time(&ttime);
  269. printf("Finish\"%s\"at:%s\r\n",ctime(&ttime));
  270. if(0<failcount)
  271. {
  272. ret=-1;
  273. }
  274. returnret;
  275. }
  276. intmain()
  277. {
  278. intcount=1000;
  279. intistableexists=0;
  280. intret=-1;
  281. char*dbname="employee.db";
  282. char*tablename="employee";
  283. sql_OPTYPEoptype;
  284. optype=INSERT;
  285. ret=test(dbname,istableexists);
  286. if(sqlITE_OK!=ret)
  287. {
  288. PRINT_TRACE("TestFailed!");
  289. return0;
  290. }
  291. istableexists=1;
  292. g_employeeid=0;
  293. optype=SELECT;
  294. ret=test(dbname,istableexists);
  295. if(sqlITE_OK!=ret)
  296. {
  297. PRINT_TRACE("TestFailed!");
  298. return0;
  299. }
  300. g_employeeid=0;
  301. optype=UPDATE;
  302. ret=test(dbname,istableexists);
  303. if(sqlITE_OK!=ret)
  304. {
  305. PRINT_TRACE("TestFailed!");
  306. return0;
  307. }
  308. g_employeeid=0;
  309. optype=DELETE;
  310. ret=test(dbname,istableexists);
  311. if(sqlITE_OK!=ret)
  312. {
  313. PRINT_TRACE("TestFailed!");
  314. return0;
  315. }
  316. return0;
  317. }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐