Peut SQLite poignée de 90 millions de disques?

Ou devrais-je utiliser un autre marteau pour résoudre ce problème.

J'ai une très simple d'utilisation pour le stockage des données, de manière efficace d'une matrice creuse, que j'ai tenté de stocker dans une base de données SQLite. J'ai créé un tableau:

create TABLE data ( id1 INTEGER KEY, timet INTEGER KEY, value REAL )

dans lequel j'ai insérer un grand nombre de données, (800 éléments, toutes les 10 minutes, 45 fois par jour), la plupart des jours de l'année. Le n-uplet de (id1,préventive) sera toujours unique.

L'préventive valeur est en secondes depuis l'epoch, et sera toujours en augmentation. Le id1 est, à toutes fins pratiques, un entier aléatoire. Il n'y a probablement que 20000 id unique bien.

Je ne puis accéder à toutes les valeurs où id1==someid ou accès à tous les éléments où préventive==de temps en temps. Sur mes tests à l'aide de la dernière SQLite via l'interface C sur Linux, recherche pour l'un de ces (ou toute variante de cette recherche) prend environ 30 secondes, ce qui n'est pas assez rapide pour mon cas d'utilisation.

J'ai essayé de définir un index de la base de données, mais cela a ralenti le curseur d'insertion complètement impraticable vitesses (j'ai peut-être fait de cette manière incorrecte si...)

Le tableau ci-dessus conduit à de très lent d'accès pour toutes les données. Ma question est:

  • Est SQLite complètement le mauvais outil pour cela?
  • Puis-je définir des indices pour accélérer les choses de manière significative?
  • Dois-je utiliser quelque chose comme HDF5 au lieu de SQL pour cela?

Veuillez excuser mon très compréhension de base de SQL!

Grâce

- Je inclure un exemple de code qui montre comment l'insertion de la vitesse ralentit énormément lors de l'utilisation d'indices. Avec la 'création d'un" indice de déclarations en place, le code prend en 19 minutes. Sans cela, il s'exécute en 18 secondes.


#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" ); 
}

  • Combien d'historique de données avez-vous besoin d'accéder à un moment donné? Vous pourriez archive des données plus anciennes dans une autre table de la persistance et de gagner du temps sur l'interrogation de "pertinent" de données.
  • I <idéalement> besoin d'accéder à toutes les données historiques. Si besoin, je peux diviser ce dans un dataset par année, mais j'espère SQLite pourrait m'épargner d'avoir à gérer de tels détails.
  • Pourriez-vous s'il vous plaît poster le code complet où vous utiliser sqlite3* fonctions (en omettant les autres pièces)? Si le processus de "rampa jusqu'à l'arrêt complet", quelque chose est certainement pas droit.
  • Avez-vous besoin de la même granularité des données historiques? Si non, RRDB peut être intéressant.
  • Pourquoi avez-vous besoin pour la recherche de id1==someid? Est-ce ainsi que vous pouvez SÉLECTIONNER "random" de données à un moment plus tard? À partir de votre scénario, il semble que vous n'avez pas besoin someid être unique, record #3 à 2010-01-01, et record #79832759385 à 2010-06-06, pourraient avoir le même id1 champ. De même, vous avez des collisions sur HHMMSS pour plusieurs enregistrements insérés par seconde. Ainsi, dans le cas 1, vous sélectionnez id==someId et obtenir zéro, un, ou plusieurs éparses dossiers; et dans le cas 2, vous obtenez zéro, un, ou plusieurs adjacentes enregistrements. Si ce sont vos besoins, vous pouvez bénéficier de différents runtime méthodes de requête.
  • Je pense que vous comprenez mes besoins correctement. Essentiellement, je suis le stockage d'une matrice creuse où la ligne d'axe est indexé par id1 et la colonne indexée par le temps. Pour mes requêtes, je veux sélectionner toute une ligne ou une colonne. Toutes les suggestions de requête méthodes adaptées à cette situation?