2013-03-09 13 views
15

Próbuję poprawić szybkość wkładów do mojej bazy danych Androida. Co jestem obecnie robi to generuje ciąg jak:Jaki jest limit zmiennych SQL, które można określić w pojedynczym zapytaniu execSQL

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

I to wykonanie go z

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); 

otrzymuję następujący błąd, gdy próbuję wstawić około 2000 wierszy:

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 ?, ?, ?, ? 

Gdy próbuję wstawić około 200 wierszy, wszystko działa poprawnie.

Przypuszczam, że to jest oczywiste - Próbuję przekazać zbyt wiele zmiennych w jednym execSQL. Czy ktokolwiek wie, jaki jest limit, abym mógł podzielić wiersze, które wstawiam w odpowiednich partiach?

+0

Trzeba zapoznać się z dokumentacją tutaj: http://www.sqlite.org/limits.html – ebarrenechea

+0

@ebarrenchea Jestem prawie pewien, że granica nie jest narzucona przez SQLite raczej z Android SQLite API. Czy znalazłeś jakieś wskazanie czegoś przeciwnego? –

+1

Możesz podejść do tego przy pomocy wyszukiwania binarnego: 2000 nie działa, więc spróbuj 1000, potem 500 (lub 1500) ... – Sam

Odpowiedz

19

Limit jest ustalony w sqlite3.c i jest ustawiony na 999. Niestety można go zmienić, ale tylko w czasie kompilacji. Oto istotne fragmenty:

/* 
** 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

Zmieniając się tylko w czasie kompilacji, czy jest to czas kompilacji systemu operacyjnego Android? Więc nie można tego zmienić w przypadku aplikacji na Androida, która otrzymuje ten błąd? Jeśli nie, będę musiał sprawdzić rozmiar moich parametrów w klauzuli IN i upewnić się, że nigdy nie przekroczą tego 999 limitu, oddzielając je na osobne zapytania do przyłączenia. –

9

Próbuję zwiększyć szybkość mojej bazy danych Android. Co Jestem obecnie robi to generuje ciąg jak:

myślałeś o użyciu TRANSACTION? Proponuję użyć go zamiast swojego podejścia. Myślę, że użycie klauzuli nie jest "wygraną" w ogóle i istnieje lepszy i przede wszystkim bezpieczniejszy sposób jej osiągnięcia.

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

Czy myślisz, że transakcja przyspieszy moje wkładki? –

+0

@BorisStrandjev jeśli nie, nie chciałbym odpowiedzieć. Jeśli chcesz być bardziej "pewny" tego, możesz zrobić kilka testów, gdy na przykład wykonasz 5 000 - 50 000 wkładek zi bez użycia transakcji oraz zmierzysz czas. – Sajmon

+0

Robię dokładnie to teraz –

Powiązane problemy