SQLite 插入大量数据慢的解决方法

本文探讨了SQLite在批量插入数据时性能不佳的问题,并通过使用显式事务处理显著提高了效率。实验结果显示,在使用显式事务后,即使是大规模的数据插入也能实现快速完成。

sqlite 插入数据很慢的原因:sqlite在没有显式使用事务的时候会为每条insert都使用事务操作,而sqlite数据库是以文件的形式存在磁盘中,就相当于每次访问时都要打开一次文件,如果对数据进行大量的操作,时间都耗费在I/O操作上,所以很慢。
解决方法是显式使用事务的形式提交:因为我们开始事务后,进行的大量操作的语句都保存在内存中,当提交时才全部写入数据库,此时,数据库文件也就只用打开一次。
我在没有显式使用事务形式插入100条数据时用了12.226s;用显式事务形式,插入100条只用了0.172s,插入1000000条也才34.891s,相关很大吧。
显式使用事务的例子:

#include <iostream>
#include <windows.h>
using namespace std;
#include "sqlite/sqlite3.h"
int main()
{
    sqlite3* db;
    int nResult = sqlite3_open("test.db",&db);
    if (nResult != SQLITE_OK)
    {
        cout<<"打开数据库失败:"<<sqlite3_errmsg(db)<<endl;
        return 0;
    }
    else
    {
        cout<<"数据库打开成功"<<endl;
    }

    char* errmsg;

    nResult = sqlite3_exec(db,"create table fuck(id integer primary key autoincrement,name varchar(100))",NULL,NULL,&errmsg);
     if (nResult != SQLITE_OK)
     {
         sqlite3_close(db);
         cout<<errmsg;
         sqlite3_free(errmsg);
        return 0;
    }

    string strSql;
    strSql+="begin;\n";
    for (int i=0;i<100;i++)
    {
        strSql+="insert into fuck values(null,'heh');\n";
    }
    strSql+="commit;";
    //cout<<strSql<<endl;

    SYSTEMTIME tm_s;
    GetLocalTime(&tm_s);

    nResult = sqlite3_exec(db,strSql.c_str(),NULL,NULL,&errmsg);

    SYSTEMTIME tm_e;
    GetLocalTime(&tm_e);

    if (nResult != SQLITE_OK)
    {
        sqlite3_close(db);
        cout<<errmsg<<endl;
        sqlite3_free(errmsg);
        return 0;
    }

    cout<<"start:"<<tm_s.wMinute<<":"<<tm_s.wSecond<<":"<<tm_s.wMilliseconds<<endl;
    cout<<"end  :"<<tm_e.wMinute<<":"<<tm_e.wSecond<<":"<<tm_e.wMilliseconds<<endl;

    return 0;
} 
### SQLite 插入数据性能优化原因分析 SQLite 插入数据速度的主要原因包括数据库默认配置、事务处理机制以及 SQL 语句的执行方式。在默认情况下,SQLite 的写同步(synchronous)设置为 `FULL`,这会确保每次事务提交都会将数据写入磁盘,从而保证数据完整性,但这也显著降低了插入速度[^2]。 此外,使用 `sqlite3_exec()` 函数直接执行包含 SQL 语句的字符串会导致每次插入操作都需要进行“词法分析”和“语法分析”,即使开启了事务也无法避免这一开销。这种重复解析过程对于大量数据插入来说是极大的性能瓶颈。 为了进一步提升性能,可以采用“执行准备”机制,即先将 SQL 语句编译好,然后通过绑定参数的方式逐条执行。这种方式减少了重复解析 SQL 语句的开销,提高了插入效率。 另一个影响插入性能的关键因素是事务的使用。如果每条插入语句都单独作为一个事务提交,则每次都要经历日志写入、页刷盘等操作,导致性能下降。相反,将多个插入操作包裹在一个事务中,可以显著减少磁盘 I/O 操作次数,从而提高整体性能[^4]。 此外,构建长 SQL 字符串并一次性执行多条插入语句的方式虽然也能提升效率,但在实际测试中发现,某些场景下插入一条数据仍可能需要近 50ms,这对于用户体验而言仍然较差。因此,合理的批量处理策略与事务控制是关键[^3]。 以下是一个优化示例,展示了如何通过预编译语句和事务机制来提升插入性能: ```c sqlite3_exec(db, "BEGIN TRANSACTION", 0, 0, 0); const char* sql = "INSERT INTO table (col1, col2) VALUES (?, ?)"; sqlite3_stmt* stmt; sqlite3_prepare_v2(db, sql, -1, &stmt, 0); for (int i = 0; i < count; ++i) { sqlite3_bind_text(stmt, 1, data[i].col1, -1, SQLITE_STATIC); sqlite3_bind_int(stmt, 2, data[i].col2); sqlite3_step(stmt); sqlite3_reset(stmt); } sqlite3_finalize(stmt); sqlite3_exec(db, "COMMIT TRANSACTION", 0, 0, 0); ``` 该方法不仅减少了 SQL 解析次数,还利用了事务机制,大幅提升了插入效率[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值