Last 5 comments
31 years ago
Rafael:  Thank you very much, I was having a huge headache to solve the very same problem!
37 years ago
Ray:  Having the same problem. Very frustrating. Luckily, for some reason my released version worked on the iPad itself, but now I can't get it to run in the simulator. Getting no such table, which I'm guessing is an initialization error. Will continue to investigate.
38 years ago
Jeremy:  FYI, I've just tried it with the SQLite 3.7.0 preview and the same problem occurs.
Also, I'm not using any extra third-party libraries with my SQLite, so the problem isn't your Unicode extension.
38 years ago
Jeremy:  I'm having the same problem with compiling SQLite against iOS 4 for the iPad simulator, but in my case it works fine running on an actual iPad (also works in the iPhone simulator and on an iPod Touch).
Same problem with 3.6.23.1, 3.6.23, and at least back to 3.6.21. Compiling against iOS 3.2 makes it work, though that's not really an option for iPhone (as opposed to iPad) apps.
I have no idea what to do about it or how big a problem it really is...
38 years ago
Pascal:  The problem seems to have deep roots, however there is a solution, see the updated post. :)
The archive
March 2011  (1)
July 2010  (1)
July 2009  (1)
March 2009  (1)
July 2008  (3)
June 2008  (1)
May 2008  (3)
March 2008  (1)
July 2007  (1)
June 2007  (3)
May 2007  (1)
April 2007  (1)
July 2006  (2)
June 2006  (6)

SQLite Bulk Insert on the iPhone

Tuesday, July 15th 2008 - 20:30 • 1 update Monday, October 19th 2009 - 17:51
I'm currently working on an application for the iPhone/iPod touch and decided to use SQLite as storage for the data. The app will display medical eponyms and must fill the database on first launch and when new eponym data is available from an XML file. It parses the XML file and fills the SQLite database, which currently results in 27 entries to a categories table, 1'623 entries to the eponyms table and 3'281 entries to a linker table (4'931 entries in total). The whole database weighs only 394 KB.

Problem

My first approach was to create the empty database file, create the tables and insert all the data with a simple INSERT statement on every row. This way the database file had to grow some bytes after every insert, which turned out not to be too effective. In the iPhone Simulator on my Mac it took about 22 seconds to parse the XML and insert the 4'931 entries into the three tables, on my iPod touch it took way longer than a minute.

Solution

So I started looking for alternatives. Providing the complete .sqlite - file was not really an option since I wanted to allow updating only the eponyms without having to update the whole app and downloading the XML is more transparent.
The solution is to first use an in-memory database and then bulk-copy all its data to a file-database using INSERT INTO table SELECT * FROM other_table. This results in much faster database creation than the old fashioned way: In the Simulator on my Mac it now takes 300 milliseconds to parse + insert the entries into the RAM-database and another 90 milliseconds to bulk-copy using the before-mentioned statement, on the iPod touch the parsing + insert takes less than 11 seconds and the bulk insert takes about 500 milliseconds.

DeviceDirect InsertRAM Database + Bulk Insert
iPhone Simulator22 sec300 ms + 90 ms
iPod touch 1st Gen>> 1 min11 sec + 500 ms


How-To

With SQLite, you can open a database in the RAM when using :memory: as the database path. I create the file database like before by touching an empty file, opening it as a SQLite database and creating the tables:
sqlite3 *database; NSString *sqlPath = @"path/to/database.sqlite"; [[NSFileManager defaultManager] createFileAtPath:sqlPath contents:nil attributes:nil]; sqlite3_open([sqlPath UTF8String], &database);
// create tables using: sqlite3_exec(database, "CREATE TABLE ...", NULL, NULL, &err)

(Note that sqlite3_open_v2([sqlPath UTF8String], &database, SQLITE_OPEN_CREATE, NULL) seems not to be available on the iPhone OS.)
After that I create a database in RAM with exactly the same tables:
sqlite3 *memory_database; if(SQLITE_OK == sqlite3_open(":memory:", &memory_database)) { // create the same tables as above }

I now use the memory_database handle to execute the same INSERT statements like before on the file database which is much much faster, and after that copy all data from memory_database to the file database which seems to not take place incrementally but in a quick swoop (90 ms vs 22 sec). This is done by attaching the file database to the memory database with ATTACH DATABASE "path/to/database.sqlite" AS database_alias first and then using the INSERT INTO ... SELECT FROM statement:
char *err; NSString *attach_qry = [NSString stringWithFormat:@"ATTACH DATABASE \"%@\" AS database_alias", sqlPath]; sqlite3_exec(memory_database, [attach_qry UTF8String], NULL, NULL, &err); if(err) { // error handling }
// do the following on all tables sqlite3_exec(memory_database, "INSERT INTO database_alias.tablename SELECT * FROM main.tablename", NULL, NULL, &err); if(err) { // error handling }
sqlite3_close(memory_database);

The Application named Eponyms will be available on the iTunes Store once it's ready, and since it will be an Open Source App you can find the source at the Google Code Project Website: eponyms-touch.googlecode.com/

Edit: I should have added this a long time ago - if you BEGIN TRANSACTION before all the insert statements and call COMMIT after you've finished, the process of writing directly to your database file will be about as fast as if using the memory approach. I switched to using the transaction view.
Craig Morris at 09.08.2008 19:42

YOU ARE THE MAN!!! I was running into the exact same problem. I am syncing data from a web service and trying to load into a sqlite DB on the iPhone. I implemented this on my three biggest size offenders and it went from a 3 minute load to 30 seconds. I googled forever to find a sqlite bulk insert hoping it was supported through some kind of API directly. Just wanted to give you a huge thanks.
karl at 11.12.2008 16:33

Here's a way to bulk insert into sqlite3 from a shell script:
http://codesnippets.joyent.com/posts/show/1808

Comments are disabled