Hallo list,

I'm relatively inexperienced when it comes to databases and SQL (but to
programming). I'm using sqlite's (recent version) C API called from a
C++ application.

I'm confronted with the following situation:

Ca. 2500-3000 objects (called 'entity') everyone with 3 properties (REAL
in sqlite notation) depending on 'positions' (x,y,z). (x,y,z) are
INTEGERS, the grid size might slightly vary between the entities.

The database in a first attempt looks like:

EntityTable

key  val1 val2 ....
1
2
.
.
2500

MatrixTable

key      key_to_entitytable   x  y  z  prop1 prop2 prop2
1                1            0  0  0    .     .     .
.                1            0  0  1    .     .     .
.                1            0  0  2    .     .     .
.                .            .  .  .    .     .     .
25*10^6          .            .  .  .    .     .     .


My problem is the second table. Appending all 25*10^6 rows takes 40
minutes on a PC with 3 GHz, 1GB memory and sufficient large harddisk.

1)
On a technical level, my usage of the sqlite API might be improper. So
I'll attach the relevant code encapsulating the appends :

The sql() functions utilizes more or less sqlite_exec + error handling,
but has no impact here.

table       ... name of the sqlite table
stmtmatrix  ... vector of rows ('BindRecord's' - 25 million for the mentioned 
case)

void Database::append(const QString& table, const vector<BindRecord>& 
stmtmatrix,
                      bool skipprimarykey /*=true*/)
{
  if (stmtmatrix.empty())
    return;

  QString pstr("insert into ");
  pstr += table + " values (";
  if (skipprimarykey)
    pstr += "NULL, ";
  pstr += "?";
  for (unsigned i=1; i!=stmtmatrix[0].values.size(); ++i)
  {
    pstr  += ",?";
  }
  pstr += ")";

  int c = 0;
  sql("begin");
  sqlite3_stmt *stmt;
  if (sqlite3_prepare(
         db_, 
         pstr.ascii(),  // stmt
        -1,
        &stmt,
         0
       )!= SQLITE_OK) 
  {
    printf("\nCould not prepare statement.");
    return;
  }
  for (unsigned i=0; i!=stmtmatrix.size(); ++i) // iterating rows
  { 
    for (unsigned j = 0; j!=stmtmatrix[i].values.size(); ++j)
    {
      int ERR = sqlite3_bind_text (
          stmt,
          j+1,  // Index of wildcard
          stmtmatrix[i].values[j].ascii(),
          stmtmatrix[i].values[j].length(),  // length of text
          SQLITE_STATIC
          );
          
        if (ERR != SQLITE_OK) 
        {
          printf("\nCould not prepare statement.");
        } 
    }
    sqlite3_step(stmt);     
    sqlite3_reset(stmt);
    ++c;
    if (c==100000)
    {
      sql("commit");
      sql("begin");
      c=0;
    }
  }
  sql("commit");  
  sqlite3_finalize(stmt);
}

Calling Database::.sql("PRAGMA synchronous = OFF")
before Database::append improves speed, but not beyond the 40 minutes
cited. Can someone elaborate on the code regarding performance ?

2)
Database design. Is this big table a good choice or has anyone
recommendations for better design. For example, splitting the big table
into smaller ones (assigned to a single entity) with ~100000 rows and
later on building database requests utilizing joints ? Or something
completely different ?

Thank you,
Micha
-- 

Reply via email to