2013-03-09 21 views
15

Sto cercando di migliorare la velocità dei miei inserimenti nel database di Android. Quello che sto facendo attualmente è di generare una stringa del tipo:Qual è il limite delle variabili SQL che è possibile specificare in una singola query execSQL

SELECT ? as title, ? as musician_id, ? as album_id, ? as genre 
UNION SELECT ?, ?, ?, ? 
UNION SELECT ?, ?, ?, ? 
UNION SELECT ?, ?, ?, ? 
UNION SELECT ?, ?, ?, ? 
UNION SELECT ?, ?, ?, ? 

E poi eseguirla con

SQLiteDatabase database = //initialized in some way 
String insertQuery; // the string of the query above 
String [] parameters; // the parameters to use in the insertion. 
database.execSQL(insertQuery.toString(), parameters); 

sto ottenendo il seguente errore quando provo ad inserire circa 2000 righe:

Caused by: android.database.sqlite.SQLiteException: too many SQL variables (code 1): , while compiling: INSERT INTO songs (title, musician_id, album_id, genre) 
SELECT ? as title, ? as musician_id, ? as album_id, ? as genre 
UNION SELECT ?, ?, ?, ? 
UNION SELECT ?, ?, ?, ? 

Quando provo a inserire circa 200 righe, tutto funziona correttamente.

Suppongo che sia ovvio: sto tentando di inserire troppe variabili in un singolo execSQL. Qualcuno sa qual è il limite in modo da poter dividere le righe che inserisco nei lotti appropriati?

+0

si dovrebbe avere uno sguardo alla documentazione qui: http://www.sqlite.org/limits.html – ebarrenechea

+0

@ebarrenchea Sono quasi certo il limite non è imposto da SQLite piuttosto dall'API SQLite Android. Hai trovato qualche indicazione del contrario? –

+1

Si potrebbe avvicinarsi a questo con una ricerca binaria: 2000 non funziona, quindi prova 1000, poi 500 (o 1500) ... – Sam

risposta

19

Il limite è hardcoded in sqlite3.c ed è impostato a 999. Purtroppo può essere cambiato, ma solo in fase di compilazione. Ecco i frammenti rilevanti:

/* 
** The maximum value of a ?nnn wildcard that the parser will accept. 
*/ 
#ifndef SQLITE_MAX_VARIABLE_NUMBER 
# define SQLITE_MAX_VARIABLE_NUMBER 999 
#endif 


/* 
** The datatype ynVar is a signed integer, either 16-bit or 32-bit. 
** Usually it is 16-bits. But if SQLITE_MAX_VARIABLE_NUMBER is greater 
** than 32767 we have to make it 32-bit. 16-bit is preferred because 
** it uses less memory in the Expr object, which is a big memory user 
** in systems with lots of prepared statements. And few applications 
** need more than about 10 or 20 variables. But some extreme users want 
** to have prepared statements with over 32767 variables, and for them 
** the option is available (at compile-time). 
*/ 
#if SQLITE_MAX_VARIABLE_NUMBER<=32767 
typedef i16 ynVar; 
#else 
typedef int ynVar; 
#endif 
+1

Cambiando solo al momento della compilazione, allora è il momento della compilazione del sistema operativo Android? Quindi non c'è modo di cambiare questo per un'app Android che sta ricevendo questo errore? In caso contrario, dovrò controllare la dimensione dei miei parametri della clausola IN e assicurarmi che non superino mai questo limite di 999, separandoli in query separate da unire. –

9

sto cercando di migliorare la velocità della mia banca dati Android inserti. Cosa Attualmente sto facendo è generare una stringa del tipo:

ne pensi uso TRANSACTION? Ti suggerisco di usarlo al posto del tuo approccio. Penso che usare la clausola UNION non sia affatto una "vittoria" e che ci sia un modo migliore e soprattutto più sicuro per raggiungerlo.

db.beginTransaction(); 
try { 
    for (int i = 0 ; i < length ; i++) { // or another kind of loop etc. 
    // make insert actions 
    } 
    db.setTransactionSuccessful(); // now commit changes 
} 
finally { 
    db.endTransaction(); 
} 
+0

Pensi che la transazione acceleri i miei inserti? –

+0

@BorisStrandjev se non lo faccio, non darei una risposta. Se vuoi essere più "sicuro" a riguardo, puoi fare dei test quando per esempio eseguirai 5 000 - 50 000 inserti con e senza l'uso della transazione e misurerai un tempo. – Sajmon

+0

Lo sto facendo esattamente ora –

Problemi correlati