Sqlite3性能测试

xiaoxiao2021-02-28  66

参考:http://blog.csdn.net/majiakun1/article/details/46607163,感谢作者分享。

Sqlite3最简单的提升读写性能的方法有:

1. 关闭写同步,也就是设置synchronous。Sqlite3是一个文件数据库,所谓的设置写同步就是设置每次写完数据之后刷新IO缓存的频率,如果写同步设置为Full,那么每次写都会刷新缓存,这样保证数据总能写到文件里,十分安全的做法,防止机器掉电等意外,但是不断地刷新缓存效率低下,一般使用没有这么高的安全要求。关闭写同步就是不去手动刷新缓存,这样效率会极大地提升。关闭写同步只要执行"PRAGMA synchronous = OFF"即可。如Slite3提供的C接口代码,

const char* kTurnOffSynchronous = "PRAGMA synchronous = OFF;"; sqlite3_exec(db, kTurnOffSynchronous, NULL, NULL, NULL); 2. 执行SQL语句时,编译一次多次使用,而不是每执行一次都进行编译执行等操作。如Sqlite3提供的C接口代码:

const char* kInsertSql = "INSERT INTO PERFORMANCE_TEST VALUES(?,?,?,?);"; sqlite3_stmt* stmt = NULL; sqlite3_prepare_v2(db, kInsertSql, strlen(kInsertSql), &stmt, NULL); for (int i = 0; i < data_count; ++i) { sqlite3_reset(stmt); sqlite3_bind_int(stmt, 1, i); sqlite3_bind_int(stmt, 2, i); sqlite3_bind_int(stmt, 3, i); sqlite3_bind_int(stmt, 4, i); sqlite3_step(stmt); } if (turn_on_transaction) { sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); } sqlite3_finalize(stmt); 3. 显式开启事务。Sqlite3的语句执行操作隐式都开启了事务,比如写十万条数据,就会进行十万次事务,极大地限制了效率,解决方法就是显式开启事务,在写数据之前开启事务,写十万条数据之后,进行提交事务。这样写十万条数据只开启了一次事务。直接执行语句“begin”和“commit”即可开启和提交事务。

简单的测试结果如下(固态硬盘,只能简单地作为参考):

测试完整代码如下:

#include <iostream> #include <string> #include <sstream> #include <vector> #include <list> #include <cstdio> #include "sqlite3.h" #include "common.h" // 参考:http://blog.csdn.net/majiakun1/article/details/46607163 static const char* kDatabaseName = "test.db"; //-------------------------------------------------------------- static void TestTimer(); //-------------------------------------------------------------- static bool PrepareDB(sqlite3** db, bool create_table); static void CreateTable(); static void ClearTable(); static void TestExec(bool turn_off_synchronous = false); static void TestNoSynchronous(); static void TestTransactionExec(); static void TestStep(bool turn_on_transaction = true); static void PerformanceTest(); //-------------------------------------------------------------- int main() { //TestTimer(); //ClearTable(); CreateTable(); PerformanceTest(); return 0; } //-------------------------------------------------------------- static void PerformanceTest() { TestExec(false); TestExec(true); TestNoSynchronous(); TestTransactionExec(); TestStep(true); TestStep(false); } // 1.直接执行sqlite3_exec。 static void TestExec(bool turn_off_synchronous) { sqlite3* db = NULL; if (!PrepareDB(&db, false)) { return; } if (turn_off_synchronous) { std::cout << "1.关闭写同步执行sqlite3_exec : " << std::endl; } else { std::cout << "2.直接执行sqlite3_exec : " << std::endl; } utility::Timer timer; std::stringstream sstream(std::stringstream::out); const int kDataCount = 1000; const char* kTurnOffSynchronous = "PRAGMA synchronous = OFF;"; if (turn_off_synchronous) { sqlite3_exec(db, kTurnOffSynchronous, NULL, NULL, NULL); } // Insert. timer.Start(); for (int i = 0; i < kDataCount; ++i) { sstream << "INSERT INTO PERFORMANCE_TEST VALUES(" << i << "," << i << "," << i << "," << i << ");"; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } double rate = kDataCount / timer.GetSeconds(); std::cout << "插入数据: " << rate <<"条/秒" << std::endl; // Delete. timer.Start(); for (int i = 0; i < kDataCount; ++i) { sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } rate = kDataCount / timer.GetSeconds(); std::cout << "删除数据: " << rate << "条/秒\n" << std::endl; sqlite3_close(db); } // 2.显式开启事务,执行sqlite3_exec。 // (A)所谓”事务“就是指一组SQL命令,这些命令要么一起执行,要么都不被执行。 // (B)在SQLite中,每调用一次sqlite3_exec()函数,就会隐式地开启了一个事务,如果插入一条数据,就调用该函数一次,事务就会被反复地开启、关闭,会增大IO量。 // (C)如果在插入数据前显式开启事务,插入后再一起提交,则会大大提高IO效率,进而加数据快插入速度。 static void TestTransactionExec() { sqlite3* db = NULL; if (!PrepareDB(&db, false)) { return; } std::cout << "3.显式开启事务执行sqlite3_exec : " << std::endl; utility::Timer timer; std::stringstream sstream(std::stringstream::out); const int kDataCount = 100000; const char* kBeginTransaction = "begin"; const char* kCommitTransaction = "commit"; // Insert. timer.Start(); sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); for (int i = 0; i < kDataCount; ++i) { sstream << "INSERT INTO PERFORMANCE_TEST VALUES(" << i << "," << i << "," << i << "," << i << ");"; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); double rate = kDataCount / timer.GetSeconds(); std::cout << "插入数据: " << rate << "条/秒" << std::endl; // Delete. timer.Start(); sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); for (int i = 0; i < kDataCount; ++i) { sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); rate = kDataCount / timer.GetSeconds(); std::cout << "删除数据: " << rate << "条/秒\n" << std::endl; sqlite3_close(db); } // 3.关闭写同步且显式开启事务执行sqlite3_exec。 // (A)在SQLite中,数据库配置的参数都由编译指示(pragma)来实现的。 // (B)synchronous选项有三种可选状态,分别是full、normal、off。 // 当synchronous设置为FULL,SQLite数据库引擎在紧急时刻会暂停以确定数据已经写入磁盘。这使系统崩溃或电源出问题时能确保数据库在重起后不会损坏。FULL synchronous很安全但很慢。 // 当synchronous设置为NORMAL, SQLite数据库引擎在大部分紧急时刻会暂停,但不像FULL模式下那么频繁。 NORMAL模式下有很小的几率(但不是不存在)发生电源故障导致数据库损坏的情况。 // 但实际上,在这种情况 下很可能你的硬盘已经不能使用,或者发生了其他的不可恢复的硬件错误。 // 当为synchronous OFF时,SQLite在传递数据给系统以后直接继续而不暂停。若运行SQLite的应用程序崩溃, 数据不会损伤,但在系统崩溃或写入数据时意外断电。 // (C)SQLite3中,该选项的默认值就是full,如果我们再插入数据前将其改为off,则会提高效率。 static void TestNoSynchronous() { sqlite3* db = NULL; if (!PrepareDB(&db, false)) { return; } std::cout << "4.关闭写同步且显式开启事务执行sqlite3_exec : " << std::endl; utility::Timer timer; std::stringstream sstream(std::stringstream::out); const int kDataCount = 100000; const char* kTurnOffSynchronous = "PRAGMA synchronous = OFF;"; const char* kBeginTransaction = "begin"; const char* kCommitTransaction = "commit"; sqlite3_exec(db, kTurnOffSynchronous, NULL, NULL, NULL); // Insert. timer.Start(); sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); for (int i = 0; i < kDataCount; ++i) { sstream << "INSERT INTO PERFORMANCE_TEST VALUES(" << i << "," << i << "," << i << "," << i << ");"; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); double rate = kDataCount / timer.GetSeconds(); std::cout << "插入数据: " << rate << "条/秒" << std::endl; // Delete. timer.Start(); sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); for (int i = 0; i < kDataCount; ++i) { sstream << "DELETE FROM PERFORMANCE_TEST WHERE ID1 = " << i; sqlite3_exec(db, sstream.str().c_str(), NULL, NULL, NULL); sstream.str(""); } sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); rate = kDataCount / timer.GetSeconds(); std::cout << "删除数据: " << rate << "条/秒\n" << std::endl; sqlite3_close(db); } // 4. 使用sqlite3_step执行。 // (A)SQLite执行SQL语句的时候,有两种方式:一种是使用前文提到的函数sqlite3_exec(),该函数直接调用包含SQL语句的字符串; // 另一种方法就是“执行准备”(类似于存储过程)操作,即先将SQL语句编译好,然后再一步一步(或一行一行)地执行。 // (B)如果采用前者的话,就算开起了事务,SQLite仍然要对循环中每一句SQL语句进行“词法分析”和“语法分析”。 // (C)“执行准备”主要分为三大步骤:并且声明一个指向sqlite3_stmt对象的指针,该函数对参数化的SQL语句zSql进行编译,将编译后的状态存入ppStmt中。 // 调用函数 sqlite3_step() ,这个函数就是执行一步(本例中就是插入一行),如果函数返回的是SQLite_ROW则说明仍在继续执行,否则则说明已经执行完所有操作。 // 调用函数 sqlite3_finalize(),关闭语句。 // (D)综上所述啊,SQLite插入数据效率最快的方式就是:事务+关闭写同步+执行准备(存储过程),如果对数据库安全性有要求的话,就开启写同步。 static void TestStep(bool turn_on_transaction) { sqlite3* db = NULL; if (!PrepareDB(&db, false)) { return; } std::string title = "5.直接执行sqlite3_step : "; if (turn_on_transaction) { title = "6.显式开启事务执行sqlite3_step : "; } std::cout << title << std::endl; utility::Timer timer; int data_count = 100; if (turn_on_transaction) { data_count = 10000; } const char* kBeginTransaction = "begin"; const char* kCommitTransaction = "commit"; // Insert. timer.Start(); if (turn_on_transaction) { sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); } const char* kInsertSql = "INSERT INTO PERFORMANCE_TEST VALUES(?,?,?,?);"; sqlite3_stmt* stmt = NULL; sqlite3_prepare_v2(db, kInsertSql, strlen(kInsertSql), &stmt, NULL); for (int i = 0; i < data_count; ++i) { sqlite3_reset(stmt); sqlite3_bind_int(stmt, 1, i); sqlite3_bind_int(stmt, 2, i); sqlite3_bind_int(stmt, 3, i); sqlite3_bind_int(stmt, 4, i); sqlite3_step(stmt); } if (turn_on_transaction) { sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); } sqlite3_finalize(stmt); double rate = data_count / timer.GetSeconds(); std::cout << "插入数据: " << rate << "条/秒" << std::endl; // Delete. timer.Start(); if (turn_on_transaction) { sqlite3_exec(db, kBeginTransaction, NULL, NULL, NULL); } const char* kDeleteSql = "DELETE FROM PERFORMANCE_TEST WHERE ID1 = ?;"; sqlite3_prepare_v2(db, kDeleteSql, strlen(kDeleteSql), &stmt, NULL); for (int i = 0; i < data_count; ++i) { sqlite3_reset(stmt); sqlite3_bind_int(stmt, 1, i); sqlite3_step(stmt); } if (turn_on_transaction) { sqlite3_exec(db, kCommitTransaction, NULL, NULL, NULL); } sqlite3_finalize(stmt); rate = data_count / timer.GetSeconds(); std::cout << "删除数据: " << rate << "条/秒\n" << std::endl; sqlite3_close(db); } static bool PrepareDB(sqlite3** db, bool create_table) { int rc = sqlite3_open(kDatabaseName, db); if (rc != SQLITE_OK) { std::cout << "Failed to open " << kDatabaseName << std::endl; std::cout << "Error msg: " << sqlite3_errmsg(*db) << std::endl; return false; } if (!create_table) { return true; } const char* kCreateTableSql = "CREATE TABLE PERFORMANCE_TEST(\ ID1 INT, ID2 INT, ID3 INT, ID4 INT\ );"; char* error_msg = NULL; rc = sqlite3_exec(*db, kCreateTableSql, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { std::cout << "Failed to create table PERFORMANCE_TEST." << std::endl; std::cout << "Error msg: " << error_msg << std::endl; sqlite3_free(error_msg); return false; } return true; } static void CreateTable() { sqlite3* db = NULL; PrepareDB(&db, true); sqlite3_close(db); } static void ClearTable() { sqlite3* db = NULL; PrepareDB(&db, false); const char* kClrearTableSql = "DELETE FROM PERFORMANCE_TEST;"; char* error_msg = NULL; int rc = sqlite3_exec(db, kClrearTableSql, NULL, NULL, &error_msg); if (rc != SQLITE_OK) { std::cout << "Failed to clear table!" << std::endl; std::cout << "Error msg: " << error_msg << std::endl; sqlite3_free(error_msg); } sqlite3_close(db); }

转载请注明原文地址: https://www.6miu.com/read-58400.html

最新回复(0)