环境介绍:
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 万条数据的情况,以上优化方法应该会有所帮助。如果有更具体的查询或性能问题,可以进一步讨论如何根据实际情况优化。
标签:sqlite,缓存,demo,查询,源码,sqlite3,### From: https://www.cnblogs.com/music-liang/p/18463167