或者我应该使用不同的锤子来解决这个问题。
我有一个非常简单的数据存储用例,实际上是一个稀疏矩阵,我试图将其存储在 SQLite 数据库中。我创建了一个表:
create TABLE data ( id1 INTEGER KEY, timet INTEGER KEY, value REAL )
我向其中插入大量数据(每 10 分钟 800 个元素,每天 45 次),一年中的大部分时间。 (id1,timet) 的元组将始终是唯一的。
时间值是自纪元以来的秒数,并且会一直增加。出于所有实际目的,id1 是一个随机整数。虽然可能只有 20000 个唯一 ID。
然后我想访问 id1==someid 的所有值或访问 timet==sometime 的所有元素。在我通过 Linux 上的 C 接口(interface)使用最新 SQLite 的测试中,查找其中一个(或此查找的任何变体)大约需要 30 秒,这对于我的用例来说不够快。
我尝试为数据库定义一个索引,但这使插入速度减慢到完全不可行的速度(虽然我可能做错了......)
上表导致对任何数据的访问都非常缓慢。我的问题是:
- SQLite 完全是错误的工具吗?
- 我可以定义索引来显着加快处理速度吗?
- 我应该为此使用 HDF5 之类的东西而不是 SQL 吗?
请原谅我对 SQL 的非常基础的理解!
谢谢
我提供了一个代码示例,展示了使用索引时插入速度如何变慢。使用“create index”语句,代码需要 19 分钟才能完成。没有它,它会在 18 秒内运行。
#include <iostream>
#include <sqlite3.h>
void checkdbres( int res, int expected, const std::string msg )
{
if (res != expected) { std::cerr << msg << std::endl; exit(1); }
}
int main(int argc, char **argv)
{
const size_t nRecords = 800*45*30;
sqlite3 *dbhandle = NULL;
sqlite3_stmt *pStmt = NULL;
char statement[512];
checkdbres( sqlite3_open("/tmp/junk.db", &dbhandle ), SQLITE_OK, "Failed to open db");
checkdbres( sqlite3_prepare_v2( dbhandle, "create table if not exists data ( issueid INTEGER KEY, time INTEGER KEY, value REAL);", -1, & pStmt, NULL ), SQLITE_OK, "Failed to build create statement");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute insert statement" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize insert");
checkdbres( sqlite3_prepare_v2( dbhandle, "create index issueidindex on data (issueid );", -1, & pStmt, NULL ), SQLITE_OK, "Failed to build create statement");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute insert statement" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize insert");
checkdbres( sqlite3_prepare_v2( dbhandle, "create index timeindex on data (time);", -1, & pStmt, NULL ), SQLITE_OK, "Failed to build create statement");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute insert statement" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize insert");
for ( size_t idx=0; idx < nRecords; ++idx)
{
if (idx%800==0)
{
checkdbres( sqlite3_prepare_v2( dbhandle, "BEGIN TRANSACTION", -1, & pStmt, NULL ), SQLITE_OK, "Failed to begin transaction");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute begin transaction" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize begin transaction");
std::cout << "idx " << idx << " of " << nRecords << std::endl;
}
const size_t time = idx/800;
const size_t issueid = idx % 800;
const float value = static_cast<float>(rand()) / RAND_MAX;
sprintf( statement, "insert into data values (%d,%d,%f);", issueid, (int)time, value );
checkdbres( sqlite3_prepare_v2( dbhandle, statement, -1, &pStmt, NULL ), SQLITE_OK, "Failed to build statement");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute insert statement" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize insert");
if (idx%800==799)
{
checkdbres( sqlite3_prepare_v2( dbhandle, "END TRANSACTION", -1, & pStmt, NULL ), SQLITE_OK, "Failed to end transaction");
checkdbres( sqlite3_step( pStmt ), SQLITE_DONE, "Failed to execute end transaction" );
checkdbres( sqlite3_finalize( pStmt ), SQLITE_OK, "Failed to finalize end transaction");
}
}
checkdbres( sqlite3_close( dbhandle ), SQLITE_OK, "Failed to close db" );
}
最佳答案
您是一次插入所有 800 个元素吗?如果是,在事务中执行插入将显着加快该过程。
参见 http://www.sqlite.org/faq.html#q19
SQLite 可以处理非常大的数据库。参见 http://www.sqlite.org/limits.html
关于sql - SQLite 可以处理 9000 万条记录吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3160987/