当前位置: 代码迷 >> SQL >> SQLite3开启事务跟关闭事务模式下,性能测试对比
  详细解决方案

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

热度:18   发布时间:2016-05-05 10:35:50.0
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、关闭事务模式(默认)

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

2、开启事务模式

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

四、源代码:

 

[cpp] view plaincopyprint?
  1. /****************************************************************************** 
  2. Copyright by Javacode007, All rights reserved! 
  3. Filename    : testsqlite3.c 
  4. Author      : Javacode007 
  5. Date        : 2012-8-11 
  6. Version     : 1.0 
  7. Description : SQLite3 基本功能性能测试 
  8. ******************************************************************************/  
  9.   
  10. #include "sqlite3.h"  
  11. #include <stdlib.h>  
  12. #include <stdio.h>  
  13. #include <string.h>  
  14. #include <sys/time.h>  
  15. #include <time.h>  
  16.   
  17. #define PRINT_TRACE(fmt, args...) do {\  
  18.     fprintf(stderr, fmt" File:%s, Line:%04d\r\n",##args, __FILE__, __LINE__);\  
  19.     \  
  20. }while(0)      
  21.   
  22.   
  23. #ifdef TRANSACTION_ON  
  24. #define START_TRANSACTION() sqlite3_exec(db, "begin transaction;", NULL, NULL, NULL)  
  25. #define END_TRANSACTION()   sqlite3_exec(db, "commit transaction;", NULL, NULL, NULL)  
  26. #else  
  27. #define START_TRANSACTION()   
  28. #define END_TRANSACTION()     
  29. #endif  
  30.   
  31.   
  32.   
  33. //性别枚举类型  
  34. typedef enum   
  35. {  
  36.     UNKNOWN,  
  37.     MALE,  
  38.     FEMALE,  
  39. }SEX_E;  
  40.   
  41. //SQL 操作枚举类型  
  42. typedef enum  
  43. {  
  44.     INSERT,  
  45.     SELECT,  
  46.     UPDATE,  
  47.     DELETE  
  48. }SQL_OPTYPE;  
  49.   
  50. typedef struct stEmployee  
  51. {  
  52.     unsigned int id;  
  53.     unsigned int age;  
  54.     SEX_E        sex;  
  55.     char         registertime[26];  
  56.     char         cellphone[12];  
  57.     char         email[128];  
  58.     char         resume[512];  
  59.     float        salary;  
  60. }Employee_S;  
  61.   
  62. //全局雇员ID  
  63. static unsigned int g_employeeid;  
  64.   
  65. long diff_timeval(struct timeval tv1, struct timeval tv2)  
  66. {  
  67.     long timecost = 0;  
  68.   
  69.     timecost = 1000000*(tv2.tv_sec - tv1.tv_sec) + (tv2.tv_usec - tv1.tv_usec);  
  70.   
  71.     return timecost;  
  72. }  
  73.   
  74. void init_employee(Employee_S* employee)  
  75. {  
  76.     time_t ttime;  
  77.       
  78.     if(NULL == employee)  
  79.     {  
  80.         PRINT_TRACE("Invalid parameter: NULL pointer!");  
  81.         return ;  
  82.     }  
  83.       
  84.     memset(employee, 0, sizeof(*employee));  
  85.     g_employeeid ++;  
  86.   
  87.     employee->id  = g_employeeid;  
  88.     employee->age = 0;  
  89.     employee->sex = UNKNOWN;  
  90.   
  91.     time(&ttime);  
  92.     sprintf(employee->registertime, "%s", ctime(&ttime));  
  93.     sprintf(employee->cellphone, "%0*d"sizeof(employee->cellphone) -1, 0);  
  94.     sprintf(employee->email, "[email protected]", g_employeeid);  
  95.     sprintf(employee->resume, "Resume:");  
  96.       
  97.     employee->salary = 12345.78;  
  98.       
  99.       
  100. }  
  101.   
  102. void print_employee(Employee_S employee)  
  103. {  
  104.     printf("id=%d, age=%d, sex=%d, regtime=%s", employee.id, employee.age, employee.sex, employee.registertime);  
  105.     printf("cellphone=%s, email=%s, resume=%s, salary=%6.2f\r\n",  employee.cellphone, employee.email, employee.resume, employee.salary);  
  106. }  
  107.   
  108.   
  109. sqlite3* open_db(const char* dbname)  
  110. {  
  111.     int ret = -1;  
  112.     sqlite3 *db = NULL;  
  113.   
  114.     if(NULL == dbname)  
  115.     {  
  116.         PRINT_TRACE("Invalid parameter: null database name!");  
  117.         return NULL;  
  118.     }  
  119.   
  120.     ret = sqlite3_open(dbname, &db);  
  121.     if(SQLITE_OK != ret)  
  122.     {  
  123.         PRINT_TRACE("Open database \"%s\" failed: %s.", dbname, sqlite3_errmsg(db));  
  124.         sqlite3_close(db);  
  125.         return NULL;  
  126.     }  
  127.   
  128.     return db;  
  129. }  
  130.   
  131. int close_db(sqlite3* db)  
  132. {  
  133.     int ret = -1;  
  134.   
  135.     if(NULL != db)  
  136.     {  
  137.         ret = sqlite3_close(db);  
  138.     }  
  139.   
  140.     return ret;  
  141. }  
  142.   
  143. int create_table(sqlite3* db, const char* tablename)  
  144. {  
  145.     int ret = -1;  
  146.     int cmdlen = 0;  
  147.       
  148.     char *errmsg ;  
  149.     char *sqlfmt = "CREATE TABLE %s (id INTEGER PRIMARY KEY, age INTEGER, sex "  
  150.                     "INTEGER, registertime VARCHAR(26), cellphone VARCHAR(12),"  
  151.                     "email TEXT, resume TEXT, salary REAL);";  
  152.     char *sqlcmd = NULL;  
  153.       
  154.   
  155.     if(NULL == db || NULL == tablename)  
  156.     {  
  157.         PRINT_TRACE("Invalid parameter: &db=%p, &tablename=%p.", db, tablename);  
  158.         return ret;  
  159.     }  
  160.   
  161.     //必须用 strlen 获取字符长度,不能用 sizeof,sizeof 获取的是指针长度,为4.  
  162.     cmdlen = strlen(sqlfmt) + strlen(tablename) + 1;  
  163.     sqlcmd = (char*)malloc(cmdlen);  
  164.   
  165.     if(NULL == sqlcmd)  
  166.     {  
  167.         PRINT_TRACE("Not enough memory for sql command!");  
  168.         return ret;  
  169.     }  
  170.       
  171.     memset(sqlcmd, 0, cmdlen);  
  172.     sprintf(sqlcmd, sqlfmt, tablename);  
  173.   
  174.     ret = sqlite3_exec(db, sqlcmd, NULL, NULL, &errmsg);  
  175.     if(SQLITE_OK != ret)  
  176.     {  
  177.         PRINT_TRACE("Create table \"%s\" failed: %s.", tablename, errmsg);  
  178.         sqlite3_free(errmsg);  
  179.         free(sqlcmd);  
  180.         return ret;  
  181.     }  
  182.   
  183.     free(sqlcmd);  
  184.   
  185.     return ret;  
  186. }  
  187.   
  188. char* get_sqlcmd(const char* tablename, SQL_OPTYPE optype, Employee_S employee)  
  189. {  
  190.     char* insertfmt = "INSERT INTO %s values(%d, %d, %d, '%s', '%s', '%s', '%s', %10.6f);";  
  191.     char* selectfmt = "SELECT * FROM %s where id <= %d;";  
  192.     char* updatefmt = "UPDATE %s set age=%d, sex=%d, registertime='%s',cellphone='%s',"\  
  193.                       "email='%s', resume='%s', salary=%10.6f where id=%d;";  
  194.     char* deletefmt = "DELETE FROM %s where id=%d;";  
  195.     char* sqlcmd = NULL;  
  196.     int   cmdlen = 0;  
  197.   
  198.     if(NULL == tablename)  
  199.     {  
  200.         PRINT_TRACE("Invalid parameter: NULL pointer of tablename!");  
  201.         return NULL;  
  202.     }  
  203.   
  204.     //为了简化,给 sql 语句申请最大空间  
  205.     cmdlen = strlen(updatefmt) + strlen(tablename) + sizeof(employee);  
  206.     sqlcmd = (char*) malloc(cmdlen);  
  207.     if(NULL == sqlcmd)  
  208.     {  
  209.         PRINT_TRACE("Not enough memory for sql command!");  
  210.         return NULL;  
  211.     }  
  212.       
  213.     switch(optype)  
  214.     {  
  215.         case INSERT:  
  216.             sprintf(sqlcmd, insertfmt, tablename, employee.id, employee.age, \  
  217.                 employee.sex, employee.registertime, employee.cellphone, \  
  218.                 employee.email, employee.resume, employee.salary);  
  219.             break;  
  220.               
  221.         case SELECT:  
  222.             sprintf(sqlcmd, selectfmt, tablename, employee.id);  
  223.             break;  
  224.   
  225.         case UPDATE:  
  226.             sprintf(sqlcmd, updatefmt, tablename, employee.age, employee.sex, \  
  227.                 employee.registertime, employee.cellphone, employee.email, \  
  228.                 employee.resume, employee.salary, employee.id);  
  229.             break;  
  230.   
  231.         case DELETE:  
  232.             sprintf(sqlcmd, deletefmt, tablename, employee.id);  
  233.             break;  
  234.   
  235.         default:  
  236.             PRINT_TRACE("Unknown operation type:%d\r\n", optype);  
  237.             free(sqlcmd);  
  238.             return NULL;  
  239.      }  
  240.   
  241.     return sqlcmd;  
  242.       
  243.       
  244. }  
  245.   
  246. int test(const char* dbname, const char* tablename, SQL_OPTYPE optype, int count, int istableexists)  
  247. {  
  248.     int  ret = -1;  
  249.     int  i = 0;  
  250.     int  failcount = 0;  
  251.     long costtime = 0;  
  252.   
  253.     time_t  ttime;  
  254.     struct timeval tvStart;  
  255.     struct timeval tvEnd;  
  256.       
  257.     sqlite3*   db = NULL;  
  258.     Employee_S employee;  
  259.     char*      sqlcmd = NULL;  
  260.     char*      errmsg = NULL;  
  261.   
  262.     time(&ttime);  
  263.     printf("\r\nStart \"%s\" at: %s", __FUNCTION__, ctime(&ttime));  
  264.       
  265.     if(NULL == dbname || NULL == tablename || 0 >= count)  
  266.     {  
  267.         PRINT_TRACE("Invalid Parameter:dbname=%p, tablename=%p, count=%d.", dbname, tablename, count);  
  268.         return ret;  
  269.     }  
  270.   
  271.     //打开数据库  
  272.     db = open_db(dbname);  
  273.     if(NULL == db)  
  274.     {  
  275.         return ret;  
  276.     }  
  277.   
  278.     //判断是否需要创建表  
  279.     if( 0 == istableexists)  
  280.     {  
  281.         ret = create_table(db, tablename);  
  282.         if(SQLITE_OK != ret)  
  283.         {  
  284.             close_db(db);  
  285.             return ret;  
  286.         }  
  287.     }  
  288.   
  289.     //开启事务模式  
  290.     START_TRANSACTION();  
  291.   
  292.     for(i = 0; i < count; i++)  
  293.     {  
  294.         init_employee(&employee);  
  295.           
  296.         sqlcmd = get_sqlcmd(tablename, optype, employee);  
  297.           
  298.         if(NULL == sqlcmd)  
  299.         {  
  300.             failcount ++;  
  301.             continue;  
  302.         }  
  303.   
  304.         //开始计时  
  305.         gettimeofday(&tvStart, NULL);  
  306.           
  307.         ret = sqlite3_exec(db, sqlcmd, NULL, NULL, &errmsg);  
  308.   
  309.         //结束计时  
  310.         gettimeofday(&tvEnd, NULL);  
  311.   
  312.         costtime += diff_timeval(tvStart, tvEnd);  
  313.   
  314.         if(SQLITE_OK != ret)  
  315.         {  
  316.             failcount ++;  
  317.             PRINT_TRACE("Excecute sql: %s failed! Error info:%s.", sqlcmd, errmsg);  
  318.         }  
  319.           
  320.         if(NULL != sqlcmd)  
  321.         {  
  322.             free(sqlcmd);  
  323.         }  
  324.               
  325.         if(NULL != errmsg)  
  326.         {  
  327.             sqlite3_free(errmsg);  
  328.         }  
  329.           
  330.     }  
  331.   
  332.     //关闭事务模式  
  333.     END_TRANSACTION();  
  334.   
  335.     close_db(db);  
  336.   
  337.     //打印结果  
  338.     printf("Operation Type: %d, Database name: %s,  Table name: %s. \r\n", optype, dbname, tablename);  
  339.     printf("Counts\tTotalTime(us)\tAverageTime(us)\r\n");  
  340.     printf("%-8d %-10ld    %-10.6f\r\n", count, costtime, (float)(costtime/count));  
  341.   
  342.     time(&ttime);  
  343.     printf("Finish \"%s\" at: %s\r\n", __FUNCTION__, ctime(&ttime));  
  344.   
  345.     if(0 < failcount)  
  346.     {  
  347.         ret = -1;  
  348.     }  
  349.   
  350.     return ret;  
  351.       
  352. }  
  353.   
  354. int main()  
  355. {  
  356.     int   count = 1000;  
  357.     int   istableexists = 0;  
  358.     int   ret = -1;  
  359.       
  360.     char* dbname = "employee.db";  
  361.     char* tablename = "employee";  
  362.   
  363.     SQL_OPTYPE optype;  
  364.       
  365.     optype = INSERT;  
  366.     ret = test(dbname, tablename, optype, count, istableexists);  
  367.     if(SQLITE_OK != ret)  
  368.     {  
  369.         PRINT_TRACE("Test failed!");  
  370.         return 0;  
  371.     }  
  372.       
  373.     istableexists = 1;  
  374.     g_employeeid = 0;  
  375.     optype = SELECT;  
  376.     ret = test(dbname, tablename, optype, count, istableexists);  
  377.       
  378.     if(SQLITE_OK != ret)  
  379.     {  
  380.         PRINT_TRACE("Test failed!");  
  381.         return 0;  
  382.     }  
  383.   
  384.     g_employeeid = 0;  
  385.     optype = UPDATE;  
  386.   
  387.     ret = test(dbname, tablename, optype, count, istableexists);  
  388.     if(SQLITE_OK != ret)  
  389.     {  
  390.         PRINT_TRACE("Test failed!");  
  391.         return 0;  
  392.     }  
  393.   
  394.     g_employeeid = 0;  
  395.     optype = DELETE;  
  396.   
  397.     ret = test(dbname, tablename, optype, count, istableexists);  
  398.     if(SQLITE_OK != ret)  
  399.     {  
  400.         PRINT_TRACE("Test failed!");  
  401.         return 0;  
  402.     }  
  403.   
  404.     return 0;  
  405. }