sqlite 源码编译,并写一个 sqlite_demo程序。

环境介绍:

ubuntu 系统

cmake (cmake 安装) (可以手动下载源码,编译安装,也可以 使用系统最新的 cmake 安装)

 

 

一、下载源码并编译

https://github.com/sqlite/sqlite/tree/vesion-3.45.1

下载 3.45.1 的源码 sqlite-vesion-3.45.1.zip 

解压 sqlite-vesion-3.45.1 到当前目录

在 sqlite-vesion-3.45.1 同级目录,创建  bld 文件夹,并进入这个文件夹

        mkdir bld                ;#  Build will occur in a sibling directory
        cd bld                   ;#  Change to the build directory

 

 
添加权限,并 执行 configure 脚本文件
     
  chmod 755 ../sqlite-vesion-3.45.1/configure
   ../sqlite-vesion-3.45.1/configure   

 

 
 编译工程:
        make  -j4            

 

编译完成之后,会在当前的 bld目录,生成 sqlite3可执行文件,
sqlite3.h, sqlite3.c  文件,以及  .libs目录,下面有  libsqlite3.a 静态库文件。

 

二、创建一个cmake工程

project_directory/
│
├── CMakeLists.txt
├── main.cpp
└── sqlitelib/           # 创建一个 sqlitelib 文件夹
    ├── sqlite3.h          # 将 sqlite3.h文件拷贝过来
    ├── libsqlite3.a       # 将 libsqlite3.a 静态库拷贝过来

 

CMakeLists.txt

cmake_minimum_required(VERSION 3.10)
project(SQLiteCppDemo)

# Set C++ standard
set(CMAKE_CXX_STANDARD 11)

# Add executable
add_executable(sqlite_demo main.cpp)

# Include the path to the SQLite3 headers and link to the SQLite3 static library
target_include_directories(sqlite_demo PRIVATE ${CMAKE_SOURCE_DIR}/sqlitelib)
target_link_libraries(sqlite_demo PRIVATE ${CMAKE_SOURCE_DIR}/sqlitelib/libsqlite3.a)


# Set the output directory for the built executable
set_target_properties(sqlite_demo PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)

 

main.cpp

1.如果 henry.db数据库不存在,则创建;

2.创建 Userinfo表;

3.插入 若干条测试数据;

4.查询 Userinfo表所有的数据,并打印输出;

#include <iostream>
#include <sqlite3.h>

void executeSQL(sqlite3* db, const char* sql) {
    char* errMsg = nullptr;
    int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
    if (rc != SQLITE_OK) {
        std::cerr << "SQL error: " << errMsg << std::endl;
        sqlite3_free(errMsg);
    }
}

int main() {
    sqlite3* db;
    const char* dbName = "henry.db";
    
    // Open the database (creates if not exists)
    int rc = sqlite3_open(dbName, &db);
    if (rc) {
        std::cerr << "Can't open database: " << sqlite3_errmsg(db) << std::endl;
        return rc;
    }
    std::cout << "Opened database successfully" << std::endl;
    
    // SQL statement to create Userinfo table
    const char* createTableSQL = R"(
        CREATE TABLE IF NOT EXISTS Userinfo (
            uid INTEGER PRIMARY KEY,
            uname VARCHAR(64),
            age INTEGER
        );
    )";
    
    executeSQL(db, createTableSQL);
    std::cout << "Table created successfully" << std::endl;

    // Insert 10 rows of sample data
    for (int i = 1; i <= 10; ++i) {
        std::string insertSQL = "INSERT INTO Userinfo (uname, age) VALUES ('User" + std::to_string(i) + "', " + std::to_string(20 + i) + ");";
        executeSQL(db, insertSQL.c_str());
    }
    std::cout << "Inserted 10 rows successfully" << std::endl;

    // Query and print all records
    const char* selectSQL = "SELECT * FROM Userinfo;";
    sqlite3_stmt* stmt;
    rc = sqlite3_prepare_v2(db, selectSQL, -1, &stmt, nullptr);
    if (rc != SQLITE_OK) {
        std::cerr << "Failed to fetch data: " << sqlite3_errmsg(db) << std::endl;
        return rc;
    }

    std::cout << "Querying data..." << std::endl;
    while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
        int uid = sqlite3_column_int(stmt, 0);
        const unsigned char* uname = sqlite3_column_text(stmt, 1);
        int age = sqlite3_column_int(stmt, 2);
        std::cout << "UID: " << uid << ", Name: " << uname << ", Age: " << age << std::endl;
    }

    sqlite3_finalize(stmt);
    sqlite3_close(db);
    
    return 0;
}

 

到此,一个sqlite 的 demo工程已开发完成。

编译了sqlite库之后,只需要 sqlite3.h头文件, libsqlite3.a库文件,接口在 demo工程里面 使用sqlite3的 若干api操作数据库。

基本介绍完成。

 

 

 

其他扩展知识:

在 SQLite 的 C++ API 中,`sqlite3_step` 是用于逐条获取查询结果的确实设计如此,SQLite 本身并不直接提供所谓的“批量查询”功能。原因在于它是一个轻量级的数据库引擎,设计目标之一是尽可能保持简单。

不过,虽然没有直接的批量查询接口,但可以通过一些优化手段来提高查询大数据量时的效率。以下是一些建议:

### 1. 使用事务来优化批量查询
当查询大量数据时,可以尝试使用事务来减少 SQLite 的 I/O 操作频率,这通常能显著提高查询速度。虽然在读取时不需要显式开启事务,但是在一些操作系统上(尤其是写操作),事务机制对效率提升有帮助。

### 2. 缓存查询结果
SQLite 提供了内存中的缓存功能,你可以通过设置 `PRAGMA cache_size` 来调整缓存大小。默认的缓存大小可能不足以容纳大量数据,通过增加缓存大小,可以减少硬盘的 I/O 次数,从而提高查询性能。

例如:

```cpp
sqlite3_exec(db, "PRAGMA cache_size = 10000;", nullptr, nullptr, nullptr);
```

这个语句可以将 SQLite 的缓存大小设置为 10000 个页面(每个页面的大小由 `PRAGMA page_size` 决定,通常是 4096 字节)。

### 3. 批量处理结果
虽然 `sqlite3_step` 是逐条获取结果的,但你可以将结果缓存到内存中,再进行批量处理。这是较为常见的做法,比如将 `sqlite3_step` 获取的每一行数据先存到一个 `std::vector` 中,然后再一次性处理。

```cpp
std::vector<std::tuple<int, std::string, int>> results;
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
int uid = sqlite3_column_int(stmt, 0);
const char* uname = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
int age = sqlite3_column_int(stmt, 2);
results.emplace_back(uid, std::string(uname), age);
}

// 批量处理 results
```

通过这种方式,虽然你仍然是逐条读取数据,但数据读取后可以一次性批量处理,避免了逐条处理的开销。

### 4. 索引优化
如果查询的速度仍然不理想,可以考虑为频繁查询的字段创建索引。尤其是当你要查询20万条数据时,索引可以显著减少查询时间。

```sql
CREATE INDEX idx_userinfo_uid ON Userinfo(uid);
```

为 `Userinfo` 表的 `uid` 列创建索引可以加速通过 `uid` 进行的查询。

### 5. 限制每次查询返回的数据量
如果 20 万条数据确实太多,你可以考虑分页查询,也就是分批次获取数据。例如,在每次查询时使用 `LIMIT` 和 `OFFSET` 关键字,这样可以避免一次性处理过多数据:

```sql
SELECT * FROM Userinfo LIMIT 10000 OFFSET 0;
```

每次只查询 10000 条,减少单次查询的内存占用,从而提升性能。

### 6. 并行处理
如果你的应用程序运行在多核处理器上,并且你可以将查询分块处理,那么可以考虑使用多线程或多进程并行查询不同的数据块。虽然 SQLite 本身不支持多线程写入,但可以通过分批查询不同的部分数据来进行并行处理,从而优化整体查询时间。

### 总结
- SQLite 没有原生的批量查询接口,但可以通过批量处理结果、增加缓存、使用索引等方法提升查询性能。
- 如果你需要查询大量数据,适当的分页查询、事务管理、并行处理也可以显著提升查询速度。

针对你查询 20 万条数据的情况,以上优化方法应该会有所帮助。如果有更具体的查询或性能问题,可以进一步讨论如何根据实际情况优化。

 

posted @ 2024-10-13 22:50  He_LiangLiang  阅读(121)  评论(0编辑  收藏  举报