Или я должен использовать другой молоток, чтобы решить эту проблему.
У меня есть очень простой вариант использования для хранения данных, фактически разреженная матрица, которую я пытался сохранить в базе данных SQLite. Я создал таблицу:
create TABLE data ( id1 INTEGER KEY, timet INTEGER KEY, value REAL )
, в которые я вставляю много данных (800 элементов каждые 10 минут, 45 раз в день), большинство дней в году. Кортеж (id1, timet) всегда будет уникальным.
Значение времени составляет секунды с начала эпохи и всегда будет увеличиваться. Для всех практических целей id1 является случайным целым числом. Хотя, вероятно, только 20000 уникальных идентификаторов.
Затем я хотел бы получить доступ ко всем значениям, где id1 == someid, или получить доступ ко всем элементам, где timet == когда-нибудь. В моих тестах с использованием последней версии SQLite через интерфейс C в Linux поиск одного из них (или любого варианта этого поиска) занимает приблизительно 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" );
}