最近学习了下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
四、源代码:
- /******************************************************************************
- CopyrightbyJavacode007,Allrightsreserved!
- Filename:testsqlite3.c
- Author:Javacode007
- Date:2012-8-11
- Version:1.0
- Description:sqlite3基本功能性能测试
- ******************************************************************************/
- #include"sqlite3.h"
- #include<stdlib.h>
- #include<stdio.h>
- #include<string.h>
- #include<sys/time.h>
- #include<time.h>
- #definePRINT_TRACE(fmt,args...)do{\
- fprintf(stderr,fmt"File:%s,Line:%04d\r\n",##args,__FILE__,__LINE__);\
- \
- }while(0)
- #ifdefTRANSACTION_ON
- #defineSTART_TRANSACTION()sqlite3_exec(db,"begintransaction;",NULL,NULL)
- #defineEND_TRANSACTION()sqlite3_exec(db,"committransaction;",NULL)
- #else
- #defineSTART_TRANSACTION()
- #defineEND_TRANSACTION()
- #endif
- //性别枚举类型
- typedefenum
- {
- UNKNOWN,
- MALE,
- FEMALE,
- }SEX_E;
- //sql操作枚举类型
- typedefenum
- {
- INSERT,
- SELECT,
- UPDATE,
- DELETE
- }sql_OPTYPE;
- typedefstructstEmployee
- {
- unsignedintid;
- unsignedintage;
- SEX_Esex;
- charregistertime[26];
- charcellphone[12];
- charemail[128];
- charresume[512];
- floatsalary;
- }Employee_S;
- //全局雇员ID
- staticunsignedintg_employeeid;
- longdiff_timeval(structtimevaltv1,structtimevaltv2)
- {
- longtimecost=0;
- timecost=1000000*(tv2.tv_sec-tv1.tv_sec)+(tv2.tv_usec-tv1.tv_usec);
- returntimecost;
- }
- voidinit_employee(Employee_S*employee)
- {
- time_tttime;
- if(NULL==employee)
- {
- PRINT_TRACE("Invalidparameter:NULLpointer!");
- return;
- }
- memset(employee,sizeof(*employee));
- g_employeeid++;
- employee->id=g_employeeid;
- employee->age=0;
- employee->sex=UNKNOWN;
- time(&ttime);
- sprintf(employee->registertime,"%s",ctime(&ttime));
- sprintf(employee->cellphone,"%0*d",sizeof(employee->cellphone)-1,0);
- sprintf(employee->email,"persion_%06d@sun.org",g_employeeid);
- sprintf(employee->resume,"Resume:");
- employee->salary=12345.78;
- }
- voidprint_employee(Employee_Semployee)
- {
- printf("id=%d,age=%d,sex=%d,regtime=%s",employee.id,employee.age,employee.sex,employee.registertime);
- printf("cellphone=%s,email=%s,resume=%s,salary=%6.2f\r\n",employee.cellphone,employee.email,employee.resume,employee.salary);
- }
- sqlite3*open_db(constchar*dbname)
- {
- intret=-1;
- sqlite3*db=NULL;
- if(NULL==dbname)
- {
- PRINT_TRACE("Invalidparameter:nulldatabasename!");
- returnNULL;
- }
- ret=sqlite3_open(dbname,&db);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("Opendatabase\"%s\"Failed:%s.",dbname,sqlite3_errmsg(db));
- sqlite3_close(db);
- returnNULL;
- }
- returndb;
- }
- intclose_db(sqlite3*db)
- {
- intret=-1;
- if(NULL!=db)
- {
- ret=sqlite3_close(db);
- }
- returnret;
- }
- intcreate_table(sqlite3*db,constchar*tablename)
- {
- intret=-1;
- intcmdlen=0;
- char*errmsg;
- char*sqlfmt="CREATETABLE%s(idINTEGERPRIMARYKEY,ageINTEGER,sex"
- "INTEGER,registertimeVARCHAR(26),cellphoneVARCHAR(12),"
- "emailTEXT,resumeTEXT,salaryREAL);";
- char*sqlcmd=NULL;
- if(NULL==db||NULL==tablename)
- {
- PRINT_TRACE("Invalidparameter:&db=%p,&tablename=%p.",db,tablename);
- returnret;
- }
- //必须用strlen获取字符长度,不能用sizeof,sizeof获取的是指针长度,为4.
- cmdlen=strlen(sqlfmt)+strlen(tablename)+1;
- sqlcmd=(char*)malloc(cmdlen);
- if(NULL==sqlcmd)
- {
- PRINT_TRACE("Notenoughmemoryforsqlcommand!");
- returnret;
- }
- memset(sqlcmd,cmdlen);
- sprintf(sqlcmd,sqlfmt,tablename);
- ret=sqlite3_exec(db,sqlcmd,&errmsg);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("Createtable\"%s\"Failed:%s.",tablename,errmsg);
- sqlite3_free(errmsg);
- free(sqlcmd);
- returnret;
- }
- free(sqlcmd);
- returnret;
- }
- char*get_sqlcmd(constchar*tablename,sql_OPTYPEoptype,Employee_Semployee)
- {
- char*insertfmt="INSERTINTO%svalues(%d,%d,'%s',%10.6f);";
- char*selectfmt="SELECT*FROM%swhereid<=%d;";
- char*updatefmt="UPDATE%ssetage=%d,registertime='%s',cellphone='%s',"\
- "email='%s',resume='%s',salary=%10.6fwhereid=%d;";
- char*deletefmt="DELETEFROM%swhereid=%d;";
- char*sqlcmd=NULL;
- intcmdlen=0;
- if(NULL==tablename)
- {
- PRINT_TRACE("Invalidparameter:NULLpointeroftablename!");
- returnNULL;
- }
- //为了简化,给sql语句申请最大空间
- cmdlen=strlen(updatefmt)+strlen(tablename)+sizeof(employee);
- sqlcmd=(char*)malloc(cmdlen);
- if(NULL==sqlcmd)
- {
- PRINT_TRACE("Notenoughmemoryforsqlcommand!");
- returnNULL;
- }
- switch(optype)
- {
- caseINSERT:
- sprintf(sqlcmd,insertfmt,\
- employee.sex,employee.registertime,\
- employee.email,employee.salary);
- break;
- caseSELECT:
- sprintf(sqlcmd,selectfmt,employee.id);
- break;
- caseUPDATE:
- sprintf(sqlcmd,updatefmt,\
- employee.registertime,\
- employee.resume,employee.salary,employee.id);
- break;
- caseDELETE:
- sprintf(sqlcmd,deletefmt,employee.id);
- break;
- default:
- PRINT_TRACE("Unknownoperationtype:%d\r\n",optype);
- free(sqlcmd);
- returnNULL;
- }
- returnsqlcmd;
- }
- inttest(constchar*dbname,constchar*tablename,intcount,intistableexists)
- {
- intret=-1;
- inti=0;
- intfailcount=0;
- longcosttime=0;
- time_tttime;
- structtimevaltvStart;
- structtimevaltvEnd;
- sqlite3*db=NULL;
- Employee_Semployee;
- char*sqlcmd=NULL;
- char*errmsg=NULL;
- time(&ttime);
- printf("\r\nStart\"%s\"at:%s",__FUNCTION__,ctime(&ttime));
- if(NULL==dbname||NULL==tablename||0>=count)
- {
- PRINT_TRACE("InvalidParameter:dbname=%p,tablename=%p,count=%d.",count);
- returnret;
- }
- //打开数据库
- db=open_db(dbname);
- if(NULL==db)
- {
- returnret;
- }
- //判断是否需要创建表
- if(0==istableexists)
- {
- ret=create_table(db,tablename);
- if(sqlITE_OK!=ret)
- {
- close_db(db);
- returnret;
- }
- }
- //开启事务模式
- START_TRANSACTION();
- for(i=0;i<count;i++)
- {
- init_employee(&employee);
- sqlcmd=get_sqlcmd(tablename,optype,employee);
- if(NULL==sqlcmd)
- {
- failcount++;
- continue;
- }
- //开始计时
- gettimeofday(&tvStart,NULL);
- ret=sqlite3_exec(db,&errmsg);
- //结束计时
- gettimeofday(&tvEnd,NULL);
- costtime+=diff_timeval(tvStart,tvEnd);
- if(sqlITE_OK!=ret)
- {
- failcount++;
- PRINT_TRACE("Excecutesql:%sFailed!Errorinfo:%s.",errmsg);
- }
- if(NULL!=sqlcmd)
- {
- free(sqlcmd);
- }
- if(NULL!=errmsg)
- {
- sqlite3_free(errmsg);
- }
- }
- //关闭事务模式
- END_TRANSACTION();
- close_db(db);
- //打印结果
- printf("OperationType:%d,Databasename:%s,Tablename:%s.\r\n",tablename);
- printf("Counts\tTotalTime(us)\tAverageTime(us)\r\n");
- printf("%-8d%-10ld%-10.6f\r\n",count,costtime,(float)(costtime/count));
- time(&ttime);
- printf("Finish\"%s\"at:%s\r\n",ctime(&ttime));
- if(0<failcount)
- {
- ret=-1;
- }
- returnret;
- }
- intmain()
- {
- intcount=1000;
- intistableexists=0;
- intret=-1;
- char*dbname="employee.db";
- char*tablename="employee";
- sql_OPTYPEoptype;
- optype=INSERT;
- ret=test(dbname,istableexists);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("TestFailed!");
- return0;
- }
- istableexists=1;
- g_employeeid=0;
- optype=SELECT;
- ret=test(dbname,istableexists);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("TestFailed!");
- return0;
- }
- g_employeeid=0;
- optype=UPDATE;
- ret=test(dbname,istableexists);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("TestFailed!");
- return0;
- }
- g_employeeid=0;
- optype=DELETE;
- ret=test(dbname,istableexists);
- if(sqlITE_OK!=ret)
- {
- PRINT_TRACE("TestFailed!");
- return0;
- }
- return0;
- }