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